[ ST NUCLEO-U575ZI-Q 测评] 9-通过UART的"接收超时"功能获取一帧数据
<div class='showpostmsg'><p data-line="0" dir="auto">很多工程师都是通过循环DMA配合UART的IDLE中断实现1帧数据接收的。</p><p data-line="2" dir="auto">但是这种方式也有缺点,比如一个设备在发送同一帧数据时,在发送数据帧的中间去处理中断,造成一个数据帧分成2个部分发出的。这两个部分中间出现了一个空闲帧。那么我们使用上面的方法去接收数据就有问题了。</p>
<p data-line="4" dir="auto">那么能不能不要一收到空闲帧就断帧,而是有一定的延时呢?有一定的延时就能很好的解决上面的问题。在以前需要使用一个定时器计时。但现在在STM32U5中提供了一个"接收超时"的功能。</p>
<p data-line="6" dir="auto">通过这个功能,我们可以设置一定的延时时间,如果在收到最后一个字节的停止位后,这个延时时间之后没有收到新的数据,就产生一个中断。</p>
<p data-line="8" dir="auto">在STM32U5中,通过RTOEN位可以使能这个功能,通过RTOIE可以使能对应的中断。通过RTO可以设置一定的延时时间,注意这个时间是按照波特率的位时间计算的,比如波特率是9600,那么如果想延时100ms,则对应的是发送了960位,那么就要在RTO中写入960,以设置100ms的延时。</p>
<p data-line="10" dir="auto">在下面的例子中,使用RTOF中断配合DMA实现数据的自动收取和断帧。</p>
<h3 data-line="12" dir="auto" id="%E4%B8%80%E4%BD%BF%E8%83%BD">一、使能</h3>
<p data-line="14" dir="auto">首先在串口初始化的下面添加使能"接收超时"的功能。</p>
<pre>
<code class="language-cpp">HAL_UART_EnableReceiverTimeout(&huart1); //使能接收超时
HAL_UART_ReceiverTimeout_Config(&huart1,960); //设置超时时间,这个需要根据波特率算,如果波特率是9600,那么超时按照100ms算的话,就是960,也就是接收960个位的时长为100ms
__HAL_UART_CLEAR_FLAG(&huart1,UART_CLEAR_RTOF); //先清楚RTOF位,这个位指示是否接收超时
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RTO); //使能接收超时的中断</code></pre>
<h3 data-line="24" dir="auto" id="%E4%BA%8C%E4%B8%AD%E6%96%AD%E5%87%BD%E6%95%B0">二、中断函数</h3>
<p data-line="26" dir="auto">然后在串口的中断函数中添加处理函数,因RTOF需要软件清除,因此需要在中断中手动清除标志位。因为DMA配置的是循环接收,所以是用的环形数组。进入RTOF中断后,就认为1帧数据结束,从数组中取出数据放到另一个缓存区,并置标志位。有main函数将数据原样发出。</p>
<p data-line="27" dir="auto">注意自己定义的RTOF中断函数要放在中断函数的前部,不要放在 *HAL_UART_IRQHandler(&huart1);*的后面,因为这个函数里也有RTOF的处理功能,会影响使用的。</p>
<pre>
<code class="language-cpp">void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
static uint16_t last_index;
uint16_t index;
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RTOF) != 0){
__HAL_UART_CLEAR_FLAG(&huart1,UART_CLEAR_RTOF); //清除标志位
//以下内容为环形数组的数据读取,写的有点粗糙,仅做参考
index = 100-( __HAL_DMA_GET_COUNTER(huart1.hdmarx));
if(index != last_index){
if(index > last_index){
for(int i = last_index;i<index;i++){
send_buf = recv_buf;
}
send_buf = index - last_index;
}else{
uint16_t s_index = 0;
for(int i=last_index;i<100;i++){
send_buf = recv_buf;
}
for(int i =0;i<index;i++){
send_buf = recv_buf;
}
send_buf = s_index;
}
last_index = index;
}
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}</code></pre>
<h3 data-line="67" dir="auto" id="%E4%B8%89%E6%B5%8B%E8%AF%95idle%E5%92%8Crtof%E4%B8%AD%E6%96%AD">三、测试IDLE和RTOF中断</h3>
<p data-line="69" dir="auto">最后测试了一下使用IDLE中断和RTOF中断,这两个的时间差。和预期的一样。如果使用115200的波特率,超时值设为1152,则IDLE中断应该比RTOF中断早100ms。通过systick的计数值估算时间,如下图所示。</p>
<p data-line="69" dir="auto"></p>
<p data-line="73" dir="auto">其中time1是进入IDLE中断的时间,time2是进入RTOF中断的时间。两者相差正好是100,也就是100ms 。</p>
<h3 data-line="75" dir="auto" id="%E5%9B%9B%E6%80%BB%E7%BB%93">四、总结</h3>
<p data-line="77" dir="auto">IDLE和RTOF两种方式获取1帧数据,各有各的有点。使用IDLE的话有现成的HAL库,但是确实会有判断出错的情况。而使用RTOF的话会更灵活,但是需要自己编写一部分代码。</p>
</div><script> var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
} </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script> <p>IDLE和RTOF两种方式获取1帧数据,各有各的有点。使用IDLE的话有现成的HAL库,但是确实会有判断出错的情况。而使用RTOF的话会更灵活,但是需要自己编写一部分代码。</p>
<p>感谢楼主分享这么清晰的串口接收代码。</p>
<p>RTOF是STM32U5特有的功能吗?如果是的话,后续系列感觉也会携带这个功能。</p>
wangerxian 发表于 2023-1-10 09:20
RTOF是STM32U5特有的功能吗?如果是的话,后续系列感觉也会携带这个功能。
<p>不是的,STM32G0也有这个功能。估计后续的产品都有这个功能。我看ST的社区说这方面的HAL库也正在设计。</p>
lugl4313820 发表于 2023-1-10 07:17
IDLE和RTOF两种方式获取1帧数据,各有各的有点。使用IDLE的话有现成的HAL库,但是确实会有判断出错的情况。 ...
<p>谢谢支持<img height="28" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/smiling-face-with-smiling-eyes_1f60a.png" width="28" /></p>
manhuami2007 发表于 2023-1-10 10:26
不是的,STM32G0也有这个功能。估计后续的产品都有这个功能。我看ST的社区说这方面的HAL库也正在设计。
<p>那不错,以前都是用的空闲中断检测数据是否发送完毕,现在能检测接收超时确实是优化了!</p>
<p>测评汇总:免费申请|ST NUCLEO-U575ZI-Q https://bbs.eeworld.com.cn/thread-1228653-1-1.html</p>
页:
[1]