最近一个项目用到了MODBUS协议,就学习了一下,这里做一下记录以免后续忘记。
要用到MODBUS肯定要先知道是MOBUS协议,这里呢我们就又要先理解协议的含义了。
所谓的协议是什么?就是互相之间的约定嘛,如果不让别人知道那就是暗号。现在就来定义一个新的最简单协议。
例如: 协议: “A”--“LED灭” “B”--“报警” “C”--“LED亮” 。
单片机接收到“A”控制一个LED灭,单片机接收到“B”控制报警,单片机接收到“A”控制一个LED亮。那么当收到对应的信息就执行相应的动作,这就是协议。
MODBUS 一包数据主要组成有 : 设备地址 功能码 数据长度 数据 CRC
先来简单分析一条MODBUS-RTU报文,例如:

这个包数据的意思是往设备地址为 0x01 的设备中,执行 0x1f 代号的功能 ,这里假设 0x1f 代号功能码代表的是保存数据再Flash,那这包数据的意思就是,控制 0x01 设备,执行 0x1f 代号功能保存后面4位数据到 MCU 的 Flash 中,其中数据长度是指后面数据字节数的大小,最后两个 CRC 校验是除了最后两位 CRC 前面所有数据经过CRC运算出来的校验码,用来保证数据的准确性。
协议大概就是这么些内容,因为只是简单的应用,就没有深入去研究了,知道这些运用到STM32上已经够了,下面的是CRC校验的代码(重点):
/***
函数名:uint16_t Crc(uint8_t Rxbuff[],uint8_t Rx_len)
说 明:Modbus协议CRC校验
传入值:Rxbuff[] 串口接收的数据,len串口接收的数据长度
传出值:返回两个字节的CRC校验码,高位在前,低位在后
**/
uint16_t Crc(uint8_t Rxbuff[],uint8_t Rx_len)
{
uint8_t len = Rx_len - 2;
uint16_t crc_result = 0xffff;
int crc_num =0;
int xor_flag=0;
for(int i=0;i crc_result ^= Rxbuff[i]; crc_num = (crc_result&0x0001); for(int m=0;m<8;m++) { if(crc_num==1) xor_flag = 1; else xor_flag = 0; crc_result >>= 1; if(xor_flag) crc_result ^= 0xa001; crc_num = (crc_result & 0x0001); } } return crc_result; } 下面的是MODBUS运用的举例代码,这里我对MODBUS协议做了些修改,在 “功能码 ” 跟 “数据长度 ” 间多加了个 “读写标志位”,实际项目时可以根据自己项目需求做一下修改也无可厚非: /*** 函数名:void modbus(uint8_t Rxbuff[],uint8_t len) 说 明:Modbus协议处理 传入值:Rxbuff[] 串口接收的数据,len串口接收的数据长度 传出值:无 **/ void modbus(uint8_t Rxbuff[],uint8_t len) { uint8_t Read_Robot [1]={0}; uint8_t Robot_add=0x01; uint8_t Robot = Get_Robot_Num(); //获取预先保存好的设备地址 uint16_t crc=Crc(Rxbuff,len); uint16_t Rx_crc = Rxbuff[len-2]<<8 | Rxbuff[len-1]; if((Robot==Rxbuff[0] ||Rxbuff[0] ==0xff) && Rx_crc==crc) //判断设备地址是否正确,预留在不知道地址的时候,使用虚拟地址0xff,防止忘记设备地址后,用虚拟地址可以修改 { switch(Rxbuff[1]) { case 0x01: //操作ID if(Rxbuff[2]==0x00) //读 Read(MCU_Rx_buff,ID_Flash_Add); else if(Rxbuff[2]==0x01) //写 Write(Rxbuff,len,ID_Flash_Add); break; case 0x02: //操作名称 if(Rxbuff[2]==0x00) //读 Read(MCU_Rx_buff,Name_Flash_Add); else if(Rxbuff[2]==0x01) //写 Write(Rxbuff,len,Name_Flash_Add); break; case 0x03: //操作环节 if(Rxbuff[2]==0x00) //读 Read(MCU_Rx_buff,Link_Flash_Add); else if(Rxbuff[2]==0x01) //写 Write(Rxbuff,len,Link_Flash_Add); break; case 0x04: //操作型号 if(Rxbuff[2]==0x00) //读 Read(MCU_Rx_buff,Model_Flash_Add); else if(Rxbuff[2]==0x01) //写 Write(Rxbuff,len,Model_Flash_Add); break; case 0x05: //操作品牌 if(Rxbuff[2]==0x00) //读 Read(MCU_Rx_buff,Brand_Flash_Add); else if(Rxbuff[2]==0x01) //写 Write(Rxbuff,len,Brand_Flash_Add); break; case 0x06: //操作行数 if(Rxbuff[2]==0x00) //读 Read(MCU_Rx_buff,Linage_Flash_Add); else if(Rxbuff[2]==0x01) //写 Write(Rxbuff,len,Linage_Flash_Add); break; case 0x07: //操作幅宽 if(Rxbuff[2]==0x00) //读 Read(MCU_Rx_buff,Wite_Flash_Add); else if(Rxbuff[2]==0x01) //写 Write(Rxbuff,len,Wite_Flash_Add); break; case 0x08: //操作高度 if(Rxbuff[2]==0x00) //读 Read(MCU_Rx_buff,Hight_Flash_Add); else if(Rxbuff[2]==0x01) //写 Write(Rxbuff,len,Hight_Flash_Add); break; case 0x09: //操作马力 if(Rxbuff[2]==0x00) //读 Read(MCU_Rx_buff,Soup_Flash_Add); else if(Rxbuff[2]==0x01) //写 Write(Rxbuff,len,Soup_Flash_Add); break; case 0x0a: //操作合作社ID if(Rxbuff[2]==0x00) //读 Read(MCU_Rx_buff,Artel_Flash_Add); else if(Rxbuff[2]==0x01) //写 Write(Rxbuff,len,Artel_Flash_Add); break; case 0x21: //修改波特率 if(Rxbuff[2]==0x00) //读 { Get_Boud_num(); } else if(Rxbuff[2]==0x01) //写 { Boud_Set(Rxbuff); HAL_UART_Transmit(&huart1,Rxbuff,len,0x1000); } break; case 0x22: //操作设备地址 if(Rxbuff[2]==0x00) //读 { Read_Robot[0] = Get_Robot_Num(); HAL_UART_Transmit(&huart1,Read_Robot,1,0x1000); } else if(Rxbuff[2]==0x01) //写 { Robot_add=Rxbuff[5]; Robot_Num_Init(Robot_add); HAL_UART_Transmit(&huart1,Rxbuff,len,0x1000); }
上一篇:STM32 HAL库关于串口中断烧录程序后可以正常运行
下一篇:STM32 实现内部Flash的读写(HAL库版)
推荐阅读最新更新时间:2026-03-24 16:28
- 支持 BLE 连接、由 4mA 至 20mA 电流回路供电的现场发送器参考设计
- AM2DM-0515DH60-NZ ±15 Vout、2W 双路输出 DC-DC 转换器的典型应用
- LTC6261IDC 音频耳机桥式驱动器运算放大器的典型应用
- LTC1775CS 2.5V/5A 可调输出降压稳压器的典型应用电路
- AD8601ARTZ-REEL7 符合 PC100 标准的线路输出放大器的典型应用
- 一种基于分立的 315MHz 振荡器解决方案,用于使用 BFR182 射频双极晶体管的远程无钥匙进入系统
- 使用 ROHM Semiconductor 的 BD49E39G-TR 的参考设计
- AM30EW-2405SZ 5V 三路输出 DC/DC 转换器的典型应用
- LTC3564 的电池在 1.2A 应用中达到 1.2V
- AL1676EV2,基于 AP1676 高亮度降压 LED 驱动控制器的评估板
- GNU Freestanding(Naked)C ARM交叉开发环境创建与测试
- 至晟微电子发布了新一代5G微基站氮化镓PA
- realme新机入网:搭骁龙888处理器,外观类似GT Neo2
- OPPO Find X5 Lite新机解密,为Reno7 5G国际改名版
- 新时间、新地点—慕尼黑上海电子生产设备展7月全新跨越,精彩起航!
- 电池堆栈监控器方案延长电动汽车锂电池寿命
- 3561电池测试仪的功能特点及应用优势分析
- 现代电动汽车车载充电器的高效散热管理设计
- 东芝的新款150V N沟道功率MOSFET具有业界领先的低导通电阻和改进的反向恢复特性
- 共模半导体推出超低噪声、超高PSRR线性稳压电源GM1205



stm32驱动屏IC rm68042
STM32 PMSM FOC 简介
基于STM32G031的测试测量训练平台完成虚拟仪器实现
现代雷达系统的信号设计
BFR340T






京公网安备 11010802033920号