当前位置: 代码迷 >> 综合 >> 串口通信之————USART
  详细解决方案

串口通信之————USART

热度:45   发布时间:2023-11-24 14:53:33.0

B站账号:小光学嵌入式


  • ? 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大二学生。
  • ?最近开始系统性补习STM32基础知识,规划有:串口通信,Github,Ucos等等。
  • ?今天总结一下串口通信之stm32-USART。

USART

  • 一.原理讲解
  • 二.USART和UART的区别
  • 三.具体固件库实现
    • 1.USART初始化
    • 2.串口收发数据
      • 1.主机发送
      • 2.从机接收数据
  • 总结

一.原理讲解

请跳转->串口通信————UART、I2C、SPI详解(总结篇

二.USART和UART的区别

UART:universal asynchronous receiver and transmitter通用异步收/发器

USART:universal synchronous asynchronous receiver and transmitter通用同步/异步收/发器
大家能看出来USART和UART相比较,可以实现同步,就是说USART相对UART的区别之一就是能提供主动时钟

三.具体固件库实现

1.USART初始化

在这里插入图片描述
根据USART的外设配置,我们可以得知,全双工模式,发送端设置为复用推挽输出,接收端设置为浮空输入或上拉输入。
初始化步骤:

  1. 使能USART使用引脚时钟
    使能串口使用所在引脚
  2. GPIO初始化
    初始化串口所在IO
  3. 接收中断初始化
    设置中断优先级和通道
  4. 初始化USART
    初始化USART,波特率、数据格式、奇偶校验位、收发模式等等。
  5. 开启中断
    USART_ITConfig();//开启串口接受中断
  6. 使能串口
    USART_Cmd();
void uart_init(u32 bound){
    //GPIO端口设置GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟//USART1_TX GPIOA.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9//USART1_RX GPIOA.10初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10 //Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器//USART 初始化设置USART_InitStructure.USART_BaudRate = bound;//串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式USART_Init(USART1, &USART_InitStructure); //初始化串口1USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断USART_Cmd(USART1, ENABLE);                    //使能串口1 }

2.串口收发数据

串口发送一般不会用到中断发送,接收会用到中断接收,因为串口通信在没有用到主动时钟的时候,他是异步通信的。
我们先认识一下固件库中的这几个函数:

void USART_SendData();//发送数据到串口,DR
uint_16_t USART_ReceiveData();//接收数据,从DR读取接收到的数据FlagStatus USART_GetFlagStatus();//获取状态标志位
void USART_ClearFlag();//清除状态标志位
ITStatus USART_GetITStatus();//获取中断状态标志位
void USART_ClearITPendingBit();//清除中断状态标志位

我们通过上面这些函数就可以完成一次成功的数据发送与接收。
下面是一个例子,完成了两个STM32之间的传输数据:

1.主机发送

发送时我们封装一个函数:
步骤:

  1. USART_ClearFlag()清除标志位
  2. USART_SendData()每次发送一个字符
  3. USART_GetFlagStatus()等待发送完成
  4. USART_ClearFlag()清楚标志位,然后继续发送知道截至标志
//串口发送字符串
void USART_SendString(USART_TypeDef* USARTx, char *DataString)
{
    int i = 0;USART_ClearFlag(USARTx,USART_FLAG_TC);										//发送字符前清空标志位(否则缺失字符串的第一个字符)while(DataString[i] != '\0')												//字符串结束符{
    USART_SendData(USARTx,DataString[i]);									//每次发送字符串的一个字符while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == 0);					//等待数据发送成功USART_ClearFlag(USARTx,USART_FLAG_TC);									//发送字符后清空标志位i++;}
}

2.从机接收数据

在接收的时候,我们使用中断接收,所以我们就要编写中断服务函数:void USARTx_IRQHandler(void)这个名字一定不能变。
接收数据步骤:

  1. USART_GetITStatus()判断是否有数据
  2. USART_ReceiveData()读取寄存器中的数据,存放到我们定义的USART_ReceiveString
  3. if(USART_ReceiveString[Receive_sum-2] == '\r' && USART_ReceiveString[Receive_sum-1] == '\n' )回车换行作为结束标志位,当接收完成后根据接收到的数据USART_ReceiveString直接执行相应的操作。
char USART_ReceiveString[20];													//接收PC端发送过来的字符
int Receive_Flag = 0;															//接收消息标志位
int Receive_sum = 0;															//数组下标
void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(USART1,USART_IT_RXNE) == 1)							//USART_FLAG_RXNE判断数据,== 1则有数据{
    if(Receive_sum > 49)													//数组能存放50个字节的数据 {
    USART_ReceiveString[49] = '\0';										//数据字节超过50位时,将最后一位设置为\0 Receive_Flag = 1;													//接收标志位置1,停止接收数据Receive_sum = 0;													//数组下标置0}if(Receive_Flag == 0)													//接收标志位等于0,开始接收数据{
    USART_ReceiveString[Receive_sum] = USART_ReceiveData(USART1);		//通过USART1串口接收字符Receive_sum++;														//数组下标++}if(Receive_sum >= 2)													//数组下标大于2{
    if(USART_ReceiveString[Receive_sum-2] == '\r' && USART_ReceiveString[Receive_sum-1] == '\n' ){
    USART_ReceiveString[Receive_sum-1] = '\0';						USART_ReceiveString[Receive_sum-2] = '\0';Receive_Flag = 1;												//接收标志位置1,停止接收数据Receive_sum = 0;												//数组下标置0if(strcmp(USART_ReceiveString,"hello") == 0){
    LED0 = !LED0;}if(strcmp(USART_ReceiveString,"world") == 0){
    LED1 = !LED1;}}		}USART_ClearITPendingBit(USART1,USART_IT_RXNE);							//接收后先清空标志位}
}

我们可以通过调整Receive_Flag的值来让它开始或者停止接收。
我用这个做了实验,完成了简单的两个板子之间的通信。

总结

今天复习了串口通信中的USART,把之前串口接收中断没有搞懂的搞懂了,之后还有SPI和I2C通信。都会用代码实现并且实验它。
继续加油!!!