在CubeMx生成代码时,默认为 HAL 库,但也可以指定为 LL库,LL库基本是直接操作寄存器,功能较为单一,但是效率更高。串口使用HAL如果每次接收一个字次,由于HAL库的效率,容易丢包,若一次性接收多个字节,又需要固定的字节数。
于是这次使用了 LL 库,在LL库中:
LL_USART_TransmitData8();
为发送一个字节函数,通过查看定义可知,它直接操作了DR寄存器,所以效率很高。
这次想设计一个简单的程序:当收到字符A的时,发送字符E,但是发现居然有丢包的现象,这是由于程序逻辑问题导致的,这也是库函数使用者对寄存器操作不熟悉的原因,最后调整程序如下:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
static uint8_t recv;
if(USART1->SR&(1<<5)) //如果接受到数据
{
recv = LL_USART_ReceiveData8(USART1); //读取数据
if(recv == 'A') //如果是字符A
{
LL_USART_TransmitData8(USART1,'E'); //发送字符E
while((USART1->SR&0X40)==0); //等待数据发送完成
}
}
/* USER CODE BEGIN 3 */
}
上文程序不断的轮询,判断是否接受到数据,再进行值的读取,将数据发送出去以后,等待数据发送完成,经测试效果稳定:
可以看到,100B/s 的速度发送了近4万个字节,也接到同样的数据,说明程序未丢包。
如果把 recv = LL_USART_ReceiveData8(USART1)
,移出if
语句,如下:
// !!错误代码示例
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
static uint8_t recv;
recv = LL_USART_ReceiveData8(USART1); //读取数据
if(USART1->SR&(1<<5)) //如果接受到数据
{
if(recv == 'A') //如果是字符A
{
LL_USART_TransmitData8(USART1,'E'); //发送字符E
while((USART1->SR&0X40)==0); //等待数据发送完成
}
}
/* USER CODE BEGIN 3 */
}
即未接收到新的数据,也不断的读取DR的值,程序测试会出现比较频繁的丢包。
可以看到,同样的数据发送,241个字节,才收到92个字节,丢包严重。原因可能是频繁的调用LL_USART_ReceiveData8()
(读取DR的值),导致串口外设一直忙碌,最后导致了丢包。