1.stm32的USART分为UART(也就是通用异步收发器),和同步的USART,区别在于UART只需要两根线,即TX和RX即可,而USART配置为同步收发器时,需要额外的时钟线

2.USART收发数据有三种方式分别是

(1)轮询阻塞

(2)中断

(3)配合DMA

3.接收数据数量的判断

示例
HAL_UART_Receive(&huart1, buff, 200, 1000)

//RxXferSize这个变量表示需要接收的数据的总大小,单位是字节
//RxXferCount这个变量表示当前还剩下多少数据需要接收,单位是字节
number=RxXferSize -huart1.RxXferCount
二者相减,即可得到接收到的实际数量

4.

采用中断方式发送与接收数据时,

(采用一个字节有效数据,一位停止位时),每当发送/接收一个字节数据,就会进入一次USART1_IRQHandler(void),进而进入    HAL_UART_IRQHandler(&huart1)HAL中断公共处理函数,在这个函数中会根据发送/接收进入不同的更低一层的处理函数,

        (1)只有在接收完最后一个数据之后(即接收完成后) ,会失能相应的RXNE的中断,然后将gstate置于ready状态,回调进入HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)在这个函数中处理数据。

        (2)在发送完最后一个数据后,会失能相应的TXE的中断,而使能TC(transmit complete)中断,调用UART_EndTransmit_IT(huart)这个函数,在其中失能TC中断,然后将gstate置于ready状态,以等待下一批数据的发送,最后调用HAL_UART_TxCpltCallback(huart)。

        (3)因此你可以发现,只有在这一批数据发送/接收完成后,才可以进入接收/发送完成回调函数

        (4)你也可以发现每次一批数据接收/发送完成之后(在进入HAL_UART_TX/RxCpltCallback 前)都进行了对TXE/RXNE的失能,因此在处理HAL_UART_TX/RxCpltCallback回调函数时,不会因为有新一批数据而会产生中断,因此当你在此需要接收/发送数据时,都需要在重新调用

HAL_UART_Transmit_IT()或者HAL_UART_Receive_IT()来重新使能TXE/RXNE中断

void USART1_IRQHandler(void)      //NVIC向量表中定义的USART1的中断函数
{
	  
     HAL_UART_IRQHandler(&huart1); //调用Hal库的USART中断公共处理函数
		
}
 

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
//接收完成回调函数

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
//发送完成回调函数

5.采用 空闲中断+循环缓冲区 实现不定长数据的收发

(1) 空闲中断:在接收到数据后,如果在一个字节的周期内没有新的数据接收,硬件会置位IDLE位

(2)循环缓冲区:

分别设置接收与发送缓冲区,接收缓冲区存放接收到的数据,而发送缓冲区存放需要发送的数据。

环形串口缓冲区建立的数组要定义一个头(记录新来的数据要存放的位置)和一个尾(记录读出数据的位置)。这时有三种情况:
        1、当头等于尾时,我们便知道此时环形串口缓冲区无数据,此时不进行读操作。
        2、有数据来时,数组存储数据,并且头按数据的长度向前移动,空闲时尾开始取数据,直到尾等于头为止。
        3、当头存到数组长度的最后一位时,返回数组第一位开始存数据

(3)注意:我们需要定义接收数据的最大长度,每次接收的数据虽然是不定长数据,但是不能超过最大长度,否则就会回调HAL_UART_RxCpltCallback(huart); 这个接收完成回调函数,我们采用的时,监测到总线空闲,就产生空闲中断,然后人为中止此次接收过程,之后在空闲中断中,处理数据

void  USART1_IRQHandler(void)
{
		HAL_UART_IRQHandler(&UCB1.UART);
	
		if(__HAL_UART_GET_FLAG(&UCB1.UART,UART_FLAG_IDLE))			//发生了空闲中断
		{
				__HAL_UART_CLEAR_IDLEFLAG(&UCB1.UART);
			
				UCB1.RxCounter+=RX_MAX- UCB1.UART.RxXferCount;   		
            //记录接收的总的数量
			
				HAL_UART_AbortReceive_IT(&UCB1.UART);              
         //以中断的方式,中止接收传输过程,失能RXNE中断
			
		}
	
}

(详细的实现调用过程,阅读源码可知)

6.利用串口实现多机通信,有两种区分通信从机的方式,一种时空闲空闲线路检测另一种是址标记检测这两种方式,总线上都不会产生空闲中断。因此利用空闲中断判断接收一批数据结束的方式就失效了。

RWU: Receiver wakeup(USART_CR1)

0: Receiver in active mode   可以接收

1: Receiver in mute mode   静默模式

(1)地址标记检测,接收器的地址在 USART_CR2 寄存器的 ADD 位中进行设置,四位,

0000-1111,总共可以区分16个从机,在此模式下,发送的第一个字节为地址,该字节的最高位为 1,则将这些字节识别为地址,否则将其识别为数据。在地址字节中,目标接收器的地址位于 4 个 LSB 上,接收器会将此 4 位字与其地址进行比较,当接收到与编程地址匹配的地址字符时,它会退出静音模式。

   (2)正如上述所说,不能通过总线空闲中断的方式,检测一批数据的接收完成,这边我们采用定时器超时判断的方式,在波特率为9600 bit/s时,1秒可以发送960个字节数据,一个字节数据需要1/960=1.04ms左右,因此可以用定时器定时20/30ms,

if(接收的是第一个字节)

{  使能定时器计数,让其开始计时}

else// 接收的不是第一个字节,接收已经开始

{  清除定时器计数器(只有最后一个数据才会 超时)   }

只有接收到最后一个字节,后面没有给他清除计数器,会导致超时,表示这一批数据接收完成,超时就触发中断函数,在中断函数中,执行相应操作。

(2)空闲检测

检测到总线空闲,那么从机就唤醒,RWU=0,发送的第一个数据为地址,地址不匹配时,手动进入静默模式,RWU=1,之后这一批数据发送完成,总线空闲时,从机的RWU=0,再次进入准备接收模式。

7.常见错误

作者:你心如何猜透

物联沃分享整理
物联沃-IOTWORD物联网 » stm32USART

发表回复