[MM32硬件] 【灵动微电子MM32F0121测评】7、手搓modbus协议从机(二)

[复制链接]
 楼主| 穿西装的强子 发表于 2025-6-20 23:06 | 显示全部楼层 |阅读模式
本帖最后由 穿西装的强子 于 2025-6-20 23:11 编辑

根据上一个帖子已经搭建好了modbus传输的协议,只需添加0x06和0x10寄存器功能即可 251716855775657c67.png
以下是0x06寄存器,根据协议,如果协议正常,则返回值与发送值一样,因此使用memcpy将接收的usart数据复制到tx数据内
再将接收数据的寄存器值存在Modbus_data这个变量里做存储使用

  1. void ModBus_Register_SingleWrite(USART_RxTx_TypeDef *usart,USART_RxTx_TypeDef *tx)
  2. {
  3.         uint16_t register_addr = (usart->Buffer[2]<<8)|(usart->Buffer[3]);// 寄存器地址
  4.         if( register_addr  >= 128)
  5.         {
  6.                
  7.         } else {
  8.                 tx->Length = usart->Length;
  9.                 memcpy(&tx->Buffer[0],&usart->Buffer[0],usart->Length);
  10.                 modbus_data[register_addr] = (usart->Buffer[4]<<8)|(usart->Buffer[5]);
  11.                 tx->CompleteFlag = 1;
  12.                 USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
  13.         }
  14. }
根据0x10寄存器,是写多个数据,按照协议,是有数据长度和寄存器个数的参数,理论上是按着寄存器数据连续的写入,而不是跳着写入这些数据,因此这些数据可以根据地址内容进行填充,正常接收的话,返回寄存器地址和寄存器个数即可。


94771685577730ae96.png
根据以上协议,数据总长度= 寄存器个数*2+固定字节9,因此小于该长度的数据都属于异常数据。
由于数据类型是16位的,因此将接收的8位数据转换成16位数据进行存储,存储的数据可以根据自己的使用方法进行调用即可。
  1. void ModBus_Register_MultiWrite(USART_RxTx_TypeDef *usart,USART_RxTx_TypeDef *tx)
  2. {
  3.         uint16_t register_addr = (usart->Buffer[2]<<8)|(usart->Buffer[3]);// 寄存器地址
  4.         uint16_t register_len = (usart->Buffer[4]<<8)|(usart->Buffer[5]);// 寄存器数据长度
  5.         if( usart->Length < (9+register_len*2)){
  6.                
  7.         } else {
  8.                 tx->Length = 0;
  9.                 tx->Buffer[tx->Length++] = DEVICES_ID;
  10.                 tx->Buffer[tx->Length++] = 16;
  11.                 tx->Buffer[tx->Length++] = usart->Buffer[2];
  12.                 tx->Buffer[tx->Length++] = usart->Buffer[3];
  13.                 tx->Buffer[tx->Length++] = usart->Buffer[4];
  14.                 tx->Buffer[tx->Length++] = usart->Buffer[5];
  15.                 uint16_t crc = calculate_crc_direct(tx->Buffer,tx->Length);
  16.                 tx->Buffer[tx->Length++] = crc;
  17.                 tx->Buffer[tx->Length++] = crc>>8;
  18.                
  19.                 for( uint16_t i = 0; i < register_len;i++)
  20.                 {
  21.                         modbus_data[register_addr+i] = (usart->Buffer[(i)*2+7]<<8)|(usart->Buffer[(i)*2+1+7]);
  22.                 }
  23.                 tx->CompleteFlag = 1;
  24.                 USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
  25.                
  26.         }
  27.         
  28. }
最后,视频演示,该视频是在使用KEIL5进行debug阶段验证,可以看到左侧工程文件是MM32F0120的芯片
840296855786e61430.png
右侧是modbus寄存器数据,可以看到视频在使用modbus poll软件进行通信时,选择了16(0x10)寄存器,进行多数据写入功能,每次修改寄存器值时,keil的右侧debug界面modbus数据都会变化。
录屏没录好,只录了modbuspoll的,没把keil录进去
73727685579f16316f.png


AdaMaYun 发表于 2025-7-31 17:53 | 显示全部楼层
modbus协议从机值得推荐
uytyu 发表于 2025-8-4 10:15 | 显示全部楼层
Modbus RTU是一种串行通信协议,使用CRC校验,适用于RS-485或RS-232接口。
claretttt 发表于 2025-8-4 15:38 | 显示全部楼层
正确解析主站发送的Modbus报文
ulystronglll 发表于 2025-8-5 12:27 | 显示全部楼层
485方向切换延时必须实测              
wilhelmina2 发表于 2025-8-5 14:42 | 显示全部楼层
RS-485收发器的DE和RE引脚被正确控制,以切换到发送模式。
maudlu 发表于 2025-8-7 17:42 | 显示全部楼层
通过Modbus Poll软件模拟主机发送Modbus RTU协议报文。
eefas 发表于 2025-8-8 10:45 | 显示全部楼层
检测Modbus帧的起始(通常为设备地址字节)和结束(CRC校验码)。
burgessmaggie 发表于 2025-8-8 14:52 | 显示全部楼层
处理不等长数据帧时的边界条件              
您需要登录后才可以回帖 登录 | 注册

本版积分规则

61

主题

258

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部