目录
【2】USART
【3】串口通信协议
【4】相关寄存器
串口控制寄存器
波特率寄存器
中断和状态寄存器
编辑
数据发送寄存器
数据接收寄存器
【5】 USART功能框图
【6】串口发送实验
实验要求
1.观察实物
2.分析原理图
3.STM32CubeMX配置
7、不定长接收
8、重定向
【1】通信的基础知识
- 通信:至少有收发两方
- 通信方式的划分
同步通信:通信双方根据同步信号通信,比如双方有一个共同的时钟信号(SPI同步通信)
异步通信:通信双方有自己的独立系统时钟,大家约定好通信的速度。异步通信不需要同步信号,但并不是说通信的过程不同步了。(UART)
串行通信:指的是同一时刻只能发送一个bit位,因此只需要一根线也可以
优点:占用引脚资源少
缺点:速率慢
并行通信:指的是同一时刻可以发送或者接收多个bit位,所以需要多根数据线
优点:速率快
缺点:占用引脚资源多
单工:要么收,要么发,只能做接受设备或者发送设备。比如:收音机
半双工:可以收,可以发,但是同一时刻只能收或发。比如:对讲机
全双工:可以在同一时刻即接收又发送。比如:手机
【2】USART
Universal Synchonous Asynchronous receiver transmitter 通用同步异步接收发射机
中文参考手册 564页
USART: 支持同步\异步通信、全双工、串行
UART :没有信号线,只支持异步通信、全双工、串行
【3】串口通信协议
数据帧格式:
空闲状态:信号线保持高电平
起始位:1位 低电平表示数据包的起始
数据位:8位or9位
校验位(可选):奇偶校验
奇校验:
数据位上的1的个数 + 校验位上1的个数 = 奇数
偶校验:
数据位上的1的个数 + 校验位上1的个数 = 偶数
停止位:1位 将电平信号拉高,代表一个数据包发送结束,回到空闲状态。
【4】相关寄存器
串口控制寄存器
(设备功能初始化、通信帧格式配置)
USART_CR1 USART_CR2 USART_CR3
波特率寄存器
USART_BRR
中断和状态寄存器
USART_ISR
数据发送寄存器
USART_TDR
数据接收寄存器
USART_RDR
【5】 USART功能框图
Tx:数据发送端
Rx:数据接收端
流控概念
在两个设备正常通信时,由于处理速度不同,就存在这样一个问题,有的快,有的慢,在某些情况下,就可能导致丢失数据的情况。如台式机与单片机之间的通讯,接收端数据缓冲区已满,则此时继续发送来的数据就会丢失。流控制能解决这个问题
nRTS:请求以发送(Request To Send),n表示低电平有效。当本设备准备好接收新数据时就会将nRTS变成低电平;当接收寄存器已满时,nRTS将被设置为高电平。
nCTS:清除以发送(Clear To Send) 为输入信号,低电平有效。用于判断是否可以向对方发送数据,低电平说明本设备可以向对方发送数据。
该引脚只适用于硬件流控制
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。
发送过程:由CPU和DMA向数据发送寄存器(TDR)中写入要发送的数据,由发送移位寄存器将数据按位移到发送端口输出。
接收过程:由CPU和DMA读取接收数据寄存器(RDR)中的数据。
【6】串口发送实验
实验要求
通过单片机向电脑(串口助手)发送数据
1.观察实物
找到通信接口 丝印“P4”
2.分析原理图
CH340 : 电平转换芯片,可以转换TTL电平-USB电平。
数据选择器/多路复用器
3.STM32CubeMX配置
- 寄存器方式编写发送接受一个字节的函数
//写一个单字节发送的函数
void put(uint8_t ch)
{
while(!(USART1->ISR & 1<<7)){}
//判断发送数据寄存器是不是空了
USART1->TDR=ch;
//将数据写入到TDR寄存器中
}
int get()
{
uint8_t ch;
while(!(USART1->ISR & 1<<5)){}
//判断接受数据寄存器是不是空了
ch=USART1->RDR;
//将数据从RDR寄存器中读出来
return ch;
}
- 寄存器方式编写发送接受一个字节的函数
HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size,
uint32_t Timeout)
功能:串口发送数据
参数:huart :串口选择(USART1) pData:需要发送的数据
Size:发送多少个数据 Timeout:超时时间
返回值:成功返回HAL_OK 失败返回HAL_TIMEOUT
HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size,
uint32_t Timeout)
功能:串口接收数据函数
参数:huart :串口选择(USART1) pData :接收数据的地址
Size:发送多少个数据 Timeout:超时时间
返回值:成功 :返回HAL_OK 失败 :返回HAL_TIMEOUT
HAL_UART_Receive(&huart1,buf,2,100);
HAL_UART_Transmit(&huart1,buf,strlen(buf),100);
memset(buf,0,sizeof(buf));
7、不定长接收
声明
uint8_t buf[128]={"0 "};//数据缓存区
uint8_t byte;//单个字节缓存区
uint8_t len=0;//接收到的数据长度
写在while内
if(HAL_UART_Receive(&huart1,&byte,1,100)==HAL_OK)
//判断接收一个字节是否成功
{
if(byte=='\n')//判断是否结束
{//如果结束处理数据
HAL_UART_Transmit(&huart1,buf,len,100);//原封不动回回去
memset(buf,0,len);//清空缓存区
len=0; //长度清0
}
else//如果没有接收完成
{
buf[len++]=byte;//继续接收,把接收到的数据存储到buf
}
}
8、重定向
//printf的重定向
int fputc(int ch,FILE *f)
{
while(!(USART1->ISR & 1<<7)){}
//判断发送数据寄存器是不是空了
USART1->TDR=ch;
//将数据写入到TDR寄存器中
}
//scanf的重定向
int fgetc(FILE *f)
{
uint8_t ch;
while(!(USART1->ISR & 1<<5)){}
//判断接受数据寄存器是不是空了
ch=USART1->RDR;
//将数据从RDR寄存器中读出来
return ch;
}
scanf("%s",buf);
printf("%s",buf);
HAL_Delay(500);
- 编写呼吸灯
- 串口发送ON开LED,发送OFF关LED或者(0X550X440XFF表示开灯,0X550X660XFF表示关灯)注:包头 0X55 包尾:0XFF 数据:0X44表示开灯 0X66表示关灯
1.呼吸灯
//自定义延时函数
void Delay(int i)
{
while(i--);
}
int main()
{
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
for(int i=0;i<3000;i++)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
Delay(i);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
Delay(3000-i);
}
for(int i=3000;i>0;i--)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
Delay(i);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
Delay(3000-i);
}
}
}
//2.开关灯控制
#include <stdio.h>
#include <string.h>
uint8_t buf[32]={"0"};//数据缓存区
uint8_t byte;//单个字节缓存区
uint8_t len=0;//接收到的数据长度
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(HAL_UART_Receive(&huart1,&byte,1,100)==HAL_OK)
{
if(byte=='N')
{
HAL_UART_Transmit(&huart1,buf,len,100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2,GPIO_PIN_RESET);
memset(buf,0,len);
len=0;
}
if(byte=='F')
{
HAL_UART_Transmit(&huart1,buf,len,100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2,GPIO_PIN_SET);
memset(buf,0,len);
len=0;
}
}
}