单片机串口使用一般就是设置串口工作状态和打开相关串口中断后在串口接收中断中将接收到的字节数据一个一个保存到一个全局数组变量中,供其它函数使用。有些时候串口接收字符串数据并没有统一的长度和格式。那么,我们怎么判断接收完串口数据呢?我们将一次性发送过来的数据称之为一帧数据。在STM8和STM32状态寄存器有两个比较常用和重要的位,分别是RXNE和IDLE,如图:
stm8串口状态寄存器
stm32串口状态寄存器 其中RXNE表示读数据寄存器非空 (Read data register not empty),即接收到1个字节数据后置1,它是可读可写的数据位,可以通过写入0来清除或对USART_DR读操作将该位清0; IDLE表示监测到总线空闲 (IDLE line detected),当检测到总线空闲时,该位被硬件置位。如果USART_CR1中的IDLEIE为’1’,则产生中断。由软件序列清除该位(先读USART_SR,然后读USART_DR)。注意: IDLE位不会再次被置高直到RXNE位被置起(即又检测到一次空闲总线),也就是说每次传完一帧数据后才会置1.
以STM32为例,配置串口时打开两者中断。注意不能这样使能中断: USART_ITConfig(USART2, USART_IT_RXNE | USART_IT_IDLE, ENABLE);//这是错误的,今天被这个使能中断搞得老惨了,不信你自己试试...... 而应该按照下面的方式使能:
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
中断函数分别判断两个中断标志位是否置1:
void USART1_IRQHandler(void) { uint8_t clear; //用于读取数据,清除IDLE中断标志 static uint8_t i; //如果是接收到一个字节的中断,将其保存到数组中 if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET) { USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除RXNE中断标志位 recv_data[i++] = USART_ReceiveData(USART1);//将接收的数据保存到数组 } //如果是监测到总线空闲的中断,说明数据传输完毕。将计数(数组下标)清零、 //串口接收到时间修改的标志置位,最后记得要清空中断标志,先读SR、再读DR清除 else if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) { byte_cnt = I + 1;//数据量为数组下标+1(数组从0开始,计数从1开始) I = 0;//接收数据数组下标归0 flag_datarecv = 1;//接收一帧数据标志置1 //以下清除IDLE中断标志 clear = USART1->SR; clear = USART1->DR; } } 串口数据处理函数判断接收一帧数据标志flag_datarecv 是否等于1,等于1则提取数组中的数据进行处理,并将flag_datarecv标志清零:
/*如果串口接收到新数据,执行数据处理等*/ if(flag_datarecv == 1) { /*处理数组数据,处理完将数组清零*/ flag_datachange = 0;//清除数据接收标志 } |