STM32移植modbus通讯协议简明教程

 目录

一、本文讨论内容

二、工具与源码

三、Modbus概述

四、Modbus-RTU通讯协议

五、完成Modbus输入输出代码

六、完成Modbus逻辑功能

七、测试与验证


一、本文讨论内容

       本文简明概要的介绍Modbus通讯协议,并在STM32上实现Modbus协议,通过与Modbus Poll(一种Modbus上位机工具)联合调试以验证程序的正确性。

        本文B站有视频讲解!均为作者原创。up主名字:“芯心智库”。

        视频链接:芯心智库的个人空间_哔哩哔哩_bilibili

二、工具与源码

        工具与源码下载方式:微信公众号关注“芯心智库”,回复“modbus”即可获取。

三、Modbus概述

       Modbus是主从方式通信,一个总线上只有一个主机,但可以有多个从机(这一点类似于IIC的通讯方式)。简单来说,也就是主机问从机答。问啥呢?主要问两个问题--从机的寄存器(线圈)的数值是多少、主机要求从机修改一下寄存器(线圈)的数值并回答。

       Modbus还可以细分很多种协议,但是主要就是四种:

1、Modbus-RTU(设备必须要有RTU协议!这是Modbus协议上规定的,且默认模式必须是RTU)

2、Modbus-ASCII(人类可读的,冗长的表示方式)

3、Modbus-TCP(以太网作为介质进行传输)

4、Modbus-PLUS(高速现场总线网络)

        其实从本质来讲,这四个都是差不多的,你只要掌握一种,其余三种都可以轻而易举地掌握。本文就讲解Modbus-RTU协议,这个是最常使用的协议。

四、Modbus-RTU通讯协议

       结合前面所讲,再来理解一下Modbus通讯协议,我们可以把通讯过程理解为主机叫哪个从机,做什么事情,怎么做,最后主机检查自己描述的对不对。一共四个步骤,也就是每次通讯都需要包含这四个步骤,每一次通讯都需要发送一个帧结构。所以就有 帧结构 = 地址 + 功能码 + 数据 + CRC校验。地址就是相当于哪个从机,功能码就是要干的事情,数据就是要具体怎么做,最后来个CRC校验确保数据是对的。值得注意的是地址: 地址的有效范围是1-247,其他有特殊用途,比如255是广播地址(广播地址就是应答所有地址,正常的需要两个设备的地址一样才能进行查询和回复),而且RTU没有帧头和帧尾,所以协议里明确两帧之间要大于3.5个字节时间间隔,作为一帧结束的判断依据

       功能码有很多,但是最主要用到的是03,06,16,而且软件Modbus Poll也主要是使用这几个功能码,掌握这三个功能码,其余码的使用也是大同小异。

       接着我们理解一下这三个功能码的区别:功能码03是查询寄存器,功能码06修改单个寄存器,功能码16是修改连续的多个寄存器。

       下面直接实战理解一下。

       功能码03实战:

       主机发送: 01 03 00 00 00 01 84 0A

        从机回复: 01 03 02 01 02 35 15

解析:

/*主机发送解析*/

01-地址

03-功能码,代表查询功能,其他功能后面再说

00 00-代表查询的起始寄存器地址.说明从0x0000开始查询.

(这里需要说明以下,Modbus把数据存放在寄存器中,通过查询寄存器来得到不同变量的值,一个寄存器地址对应2字节数据;)

00 01-代表查询了一个寄存器.结合前面的00 00,意思就是查询从0开始的1个寄存器值;

84 0A-循环冗余校验,是modbus的校验公式,从首个字节开始到84前面为止;

