> 文档中心 > STM32 Modbus通信学习笔记—— 代码及示例

STM32 Modbus通信学习笔记—— 代码及示例

文章目录

  • 前言
  • 从机帧格式
    • 举个栗子:
  • STM32 Modbus_RTU与维控屏通信
    • STM32代码
      • 1.定时器
      • 2串口收发
      • 3.数据包处理
  • 维控屏代码
  • 总结
  • 合集

前言

前面已经介绍了Modbus的通信流程以及主机的数据帧,此篇主要结合STM32的代码来进一步介绍从机端的帧格式以及整个通信过程。

从机帧格式

从机格式与上一篇的主机格式类似,从机会根据主机的命令和功能码返回对应信息,这里从机返回的地址、功能码是和主机发送的数据一致,数据段则是根据主机访问的范围而定。
在这里插入图片描述
RTU格式从机返回的帧为地址、功能码、总字节数、数据段、CRC校验码。
ASCLL的格式类似,在此不做赘述。

举个栗子:

这里以读取数据也就是功能码是03为例,其余功能码也是大同小异,想了解的可以私聊笔者获取代码。
在这里插入图片描述
如上图所示:主机发送的数据包为“04 03 00 00 00 09 85 99”
04是从设备地址;03是功能码,对应的功能是读取16位寄存器的值;
00 00 是起始寄存器位置,00 09是访问的个数。
85 99 是CRC校验码。
在这里插入图片描述
当从机4接收到这个指令后,就会解析出命令,并返回数据包:
“04 03 12 00 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 31 16 ”
04:从机地址;03功能码;12:字节数;00 00-----00 08是数据段,分别对应九个16位寄存器的高低八位。
31 16是CRC校验码。
STM32 Modbus通信学习笔记—— 代码及示例
在这里插入图片描述
查看代码中寄存器值得定义,可以发现与返回值一致。

STM32 Modbus_RTU与维控屏通信

了解完整个代码的主从帧和通信模式,接下来来试试应用;本示例以STM32和PLC常用的维控屏进行通信,主要实现
1.屏幕控制控件LED;
在这里插入图片描述
2.屏幕监控STM32LED灯状态;
在这里插入图片描述
3.屏幕监控按键的按下,并记录日志;
在这里插入图片描述
4.屏幕实时显示数字变量。

STM32代码

1.定时器

由于使用的是RTU的通信帧,在上一篇的介绍中可以知道RTU格式没有固定的包头和包尾,是通过3.5个字符的时间来作为包尾的,所以在为了实现正常通信,需要设置一个能够计时毫秒的定时器,根据然后根据自己的波特率进行计算,算出所需要的延时时间。例如使用9600时,就需要定时大于4ms时间,为了保证通信正常往往会留有余量,如下图就是使用的8ms来作为标志。
在这里插入图片描述

2串口收发

在完成定时器的初始化后,还需要能够保证串口的正常收发,笔者这里用的是STM32最小系统,自带CH340,维控屏也是使用的的电脑进行仿真,所以不需要针对类似485这样的硬件电路来对代码进行调整,只需要正常初始化串口就行。整体的代码框架如下:

// An highlighted block/******************************************************************************* 函数名:main* 描述:主函数* 参数:无* 返回:无* 编写者:* 编写日期:*******************************************************************************/int main(void){SystemInit();delay_init(72);CLI();    //关总中断NVIC_Configuration();General_Gpio_Init();//通用GPIO口初始化GeneralIOStructInit();   //初始化IO口结构体变量Usart1_Init(115200);//串口1初始化SEI();    //开总中断IWDG_Init(4,6250); user_printf(USART1,"初始化完毕\r\n");delay_ms(1000);delay_ms(1000);while(1){com1_rtu_slave();//modbus处理函数AllModuleProDeal(); //所有运行代码General_Gpio_Update();//通用GPIO口状态更新heartbeat(); //心跳检测IWDG_Feed();//喂狗}}

3.数据包处理

