ModbusRTU中的T3.5和T1.5的处理

ModbusRTU中的T3.5和T1.5的处理

本文是对上一篇文章的补充,写一写上篇文章中T3.5和T1.5的处理过程

1.首先讲一讲3.5个字符和1.5个字符的时间计算

在RTU模式,报文由时长至少3.5个字符时间的空间间隔区分。如下图:
两个帧数据之间,如果超过3.5个字符(字节)定时器的接收或发送周期,则产生中断,告诉本次帧接收完成了。两个帧数据之间,如果超过3.5个字符(字节)定时器的接收或发送周期,则产生中断,告诉本次帧接收完成了。在这里插入图片描述
两个帧数据之间,如果超过3.5个字符(字节)定时器的接收或发送周期,则产生中断,告诉本次帧接收完成了。
modbus帧内间隔在这里插入图片描述
整个报文帧必须以连续的字符流发送,如果两个字符之间的空闲大于1.5个字符时间,则报文帧认为不完整,应该被接收点丢弃。
注意:RTU接收驱动程序的实现,由于T1.5和T3.5的定时,隐含着大量对中断的管理。在高通信速率下,这导致CPU负担家中,因此,在<=19200bps时,这两个定时必须严格遵守;对于>19200bps的情形,应该使用2个定时的固定值,建议字符间的超时时间t1.5为750us;帧间超时时间为1.75ms。
3.5字符的时间间隔采用以下方式计算:

1个字符包括1位起始位、8位数据位(一般情况)、1位校验位(或者没有)、1位停止位(一般情况下)

这样说起来一般情况下1个字符就包括11位

那么3.5个字符就是3.511=38.5位 ;
波特率含义是每秒传输的二进制位的个数
我设置的波特率是9600bps,意思就是说每1秒(也就是1000毫秒)传输9600个位,
反过来说传输9600个二进制位需要1000毫秒
那么传输38.5个二进制位需要的时间就是:
38.5/9.6=4.0104167毫秒
MODBUS RTU要求一帧数据起始和结束至少有大于等于3.5个字符的时间
在波特率为9600的情况下,只要大于4.0104167毫秒即可!
1.5个字符时间间隔就是(1.5x11)/9.6=1.71875‬ms
而在上篇文章中已经设定了**定时器溢出时间为 Tout=((9+1)
(7199+1))/72000000=1ms**

2.0 FreeRTOSModbusRTU中关于数据的接收的处理过程

USART中字节的接收和发送:
在STM32的USART中,是按照字节发送的,每接收或发送一个字节,产生一次中断。
例如 TX:01 03 00 00 04 44 09
接收的步骤:

1)先接收01,然后产生一个中断,进入中断服务程序。

(中断服务程序功能:将01放进缓存中,然后重新定时器赋0值,并开启)

2)开始接收下一个数据:03。

3)依次类推,接收完所有的字节,然后拼接在一起,形成一个完整的数据帧。

字节、帧、定时器之间的配合:
在USART每次接收完一个字节,产生中断函数,函数重新给3.5T的这个定时器赋初始值0并开启。

当最后一个字符(例如上例中的 09)接收完后,对3.5T定时器进行最后一次赋0值。

3.5T定时器就一直计时,直到产生中断。此时,标志着一帧数据接收完成,开始了下一帧的数据。

在代码编程中的实现
我设置的定时器溢出时间是1ms,在上一篇文章中已经有了介绍。定时器每溢出1ms,就会产生一次定时中断,就会调用一次定时回调函数,变量 uCnt就会加一,当超过4次,就意味着超过了4ms即超过了3.5字符的时间间隔。这时就意味着一帧数据传输完成,然后关闭定时器,启动串口的回调函数即HAL_UART_RxCpltCallback(&huart1),处理数据。
处理流程为:
在这里插入图片描述

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
/* USER CODE END Callback 0 */
if (htim->Instance == TIM1) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */
  if(htim == &htim3)
    {
        uCnt ++;
        if(uCnt >= 4)
        {
           uCnt = 0;
            HAL_TIM_Base_Stop_IT(&htim3); // 停止定时器
            HAL_UART_RxCpltCallback(&huart1); // 一帧传输完成
        }
    }
   }

上面已经计算出了1.5个字符的时间间隔为1.71875‬ms,为了方便应用定时器,可以约等于为2ms。就是定时器溢出2次。这个需要到串口中断处理函数中去处理,即
HAL_UART_IRQHandler(UART_HandleTypeDef huart)
处理流程为:
在这里插入图片描述
在 HAL_UART_IRQHandler 函数中对以下代码段进行丰富:
/
UART in mode Receiver -------------------------------------------------*/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
return;
}
改为

/* UART in mode Receiver -------------------------------------------------*/
        if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
        {
            UART_Receive_IT(huart);
            if(uCnt >= 2) // 数据接收非法,清除已经接收数据
            {
                uCnt = 0;
                HAL_TIM_Base_Stop_IT(&htim3); // 停止定时器
             // 接收数据清零
            }
            else
            {
                uCnt = 0;
                HAL_TIM_Base_Stop_IT(&htim3); // 停止定时器
                __HAL_TIM_SET_COUNTER(&htim3, 0);
                HAL_TIM_Base_Start_IT(&htim3); // 启动定时器
            }
            return;
        }

串口每接收到一个字节,就会产生一次中断,进入中断处理,这时就要重新定时器赋0值,并开启。
上面的代码意思就是,当我们本次接收到的字节数据与上次间隔超过2 毫秒的时候,我们认为接收出错,扔掉上次已经接收的数据,下次重新接收。

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 数字20 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读