(这里新手可能不懂,这个校验就是保证数据传输过程没有错误的一种手段,不同的协议这种校验公式不一样,只需了解这个就足够了,具体怎么求的,可以直接在输出数据得到结果,地址为:http://www.ip33.com/crc.html)

/*从机回复解析*/

01-地址

03-功能码

02-代表后面数据的字节数,因为上面说到,一个寄存器有2个字节,所以后面的字节数肯定是2*查询的寄存器个数;

01 02-寄存器的值是0x0102,结合发送的数据看出,01这个寄存器的值为0x0102

35 15-循环冗余校验

      

       功能码06实战:

       主机发送: 01 06 00 00 12 34 84 BD

        从机回复: 01 06 00 00 12 34 84 BD

解析:

/* 主机发送解析 */

01-主机要查的地址

06-功能码,代表修改单个寄存器功能

00 00-代表修改的起始寄存器地址.说明从0x0000开始.

12 34-代表修改的值为0x12 34.结合前面的00 00,意思就是修改0号寄存器值为0x1234;

84 BD -循环冗余校验,是Modbus的校验公式,从首个字节开始到84前面为止;



/*从机回复解析*/

01-从机返回的地址,说明这就是主机查的从机

06-功能码,代表修改单个寄存器功能;

00 00-代表修改的起始寄存器地址.说明是0x0000.

12 34-代表修改的值为0x1234.结合前面的00 00,意思就是修改0号寄存器值为0x1234;

84 BD -循环冗余校验,是Modbus的校验公式,从首个字节开始到84前面为止;

        ③功能码16实战:

        主机发送: 01 10 00 00 00 02 04 00 11 22 33 FB 1F

        从机回复: 01 10 00 00 00 02 41 C8

解析:

/*主机发送解析*/

01-主机要查的地址

10-功能码,0x10=16D代表修改多个寄存器功能;

00 00-代表修改的起始寄存器地址.说明从0x0000开始.

00 02-代表修改的寄存器数量,这里开始于0x06的修改不同;

04 -表示修改的总字节数,由于修改了2个寄存器,所以数据要有4个字节;

00 11-表示修改的值,结合上面,就是从第0000寄存器开始修改第一个寄存器值为0x0011,就是把0000寄存器改为0x0011;

22 33-表示修改的值,结合上面,就是从第0000寄存器开始修改第二个寄存器值为0x22 33,就是把0001寄存器改为0x2233;

FB 1F -循环冗余校验,是Modbus的校验公式,从首个字节开始到22前面为止;



/*从机回复解析*/

01-从机返回的地址,说明这就是主机查的从机

10-功能码

00 00-代表修改的起始寄存器地址.说明是0x0000.

00 02-代表修改的寄存器数量,只需要回复这么多久足够了,从机告诉主机,你修改了哪几个寄存器就足够了;

41 C8-循环冗余校验;

五、完成Modbus输入输出代码

        我们使用正点原子的战舰开发板,程序的模板基于正点原子的“实验8 定时器中断实验(HAL库)”进行开发,以串口(USART1)作为介质与上位机Modbus Poll通讯。

        先说一下输出部分的程序,这个就最简单的,直接调用HAL库的函数就可以了。代码如下:

/* 发送数据函数,buff为发送内容,len表示发送字节数 */

void modbus_send_data(u8 *buff,u8 len)

{

    HAL_UART_Transmit(&UART1_Handler,(uint8_t*)buff,len,1000); //发送数据

    while(__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_TC)!=SET);//等待发送结束

}

        然后输入部分,不知道读者记不得前文说的“两帧之间要大于3.5个字节时间间隔,作为一帧结束的判断依据”这句话,那么字节时间怎么计算呢?如果波特率为9600,代表1秒可以传送9600 bits的数据,以业内常用的格式是8位数据,无校验位,1位停止位,加上一个必须的1 bit的起始位,那么一字节的串口数据一共是10位。所以每个字节时间为1/(9600/10)秒,也就是1.04ms。两帧之间要大于3.5个字节时间间隔,那么间隔时间设置为4ms即可。

        在程序中,我们定义一个变量modbus_time作为间隔时间的标志位,把modbus_time放入定时器中断服务函数(周期:1ms)中,让其一直增加数值,在串口中断函数中只要收到1Byte消息便会把modbus_time清零,当modbus_time大于4(字节间隔了4ms)且串口曾收到数据但没有接收到新的字节便认为一个帧结构数据接收完成。

        举个栗子,有01 02 03数据要发送过来,当数据01发送过来时,串口中断清零modbus_time,此时modbus_time=0,然后过了1.04秒后,数据02发了过来,此时modbus_time=1,但是串口中断清零modbus_time,此时modbus_time又变成0,然后过了1.04秒后,数据03发了过来,此时modbus_time=1,但是串口中断清零modbus_time,此时modbus_time又变成0,最后没有数据再发送过来了,此时modbus_time大于4(字节间隔了4ms)且串口曾收到数据但没有接收到新的字节便认为一个帧结构数据接收完成。

        此外我们需要修改串口中断服务函数,把接收状态标记USART_RX_STA的接收完成标志bit15相关功能屏蔽(因为正点原子的原本例程是串口收到0x0d 与 0x0a表示收到完整的串口数据),然后将接收状态标记USART_RX_STA的接收完成标志bit15写在定时器中断函数中作为Modbus接收完成标志位。代码如下

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{

       if(huart->Instance==USART1)//如果是串口1

       {

              if((USART_RX_STA&0x8000)==0)//接收未完成

              {

//                  if(USART_RX_STA&0x4000)//接收到了0x0d

//                  {

//                         if(aRxBuffer[0]!=0x0a)USART_RX_STA=0;//接收错误,重新开始

//                         else USART_RX_STA|=0x8000;    //接收完成了

//                  }

//                  else //还没收到0X0D

//                  {     

//                         if(aRxBuffer[0]==0x0d)USART_RX_STA|=0x4000;

//                         else

//                         {

                                   USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ;

                                   USART_RX_STA++;

                             modbus_time = 0;

                                   if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收   

//                         }            

//                  }

              }



       }

}
//回调函数,定时器中断服务函数调用

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

    if(htim==(&TIM3_Handler))

    {

        modbus_time++;

                      if((modbus_time>4) &&((modbus_time & 0x3fff)!=0))

                      {

                             USART_RX_STA|=0x8000;

                      }

    }

}

