在如今这个需要快速开发设计出产品的时代,模块化的东西越来越方便快捷,在各种模块使用的接口里面串口应该是比较常见和常用的,串口蓝牙模块,串口WIFI模块等等,除此之外串口还常用于和客户产品进行通信中也比较方便,因此一个接收发送数据等功能完善的串口对项目开发来说非常重要。(STM32官网)
在ST发布比较新的系列的ARM芯片中,串口已经非常强大,下面我们就简单测试几个比较常用的功能。
1、接收超时中断+DMA接收不定长数据
如果我们想要用串口接收一段长度不确定的数据,比较常见的做法是空闲中断配合DMA或者自己使用定时器进行一个超时判断来确定一帧长度数据接收完成,除此之外在STM32F7系列中串口有一个Receiver timeout 中断,使用这个接收超时中断配合DMA可以很方便的接收不定长数据。
接收超时中断用于串口在接收到最后一个字符后,在设置的超时时间内没有接收到新的数据便会触发。
接收超时中断的设置超时时间是以串口接收一个bit的持续的时间为单位,这个时间和波特率有关系实际使用中可以根据具体情况进行调整,然后设置超时多少个这样的持续时间才会触发中断。
接收超时设置和中断回调函数如下
- //打开或者关闭串口接收超时
- void USART_ReceiverTimeOutCmd(USART_TypeDef* USARTx, FunctionalState NewState)
- {
- if (NewState != DISABLE)
- {
- USARTx->CR2 |= USART_CR2_RTOEN;
- }
- else
- {
- USARTx->CR2 &= (uint32_t)~((uint32_t)USART_CR2_RTOEN);
- }
- }
- //设置串口接收超时时间
- void USART_SetReceiverTimeOut(USART_TypeDef* USARTx, uint32_t USART_ReceiverTimeOut)
- {
- USARTx->RTOR &= (uint32_t)~((uint32_t)USART_RTOR_RTO);
- USARTx->RTOR |= USART_ReceiverTimeOut;
- }
- //接收超时中断回调函数
- void UART_ReceiverTimeOut_Callback(UART_HandleTypeDef *huart)
- {
- uint16_t len;
- uint32_t tmp1 = 0;
- tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RTOF);
- if((tmp1 != RESET))
- {
- __HAL_UART_CLEAR_IT(huart, UART_CLEAR_RTOF);
- /* set uart state ready*/
- huart->RxState = HAL_UART_STATE_READY;
- /* Disable the rx DMA peripheral */
- __HAL_DMA_DISABLE(huart->hdmarx);
- /*Clear the DMA Stream pending flags.*/
- __HAL_DMA_CLEAR_FLAG(huart->hdmarx, __HAL_DMA_GET_TC_FLAG_INDEX(huart->hdmarx));
- /* get rx data len */
- len = huart->hdmarx->Instance->NDTR;
- U1_Rxlen = RXBUFFLENGTH - len;
- /* Process Unlocked */
- __HAL_UNLOCK(huart->hdmarx);
-
- huart->hdmarx->State = HAL_DMA_STATE_READY;
- HAL_UART_Receive_DMA(huart, U1_RxBuff, RXBUFFLENGTH);
- }
- }
复制代码 在演示程序的mian函数中我们将接收到的数据使用dma再发送到串口
- //串口接收超时中断测试
- //2016年12月10日
- //creep
- int main(void)
- {
- CPU_CACHE_Enable();
- HAL_Init();
- SystemClock_Config();
- USART1_Init();
- while (1)
- {
- if(U1_Rxlen)
- {
- HAL_UART_Transmit_DMA(&UartHandle, U1_RxBuff, U1_Rxlen);
- U1_Rxlen = 0;
- }
- }
- }
复制代码 下面的演示可以看到调试串口助手可以发送不定长的任意数据到串口,然后串口将接收的数据在发送到调试串口:
上面的演示中发送和接收字符串开始和结尾带有特殊的◇和■是因为串口助手的时间戳和分包显示导致,实际接收和发送的数据不受影响:
2、字符匹配中断
STM32F7系列串口还有一个中断叫 Character match中断,主要功能就是检测到串口收到某个字符后产生中断,这个字符可以设置为一个字节的长度。
要使用这个中断比较简单,只需要设置要匹配的字符然后使能中断即可。设置匹配的寄存器如下:
匹配字符设置和中断回调函数如下:
- //设置匹配的检测字符
- void USART_SetCharactermatch(USART_TypeDef* USARTx, uint8_t match)
- {
- USARTx->CR2 &= (uint32_t)~((uint32_t)USART_CR2_ADD);
- USARTx->CR2 |= match << 24;
- }
- //字符匹配中断回调函数
- void UART_Charactermatch_Callback(UART_HandleTypeDef *huart)
- {
-
- uint32_t tmp1 = 0;
- tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_CMF);
- if((tmp1 != RESET))
- {
- __HAL_UART_CLEAR_IT(huart, UART_CLEAR_CMF);
- huart->RxState = HAL_UART_STATE_READY;
- CharMatchSta = ENABLE;
- CharMatchVal = USART3->RDR;
- }
- }
复制代码 mian函数如下,如果检测到匹配字符,回复串口助手 “Receive Match Character”,如果收到的字符不是匹配字符不回复任何数据
- //串口接收字符匹配中断测试
- //2016年12月10日
- //creep
- int main(void)
- {
- CPU_CACHE_Enable();
- HAL_Init();
- SystemClock_Config();
- USART1_Init();
- while (1)
- {
- if(CharMatchSta)
- {
- printf("Receive Match Character\r\n");
- CharMatchSta = DISABLE;
- }
- }
- }
复制代码 我们首先设置匹配字符'a',然后可以看到发送a的时候回收到应答,发送不是a的时候收不到应答:
然后我们再设置匹配字符为hex的0x41(既是ascii的A)
3、字符匹配中断+DMA
字符匹配中断如何配合DMA使用也可以接收一个特殊的字符串,或许在特殊的情况下能起到事半功倍的效果。 同样下面在测试中我们将收到的数据通过串口发的串口助手,匹配字符设置为a。
a) 发送多个字符串,当发送的字符中有a时会收到之前发送的所有的字符串
b)发送任意长度的以a结尾的字符串
c)发送的字符a后面还有字符串 类似 "hello world a Hi, I AM CREEP"这样的字符
通过上面3种不同字符串类型我们可以看到字符匹配中断和DMA配合使用可以很方便实现接收一些特殊类型的字符串。
4、串口的其他功能
除了上面的超时中断和字符匹配中断之外,STM32f7还有很多其他的功能,比如波特率自动检测,TX/RX交换,Binary Data 倒置,空闲中断,END of Block 中断等等功能,总之ST的新的系列的芯片的串口真的是越来约强大了,这无疑给我们的开发和使用带来非常大的方便。
上面的测试代码只对基本的功能做演示和验证,如果要在实际的项目和产品中使用还需要对相应的功能更加仔细的研究和严格的验证。
延伸阅读:
波特率自动识别
测试代码:
USART_ReceiverTimeOut_DMA.rar
(865.88 KB, 下载次数: 142)
|
gif 录制软件:
最新版本sscom:
可能兼容不好做,要不F1/F4这些发布较早的系列也可以加入这些新功能了,而且这些系列用户群目前应该是最多的。
我用的F1/F4时也没有看到过这个超时中断和字符匹配中断,L0/F0/F7这些后面的系列好像都有这些中断了。
我也是看参考手册才发现新出的系列的串口功能真多。
谢谢分享
飞哥好