串口通信之————USART

B站账号:小光学嵌入式


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

USART

一.原理讲解

请跳转->串口通信————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
根据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.9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  GPIO_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;//PA10
  GPIO_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 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_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); //初始化串口1
  USART_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;												//数组下标置0
					

				if(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通信。都会用代码实现并且实验它。
继续加油!!!

上一篇:FFmpeg源代码:avcodec_receive_frame


下一篇:stm32 USART