六、完成Modbus逻辑功能

        这一部分考验C语言的功底,只要清楚Modbus-RTU协议并且C语言功底扎实,相信读者自己也可以办到。详细部分看笔者的源码实现。

七、测试与验证

        打开上位机Modbus Poll,然后按下图设置便将上位机连接到板卡。

        连接成功后,读者会发现10个寄存器的值会发生改变。这十个数值是程序初设设定的寄存器数值。如下图。

        然后我们双击上图数值,便可进入快捷修改寄存器数值界面。然后便可以对功能码06和功能码16进行测试,测试结果如下:

        另外点击右侧的“TC”可以自定义写入数据,我们将教程的数据写入测试可以得到下图结果。而且点击类似查找的按钮可以查看当前发送消息和接收消息内容(可以结合快捷修改寄存器数值界面使用)。

  • 37
    点赞
  • 287
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 26
    评论
### 回答1: STM32是一种广泛应用于嵌入式系统开发的微控制器,而MODBUS是一种串行通信协议,广泛应用于工业自动化领域。下面将介绍如何在STM32上成功移植MODBUS。 首先,我们需要准备相应的硬件和软件资源。硬件方面,我们需要一款STM32开发板,例如STM32F4系列、STM32F7系列等。同时,我们还需要一台PC机,用于开发和调试。软件方面,我们需要安装Keil MDK集成开发环境,并准备好对应的STM32 HAL库和MODBUS协议库。 接下来,我们需要编写相关的代码进行移植。首先,我们需要在Keil MDK中创建一个新的项目,并选择对应的STM32型号。然后,我们需要在项目中添加STM32 HAL库和MODBUS协议库的相关文件。 在编写代码的过程中,我们需要了解MODBUS协议的基本原理和通信规则。MODBUS协议分为RTU和ASCII两种通信格式,我们可以根据实际需求选择合适的方式。我们需要编写相应的函数来完成MODBUS的数据读写、错误处理等功能。 移植MODBUS还需要配置串口通信参数,例如波特率、数据位、校验位等。我们可以使用STM32的UART模块来实现串口通信,并配置对应的寄存器。 在完成代码编写后,我们需要进行编译、连接和下载等步骤,将代码烧录到STM32开发板中。然后,我们可以使用PC机上的MODBUS客户端软件进行测试。 在测试过程中,我们可以通过读写寄存器、读取输入寄存器等功能进行数据交互。如果出现问题,我们可以通过调试工具和日志查找错误原因,并进行相应的修复和优化。 总的来说,STM32移植MODBUS需要了解MODBUS协议的原理和使用方式,以及熟悉STM32的开发环境和相关库函数。在编码和调试过程中,需要耐心和细心地进行,以确保代码的正确性和可靠性。移植成功后,我们可以在工业自动化领域中广泛应用MODBUS通信。 ### 回答2: STM32是一种高性能32位微控制器系列,有着广泛的应用领域。而Modbus是一种通信协议,常用于工业自动化领域。移植Modbus协议到STM32上,可以实现与其他Modbus设备之间的通信。 首先,需要在STM32上选择一个适合的串口作为通信接口。然后,在STM32的开发环境中,创建一个工程并添加Modbus通信相关的库文件。 接下来,需要根据具体需求配置STM32的串口参数,例如波特率、数据位、校验位和停止位等。根据Modbus协议规范,还需要设置一个从站地址,用于识别STM32Modbus网络中的身份。 在代码编写方面,可以使用库函数或者原生的寄存器操作进行开发。首先,需要初始化串口配置和Modbus相关参数。然后,使用Modbus协议规定的函数进行读写操作,例如读取寄存器或写入寄存器的数值。 在通信过程中,需要注意Modbus协议的报文格式。例如,读取寄存器时需要构建读取请求报文,并通过串口发送到目标设备。然后,接收目标设备返回的响应报文,并解析其中的数据。 最后,进行测试和调试。可以通过与其他Modbus设备进行通信,验证STM32是否能够正常收发数据。如果出现问题,可以利用调试工具进行故障排查,例如使用串口调试助手查看串口发送和接收的数据。 总之,移植Modbus协议到STM32上需要进行串口配置、Modbus参数设置、代码编写和功能测试等步骤。随着不断的开发和调试,最终可以实现STM32与其他Modbus设备之间的可靠通信。 ### 回答3: 要在STM32移植Modbus协议,需要进行以下步骤: 1. 确定Modbus协议类型:根据实际需求确定使用的Modbus协议类型,包括Modbus RTU、Modbus ASCII或Modbus TCP/IP等。 2. 引入相关库文件:从官方网站或第三方提供的源码库中下载与所选协议类型兼容的Modbus协议库文件,如Modbus Slave Library等。 3. 配置串口或网络接口:根据所选协议类型的不同,配置相应的串口或网络接口,如使用Modbus RTU协议,需要配置UART通信;使用Modbus TCP/IP协议,则需要配置以太网接口。 4. 初始化Modbus库:根据所选协议类型的库文件提供的接口,进行Modbus库的初始化设置,包括波特率、数据位、校验位等参数的配置。 5. 注册Modbus功能码:根据项目需求,注册相关的Modbus功能码,包括读取寄存器、写入寄存器、读取线圈状态等,以便后续进行数据交互操作。 6. 处理Modbus请求和响应:在主循环中不断监听来自Modbus主机(如上位机或PLC)的请求,并根据请求的功能码执行相应的操作,如读取或写入寄存器值。 7. 构建Modbus响应:根据请求的功能码和相关参数,构建相应的Modbus响应,并发送给Modbus主机,确保数据的正确传输和处理。 8. 完善错误处理和容错机制:在移植过程中,要注意处理错误情况,如通信超时、校验错误等,确保系统具备一定的容错能力。 9. 调试和验证:完成移植后,进行系统测试和验证,检查Modbus协议的功能是否正常,并进行必要的调试和修复工作。 总之,移植Modbus协议到STM32芯片需要进行协议类型选择、库文件引入、接口配置、功能码注册、请求响应处理等一系列操作。在完成移植后,需要进行测试和验证,确保协议的正常运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芯心智库

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值