STM32使用HAL库实现ModBus RTU从机通讯

实验目的:使用HAL库实现ModBus RTU从机通讯
实验芯片:STM32F407
实验平台:STM32Cube IDE
1、ModBus RTU通讯介绍
网上类似的介绍很多,我只以我所需要的了解情况进行介绍,主要目的是为了快速上手,实现仪器通讯。
ModBus RTU只是一种特定的通讯方式,对于STM32来说就是通过串口通讯,以该协议进行解码和传数。
而对于ModBus RTU协议来说,我们先从一条简单的报文来开始了解这个协议。

01 06 00 01 00 17 98 04
从机地址 功能号 数据地址 数据 CRC校验

其中数据地址,数据,CRC校验都是两个字节。
这一串数据的意思是:把数据 0x0017(十进制23) 写入到 1号从机地址中的 0x0001数据地址。其中06功能码就代表写入的含义。

  • 报文:就是一帧数据,包含地址、功能号等内容,就像上面的那一串数据。
  • CRC校验:例如上面的 98 04 是它前面的数据(01 06 00 01 00 17)通过一算法计算出来的结果。
  • 功能号:代表不同的功能,在该协议里通常会用到读写寄存器之类的说法。按我自己的理解就是对应于不同的变量,所谓的“线圈”“寄存器”就是“位变量”“16位变量”。
    常用的功能号如下
    01 (0x01) 读线圈
    02 (0x02) 读离散量输入
    03 (0x03) 读保持寄存器
    04(0x04) 读输入寄存器
    05 (0x05) 写单个线圈
    06 (0x06) 写单个寄存器
    15 (0x0F) 写多个线圈
    16 (0x10) 写多个寄存器
    举个栗子吧!
    对于功能号1,我们对从机地址1发送功能号1,读取寄存器地址为0x0000开始的8个寄存器数值
01 01 00 00 00 08 3D CC
从机地址 功能号 寄存器地址 寄存器个数 CRC校验

从机返回,例如:

01 01 02 03 xx xx
从机地址 功能号 数据字节 寄存器值 CRC校验

其中对于功能号中“线圈”来说,它是位的概念,相当于1个字节中每位都代表1个寄存器的值或者状态,由于我刚自己接触该行业,表述有误的地方,欢迎指正!
因此返回也是1个字节

对于功能号3,我们对从机地址1发送功能号3,读取寄存器地址为0x0CBC(十进制就是3260)开始的2个寄存器数值

01 03 0C BC 00 02 06 BF
从机地址 功能号 寄存器地址 寄存器个数 CRC校验

从机返回,例如:

01 03 04 FC 5B 49 76 0D C6
从机地址 功能号 数据字节(寄存器个数*2) 寄存器1值 寄存器2值 CRC校验

对于功能号中“寄存器”来说,它是16位的概念,因此从机返回的数据字节数就是寄存器个数*2个字节。

  • CRC校验算法说明
    对于CRC校验,可以根据用户自己的需求进行修改。目前我使用的是通用常规的计算方法:循环冗余算法。
    循环冗余校验CRC区为2字节,含一个16位二进制数据。由发送设备计算CRC值,并把计算值附在信息中,接收设备在接收信息时,重新计算CRC值,并把计算值与接收的在CRC区中实际值进行比较,若两者不相同,则产生一个错误。
    CRC开始时先把寄存器的16位全部置成“1”,然后把相邻2个8位字节的数据放入当前寄存器中,只有每个字符的8位数据用作产生CRC,起始位,停止位和奇偶校验位不加到CRC中。产生CRC期间,每8位数据与寄存器中值进行异或运算,其结果向右移一位(向LSB方向),并用“0”填入MSB,检测LSB,若LSB为“1”则与预置的固定值异或,若LSB为“0”则不作异或运算。
    重复上述处过程,直至移位8次,完成第8次移位后,下一个8位数据,与该寄存器的当前值异或,在所有信息处理完后,寄存器中的最终值为CRC值。
    产生CRC的过程:
    1. 把16位CRC寄存器置成FFFFH.
    2. 第一个8位数据与CRC寄存器低8位进行异或运算,把结果放入CRC寄存器。
    3. CRC寄存器向右移一位,MSB填零,检查LSB.
    4. (若LSB为0):重复3,再右移一位。
      (若LSB为1):CRC寄存器与A001 H 进行异或运算
    5. 重复3和4直至完成8次移位,完成8位字节的处理。
    6. 重复2至5步,处理下一个8位数据,直至全部字节处理完毕。
    7. CRC寄存器的最终值为CRC值。
    8. 把CRC值放入信息时,高8位和低8位应分开放置。
      大致介绍到这,其他可以根据协议进行细化。
      2、ModBus RTU超时设置
      至少需要 3.5 个字符时间间隔
      STM32使用HAL库实现ModBus RTU从机通讯_第1张图片
      两帧数据之间至少要有3.5个字符,可以根据所设的波特率进行配置。
/* RTU通信需要确定超时时间 */
#if DEBUG_USARTx_BAUDRATE <= 19200
  /* 1.5个字符的超时时间 T = BAUDRATE/11/1000*/
  #define OVERTIME_15CHAR             (((float)DEBUG_USARTx_BAUDRATE/11)*1.5f)
  /* 3个字符的超时时间 */
  #define OVERTIME_35CHAR             (((float)DEBUG_USARTx_BAUDRATE/11)*3.5f)
#else 
  /* 波特率超过19200bit/s的情况下建议的超时时间 */
  #define OVERTIME_15CHAR                750.0f    // 750us 
  #define OVERTIME_35CHAR               1750.0f  // 1.75ms  
  
#endif

你可能感兴趣的:(STM32学习,stm32)