wuzhengmin 发表于 2026-1-28 13:10:17

RTU 模式:
控制器以RTU模式在Modbus总线上进行通讯时,信息中的数据按十六进制传输,该模式的主要优点是在相同波特率下其传输的字符的密度高于ASCI模式,每个信息必须连续传输。
RTU 模式中每个字节的格式:
编码系统:所有数据均为十六进制。.
数据位:1 起始位
8 位数据,低位先送。
奇/偶校验:有奇/偶校验时占1位;无奇偶校验时不发送。(项目中一般都是无校验)。
停止位:有奇/偶校验则用1位停止位;无奇/偶校验则用2位停止位。(项目中一般使用1个停止位)。.
校验域:循环冗余校验(CRC16).
结束符:3.5个字符(字节)时间空闲。
RTU 帧:
RTU模式中,信息开始至少需要有3.5个字符的静止(空闲)时间(或者主机发送一帧结束后至少要间隔3.5 个字符的时间才发送下一帧),依据使用的波特率,很容易计算这个静止(空闲)的时间下面用实际的命令来说明,命令中所有数据均为十六进制。整个信息必须连续发送,如果在发送帧信息期间出现大于1.5个字符的静止时间时,则接收设备有可能丢弃不完整的信息。.

wuzhengmin 发表于 2026-1-28 13:16:34

偏移 0:此字节为从机设备地址,用于指定本次接收处理的从机地址,取值为0x00-0xff。从机设备地址是唯一的,同一条总线上不能有相同地址的连个从机。
一般0x00用于广播(比如发送同步帧),从机不返回信息。上例从机设备地址为0x01。
偏移 1:此字节为功能码,表明本次命令的操作功能,这个可以查询 MODBUS 支持的各种功能,实际项目一般用其中的一部分工嗯呢码,上例的功能码0x10就是“写多寄存器”。.
偏移 2:此 2 字节为要写入的寄存器首地址 0x0100,MODBUS 协议对数据的都是基于寄存器访问的,每个寄存器2个字节(一个WORD)。高字节在前,低字节在后。
偏移 4:此 2 字节为要写入的寄存器个数,0x0008 表示要写入 8 个奇存器。偏移 6:此字节为要写入的字节数,0x10 表示要写入 16个字节(8个寄存器)。

CRC校验电脑是小端模式

51是大端模式:
算出来是12CE传出去的是CD12

wuzhengmin 发表于 2026-1-28 13:22:43

偏移 6:此字节为要写入的字节数,0x10 表示要写入 16 个字节(8 个寄存器)。.
偏移7:此16个字节为要写入的数据。.
最后两个字节:CRC16 校验值 0x12CE,低字节在前,高字节在后(算法与电脑通用,小端模式)。
各个从机接收到信息后,有多种方式去判断是否是自己的数据,我一般习惯先校验,校验通过才做数据解
析,然后做出应答。如果校验通过,从机地址正确,则本机一定要做应答(即使是错误的命令)。


wuzhengmin 发表于 2026-1-28 13:27:37

偏移0:此字节为从机设备地址,同上述描述。
偏移1:此字节为功能码,同上述描述
偏移 2:此 2 字节为要写入的寄存器首地址,同上述描述。
偏移 4:此 2 字节为已经写入的寄存器个数,0x0004 表示已经写入 4个奇存器。
最后两个字节:CRC16 校验值 0x33C0,低字节在前,高字节在后(算法与电脑通用,小端模式)。,

wuzhengmin 发表于 2026-1-28 13:31:10

接着实际操作写多寄存器,读多寄存器:

wuzhengmin 发表于 2026-1-28 13:33:34

好好研究STC的CDC串口助手

可以发送CRC校验:

wuzhengmin 发表于 2026-1-28 13:37:04

双绞线传输,把干扰减低到最大,和网线一样

但是有寄生电容产生,就用9600!

我们接收方是STC link1D :

wuzhengmin 发表于 2026-1-28 13:37:55

读多寄存器也一样:

wuzhengmin 发表于 2026-1-28 13:48:10

程序执行的一般流程:

wuzhengmin 发表于 2026-1-28 13:52:09

校验结果=0为正常

除了自己的地址,还要检查广播地址0

各种错误代码的处理:

while (1)
        {
                if(B_RX1_OK && !B_TX1_Busy)        //收到数据, 进行MODBUS-RTU协议解析
                {
                        if(MODBUS_CRC16(RX1_Buffer, RX1_cnt) == 0)        //首先判断CRC16是否正确, 不正确则忽略, 不处理也不返回信息
                        {
                                if((RX1_Buffer == 0x00) || (RX1_Buffer == SL_ADDR))        //然后判断站号地址是否正确, 或者是否广播地址(不返回信息)
                                {
                                        if(RX1_cnt > 2) RX1_cnt -= 2;        //去掉CRC16校验字节
                                        i = MODBUS_RTU();        //MODBUS-RTU协议解析
                                        if(i != 0)        //错误处理
                                        {
                                                TX1_Buffer = SL_ADDR;        //站号地址
                                                TX1_Buffer = i;                        //错误代码
                                                crc = MODBUS_CRC16(TX1_Buffer, 2);
                                                TX1_Buffer = (u8)crc;        //CRC是小端模式, 先发低字节,后发高字节。
                                                TX1_Buffer = (u8)(crc>>8);
                                                B_TX1_Busy = 1;                //标志发送忙
                                                TX1_cnt    = 0;                //发送字节计数
                                                TX1_number = 4;                //要发送的字节数
                                                TI = 1;                                //启动发送
                                        }
                                }
                        }
                        RX1_cnt = 0;
                        B_RX1_OK = 0;
                }
        }
页: 77 78 79 80 81 82 83 84 85 86 [87] 88 89
查看完整版本: 有关DMA,山东大学陈桂友教授