modbus从机的处理函数如下(注意此代码是灵育教育的modbus处理并非笔者上述工程所示的处理函数,但是总体思路一致,这里给大家作参考):

// An highlighted blockvoid Mosbus_Event(){u16 crc;u16 rccrc;  if(modbus.reflag==0)  //没有收到MODbus的数据包{  return ;}crc= crc16(&modbus.rcbuf[0], modbus.recount-2);//计算校验码  rccrc=modbus.rcbuf[modbus.recount-2]*256 + modbus.rcbuf[modbus.recount-1];  //收到的校验码  if(crc ==  rccrc)  //数据包符号CRC校验规则{   if(modbus.rcbuf[0] == modbus.myadd)  //确认数据包是否是发给本设备的 {  switch(modbus.rcbuf[1])  //分析功能码{  case 0:     break;  case 1:     break;    case 2:     break;    case 3:     Modbud_fun3();    break;   //3号功能码处理    case 4:     break;    case 5:     break;    case 6:     Modbud_fun6();     break;   //6号功能码处理      case 7:     break; //....}}else if(modbus.rcbuf[0] == 0)   //广播地址{}}modbus.recount=0;   //  modbus.reflag=0;}void Modbud_fun3()  //3号功能码处理  ---主机要读取本从机的寄存器{  u16 Regadd;u16 Reglen;u16 byte;u16 i,j;u16 crc;Regadd=modbus.rcbuf[2]*256+modbus.rcbuf[3];  //得到要读取的寄存器的首地址Reglen=modbus.rcbuf[4]*256+modbus.rcbuf[5];  //得到要读取的寄存器的数量i=0;modbus.Sendbuf[i++]=modbus.myadd;//本设备地址  modbus.Sendbuf[i++]=0x03; //功能码        byte=Reglen*2;   //要返回的数据字节数//modbus.Sendbuf[i++]=byte/256;  //modbus.Sendbuf[i++]=byte%256;for(j=0;j<Reglen;j++){  modbus.Sendbuf[i++]=Reg[Regadd+j]/256;modbus.Sendbuf[i++]=Reg[Regadd+j]%256;}crc=crc16(modbus.Sendbuf,i);modbus.Sendbuf[i++]=crc/256;  //modbus.Sendbuf[i++]=crc%256;RS485_RT_1;  //for(j=0;j<i;j++){ RS485_byte(modbus.Sendbuf[j]);}RS485_RT_0;  //}void Modbud_fun6()  //6号功能码处理{  u16 Regadd;u16 val;u16 i,crc,j;i=0;  Regadd=modbus.rcbuf[2]*256+modbus.rcbuf[3];  //得到要修改的地址 val=modbus.rcbuf[4]*256+modbus.rcbuf[5];     //修改后的值Reg[Regadd]=val;  //修改本设备相应的寄存器//以下为回应主机modbus.Sendbuf[i++]=modbus.myadd;//本设备地址  modbus.Sendbuf[i++]=0x06; //功能码   modbus.Sendbuf[i++]=Regadd/256;modbus.Sendbuf[i++]=Regadd%256;modbus.Sendbuf[i++]=val/256;modbus.Sendbuf[i++]=val%256; crc=crc16(modbus.Sendbuf,i); modbus.Sendbuf[i++]=crc/256;  // modbus.Sendbuf[i++]=crc%256;RS485_RT_1;  //for(j=0;j<i;j++){ RS485_byte(modbus.Sendbuf[j]);}RS485_RT_0;  //}

维控屏代码

维控屏这边就是拖动控件进行布局,然后绑定寄存器地址,根据自己的需求做一些界面即可。
在这里插入图片描述

总结

有关modbus通信的介绍就到此为止,如有不足之处欢迎指出,相关工程也会放到笔者的下载资源,有需要的自行下载。

合集

STM32 Modbus通信学习笔记——理论基础
STM32 Modbus通信学习笔记——通信流程
STM32 Modbus通信学习笔记—— 代码及示例
STM32 使用MODBUS与维控屏通信(modbus系列代码)