STM32使用HAL库实现ModBus RTU从机通讯
实验目的:使用HAL库实现ModBus RTU从机通讯实验芯片:STM32F407实验平台:STM32Cube IDE1、ModBus RTU通讯介绍网上类似的介绍很多,我只以我所需要的了解情况进行介绍,主要目的是为了快速上手,实现仪器通讯。ModBus RTU只是一种特定的通讯方式,对于STM32来说就是通过串口通讯,以该协议进行解码和传数。而对于ModBus RTU协议来说,我们先从一条简单的
实验目的:使用HAL库实现ModBus RTU从机通讯
实验芯片:STM32F407
实验平台:STM32Cube IDE
1、ModBus RTU通讯介绍
网上类似的介绍很多,我只以我所需要的了解情况进行介绍,主要目的是为了快速上手,实现仪器通讯。
ModBus RTU只是一种特定的通讯方式,对于STM32来说就是通过串口通讯,以该协议进行解码和传数。
而对于ModBus RTU协议来说,我们先从一条简单的报文来开始了解这个协议。
| 01 | 06 | 00 | 01 | 00 | 17 | 98 | 04 |
|---|---|---|---|---|---|---|---|
| 从机地址 | 功能号 | 数据地址 | 数据 | CRC校验 |
其中数据地址,数据,CRC校验都是两个字节。
这一串数据的意思是:把数据 0x0017(十进制23) 写入到 1号从机地址中的 0x0001数据地址。其中06功能码就代表写入的含义。
- 报文:就是一帧数据,包含地址、功能号等内容,就像上面的那一串数据。
- CRC校验:例如上面的 98 04 是它前面的数据(01 06 00 01 00 17)通过一算法计算出来的结果。
- 功能号:代表不同的功能,在该协议里通常会用到读写寄存器之类的说法。按我自己的理解就是对应于不同的变量,所谓的“线圈”“寄存器”就是“位变量”“16位变量”。
常用的功能号如下
01 (0x01) 读线圈
02 (0x02) 读离散量输入
03 (0x03) 读保持寄存器
04(0x04) 读输入寄存器
05 (0x05) 写单个线圈
06 (0x06) 写单个寄存器
15 (0x0F) 写多个线圈
16 (0x10) 写多个寄存器
举个栗子吧!
对于功能号1,我们对从机地址1发送功能号1,读取寄存器地址为0x0000开始的8个寄存器数值
| 01 | 01 | 00 | 00 | 00 | 08 | 3D | CC |
|---|---|---|---|---|---|---|---|
| 从机地址 | 功能号 | 寄存器地址 | 寄存器个数 | CRC校验 |
从机返回,例如:
| 01 | 01 | 02 | 03 | xx | xx |
|---|---|---|---|---|---|
| 从机地址 | 功能号 | 数据字节 | 寄存器值 | CRC校验 |
其中对于功能号中“线圈”来说,它是位的概念,相当于1个字节中每位都代表1个寄存器的值或者状态,由于我刚自己接触该行业,表述有误的地方,欢迎指正!
因此返回也是1个字节
对于功能号3,我们对从机地址1发送功能号3,读取寄存器地址为0x0CBC(十进制就是3260)开始的2个寄存器数值
| 01 | 03 | 0C | BC | 00 | 02 | 06 | BF |
|---|---|---|---|---|---|---|---|
| 从机地址 | 功能号 | 寄存器地址 | 寄存器个数 | CRC校验 |
从机返回,例如:
| 01 | 03 | 04 | FC | 5B | 49 | 76 | 0D | C6 |
|---|---|---|---|---|---|---|---|---|
| 从机地址 | 功能号 | 数据字节(寄存器个数*2) | 寄存器1值 | 寄存器2值 | CRC校验 |
对于功能号中“寄存器”来说,它是16位的概念,因此从机返回的数据字节数就是寄存器个数*2个字节。
- CRC校验算法说明
对于CRC校验,可以根据用户自己的需求进行修改。目前我使用的是通用常规的计算方法:循环冗余算法。
循环冗余校验CRC区为2字节,含一个16位二进制数据。由发送设备计算CRC值,并把计算值附在信息中,接收设备在接收信息时,重新计算CRC值,并把计算值与接收的在CRC区中实际值进行比较,若两者不相同,则产生一个错误。
CRC开始时先把寄存器的16位全部置成“1”,然后把相邻2个8位字节的数据放入当前寄存器中,只有每个字符的8位数据用作产生CRC,起始位,停止位和奇偶校验位不加到CRC中。产生CRC期间,每8位数据与寄存器中值进行异或运算,其结果向右移一位(向LSB方向),并用“0”填入MSB,检测LSB,若LSB为“1”则与预置的固定值异或,若LSB为“0”则不作异或运算。
重复上述处过程,直至移位8次,完成第8次移位后,下一个8位数据,与该寄存器的当前值异或,在所有信息处理完后,寄存器中的最终值为CRC值。
产生CRC的过程:- 把16位CRC寄存器置成FFFFH.
- 第一个8位数据与CRC寄存器低8位进行异或运算,把结果放入CRC寄存器。
- CRC寄存器向右移一位,MSB填零,检查LSB.
- (若LSB为0):重复3,再右移一位。
(若LSB为1):CRC寄存器与A001 H 进行异或运算 - 重复3和4直至完成8次移位,完成8位字节的处理。
- 重复2至5步,处理下一个8位数据,直至全部字节处理完毕。
- CRC寄存器的最终值为CRC值。
- 把CRC值放入信息时,高8位和低8位应分开放置。
大致介绍到这,其他可以根据协议进行细化。
2、ModBus RTU超时设置
至少需要 3.5 个字符时间间隔
两帧数据之间至少要有3.5个字符,可以根据所设的波特率进行配置。
/* RTU通信需要确定超时时间 */
#if DEBUG_USARTx_BAUDRATE <= 19200
/* 1.5个字符的超时时间 T = BAUDRATE/11/1000*/
#define OVERTIME_15CHAR (((float)DEBUG_USARTx_BAUDRATE/11)*1.5f)
/* 3个字符的超时时间 */
#define OVERTIME_35CHAR (((float)DEBUG_USARTx_BAUDRATE/11)*3.5f)
#else
/* 波特率超过19200bit/s的情况下建议的超时时间 */
#define OVERTIME_15CHAR 750.0f // 750us
#define OVERTIME_35CHAR 1750.0f // 1.75ms
#endif
更多推荐



所有评论(0)