FreeModbus从站设计(8)-用HAL库函数理清Modbus的数据收发流程
关键词:FreeModbus STM32F103 CubeMX HAL库
1.基本框图
如图1所示,HAL库的函数中,与Freemodbus协议栈相关的,主要是定时器和串口的操作部分。孔丙火(微信公众号:孔丙火)认为,可以这样简单描述:在协议栈完成初始化后,就将串口(RS485)设置为接收状态,等待主站的数据,当接收到主站的一个字节的数据后,开启定时器,在3.5个字符周期内如果接收到了第二个字节的数据,则将定时器清零重新开始计时,若果3.5个字符周期内没有接收到新的字节,则认为一帧数据接收完毕,开始处理数据,并相应地发送回复数据,回复数据也是逐个字节进行发送的。
图1
2.接口函数
2.1 vMBPortSerialEnable()
这个函数定义在portserial.c中,所有的调用均在mbrtu.c和mbascii.c中,由于这里我们只实现RTU,因此,只关注mbrtu.c中调用。在mbrtu.c中,共有5处调用此函数,分别在eMBRTUStop()、eMBRTUStop()、eMBRTUSend()、xMBRTUTransmitFSM()中,这个函数的作用,就是使能或禁止串口的接收或发送中断,状态的转换是根据协议栈的状态机来进行的,孔丙火(微信公众号:孔丙火)认为,看一看Modbus协议文本中的状态机图,有助于深入理解协议的运行。基于以上理解,vMBPortSerialEnable()函数的代码如下:
图2
HAL_UART_Receive_IT(&huart2,&ucUsrUart2Rxbuf,1),这个函数是HAL库函数,孔丙火(微信公众号:孔丙火)认为,可以这样理解,以中断方式通过串口2接收一个字节的数据,存在变量ucUsrUart2Rxbuf中,这里取得是ucUsrUart2Rxbuf的地址指针。
__HAL_UART_DISABLE_IT(&huart2,UART_IT_RXNE)这个函数是禁止接收中断。在这个函数下面,写了这样一个语句:huart2.RxState = HAL_UART_STATE_READY;同样的,在发送部分有:huart2.gState = HAL_UART_STATE_READY;下面简单阐述一下作用。
最初开始弄FreeModbus移植的时候,在网上查阅了一些资料,有的是基于HAL库的,有的不是,有的是交叉使用,由于学习了一段时间的HAL库,感觉其还是比较易用的,孔丙火(微信公众号:孔丙火)就想着能不能完全用HAL库的函数来实现的FreeModbus移植,于是就有后来的实践。
加这样一个语句,是为了解决在实际调试过程中碰到的问题。刚开始调试的时候发现,单片机作为从站,只能接收一帧数据,第2帧以后的数据,不再有反应。由于是调用HAL_UART_Receive_IT(&huart2,&ucUsrUart2Rxbuf,1);来使能接收非空中断,调用__HAL_UART_DISABLE_IT(&huart2,UART_IT_RXNE);来禁用接收非空中断,那就要从HAL_UART_Receive_IT()这个函数开始说起,在以前的文章中,孔丙火(微信公众号:孔丙火)说过,这个函数本质上是一个配置函数,配置好接收缓冲区的指针和一次接收的字节数,把这个函数贴出来看一下:
图3
可以看出,这个函数的主要功能就是设置接收缓存的指针和字节数,然后使能接收非空中断,但在一开始有一个条件判断,huart->RxState,这其实是对串口接收状态的一个管理,当串口中断方式接收已经被配置过了、接收过程还没有完成的时候,是不能再次配置的,防止接收数据出错。
在这个函数中,配置完了以后,就将huart->RxState的状态置为了HAL_UART_STATE_BUSY_RX,这个状态是在串口中断处理函数中完成数据接收后,重新设为HAL_UART_STATE_READY。在本文的程序中,当从站接收数据完成后(定时器动作,表示一个完整的帧接收完成),协议栈需要将接收非空中断禁掉,但这之前串口仍处于接收状态(调用过HAL_UART_Receive_IT(&huart2,&ucUsrUart2Rxbuf,1)),因此RxState的状态是HAL_UART_STATE_BUSY_RX,这样在下次转为接收时,无法HAL_UART_Receive_IT()来进行配置,就是由于上面提到的图3红框中的条件判断。因此,在发现此问题后,加了这个语句,确保后续能正常接收,并且这样可以不用修改HAL库本身的函数。发送部分是同样的道理。
下一篇精彩继续。
文章在公众号(孔丙火)同步推出,欢迎查看更多系列文章。
单片机、PLC、嵌入式软硬件的设计经验分享,秉承“点点滴滴皆智慧”的理念,以实际项目为单元阐述知识点,一起分享,共同交流。
文章评论(0条评论)
登录后参与讨论