云社区 博客 博客详情
云社区 博客 博客详情

LIteOS的RS485通讯--Freemodbus协议及RTU移植重点

o0龙龙0o 发表于 2020-12-02 10:56:55 12-02 10:56
o0龙龙0o 发表于 2020-12-02 10:56:55 2020-12-02
0
0

【摘要】 modbus是工业网络通讯常用协议,freemodbus在开源协议是用的比较广泛,本文主要介绍freemodbus是什么,及如何进行移植,LIteOS尚未对modbus有官方支持,有兴趣的可以直接把这个加载上去

​Freemodbus


        FreeMODBUS 是针对通用的Modbus协议栈在嵌入式系统中应用的一个实现。Modbus协议是一个在工业制造领域中得到广泛应用的一个网络协议。一个Modbus通信协议栈包括两层:定义了数据结构和功能Modbus应用协议和网络层。在FreeMODBUS的当前版本中,提供了RTU/ASCII传输模式。也支持在TCP传输。Freemodbus遵循BSD,这意味着本协议栈的实现代码可以应用于商业用途。目前版本的FreeModbus支持如下的功能码:

  • 读输入寄存器 (0x04)

  • 读保持寄存器 (0x03)

  • 写单个寄存器 (0x06)

  • 写多个寄存器 (0x10)

  • 读/写多个寄存器 (0x17)

  • 读取线圈状态 (0x01)

  • 写单个线圈 (0x05)

  • 写多个线圈 (0x0F)

  • 读输入状态 (0x02)

  • 报告从机标识 (0x11)

        接收和传输Modbus RTU/ASCII数据帧是通过一个由硬件提取层的调用来驱动状态机来实现的。这就使得该协议非常容易移植到其他的平台之上。当收到一个完整的数据帧后,该数据帧被传入Modbus应用层,数据帧的内容在该层得到解析。为例方便增加新的Modbus功能,Freemodbus在应用层通提供了Hooks。
        如果用到了Modbus TCP协议,那么当准备处理一个新数据帧的时候,移植层就必须首先向协议栈发送一个事件标志。然后,协议栈调用一个返回值为接收到的Modbus TCP数据帧的函数,并且开始处理这个数据帧。如果数据有效,则相应的Modbus反馈帧将提供给移植层生成反馈帧。最后,该反馈被发送到客户端。

硬件需求


最小的硬件需求:

  • 大约5-10Kbyte的flash和300byte的RAM资源

  • 一个支持中断的异步串行通讯接口

  • 一个精度大约750微妙的定时器

有无操作系统都可以进行操作。如果有RTOS,则可以使用事件队列来避免在MODBUS任务中忙于等待。对于在没有RTOS的情况下运行的系统,可以使用结合全局变量的基于轮询的方法。
实际的内存要求取决于所使用的模块。下表显示了所需的内存以及已编译的所有可支持选择的函数。


MODULE

ARM CODE

ARM RAM (STATIC)

AVR CODE

AVR RAM (STATIC)

Modbus RTU (Required)

1132Byte

272Byte

1456Byte

266Byte

Modbus ASCII (Optional)

1612Byte

28Byte

1222Byte

16Byte

Modbus Functions [1]

1180Byte

34Byte

1602Byte

34Byte

Modbus Core (Required)

924Byte

180Byte

608Byte

75Byte

Porting Layer (Required [2])

1756Byte

16Byte

704Byte

7Byte

Totals

7304Byte

530Byte

5592Byte

398Byte

支持的设备类型


官方已经支持的设备类型包括:(官方都已经对这些支持提供了移植参考)

Cortex M3 ARM、AVR 、Coldfire 、MSP430 、Z8Encore 、Win32、Linux。

功能配置


通过配置文件mbconfig.h来配置freemodbus的功能,也可对其进行剪裁

Defines#define MB_ASCII_ENABLED   ( 1 )          开启ASCII模式#define MB_RTU_ENABLED   ( 1 )            开启RTU模式#define MB_TCP_ENABLED   ( 0 )            开启TCP模式#define MB_ASCII_TIMEOUT_SEC   ( 1 )        ASCII模式超时时间#define MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS   ( 0 )ASCII启动等待时间#define MB_FUNC_HANDLERS_MAX   ( 16 )        开启的最大功能数量#define MB_FUNC_OTHER_REP_SLAVEID_BUF   ( 32 )    从站ID字节数#define MB_FUNC_OTHER_REP_SLAVEID_ENABLED   ( 1 )  开启报告从站ID#define MB_FUNC_READ_INPUT_ENABLED   ( 1 )      开启读输入功能#define MB_FUNC_READ_HOLDING_ENABLED   ( 1 )    开启读寄存器功能#define MB_FUNC_WRITE_HOLDING_ENABLED   ( 1 )    开启写寄存器功能#define MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED   ( 1 )开启连续写寄存器功能#define MB_FUNC_READ_COILS_ENABLED   ( 1 )      开启读线圈功能#define MB_FUNC_WRITE_COIL_ENABLED   ( 1 )      开启写线圈功能#define MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED   ( 1 )开启开启写连续线圈功能#define MB_FUNC_READ_DISCRETE_INPUTS_ENABLED   ( 1 )开启读离线线圈功能#define MB_FUNC_READWRITE_HOLDING_ENABLED   ( 1 )  开启读写寄存器功能

移植的重点


        移植主要是对接口文件的修改,及Port文件夹中的四个文件portserial.c、porttimer.c、port.h三个文件,里面有串口的驱动的映射、定时器驱动的映射、及对中断的处理映射。


在port.h文件中,我们需要定义中断使能和中断去使能的宏,来freemodbus可以调用实现开关全局中断进入临界区功能。

如在ARM-Cortex,我们可以利用CMSIS函数实现中断的开关,

#define ENTER_CRITICAL_SECTION()    __set_PRIMASK(1) 关全局中断#define EXIT_CRITICAL_SECTION()     __set_PRIMASK(0) 开全局中断

将这两个宏进行补全实现了freemodbus进入临界区的功能。


在portserial.c文件中,我们要实现将串口或RS485(UART)映射到Freemodbus的串口上,这里每个芯片或构架因为串口驱动各不相同,就需要参考自己的串口驱动进行配置,本文以STM32 HAL库驱动进行讲解说明。

首先串口使能开关控制的功能函数的映射,在这里Freemodbus来控制串口开关

void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ){    if (xRxEnable)  //接收使能  {  __HAL_UART_ENABLE_IT(&husartx_rs485,UART_IT_RXNE);    }  else  {  __HAL_UART_DISABLE_IT(&husartx_rs485,UART_IT_RXNE);  }  if (xTxEnable)  //发送使能  {  __HAL_UART_ENABLE_IT(&husartx_rs485,UART_IT_TXE);  }  else  {  __HAL_UART_DISABLE_IT(&husartx_rs485,UART_IT_TXE);  }}

然后在下面两个函数实现freemodbus的发送和接收,这两个函数同样需要映射到串口的发送接收上


BOOL xMBPortSerialPutByte( CHAR ucByte )  //freemodbus发送{  if(HAL_UART_Transmit(&husartx_rs485 ,(uint8_t *)&ucByte,1,0x01) != HAL_OK )  return FALSE ;  else  return TRUE;}BOOL xMBPortSerialGetByte( CHAR * pucByte )  //freemodbus接收{    if(HAL_UART_Receive (&husartx_rs485 ,(uint8_t *)pucByte,1,0x01) != HAL_OK )  return FALSE ;  else  return TRUE;}

porttimer.c文件中,Modbus协议栈需要一个计时器来检测帧结束,计时器的分辨率应为串行字符时间的一半。我们通常使用硬件定时器或是软件定时实现该功能,如果是带操作系统的工程,则可以利用


BOOL xMBPortTimersInit( USHORT usTim1Timerout50us )  映射定时初始化驱动


inline void vMBPortTimersEnable(  )  映射定时器开使能驱动
inline void vMBPortTimersDisable(  )  映射定时器关使能驱动



总结


        freemodbus自己可以按照队列操作进行运行,开发者只需要配合自己的开发板的串口和定时器的驱动进行驱动PORT映射开发,就可以实现自己的modbus RTU的从站操作,利用freemodbus可以大大减低自己编写modbus RTU 出现代码冗余和漏洞的可能,只要简单配置就可以让自己的modbus协议跑起来。

如有相关问题请关注个人公众号;ashysage

登录后可下载附件,请登录或者注册

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:huaweicloud.bbs@huawei.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
评论文章 //点赞 收藏 0
点赞
分享文章到微博
分享文章到朋友圈

评论 (0)


0/1000
评论

登录后可评论,请 登录注册

评论

您没有权限执行当前操作

温馨提示

您确认删除评论吗?

确定
取消
温馨提示

您确认删除评论吗?

删除操作无法恢复,请谨慎操作。

确定
取消
温馨提示

您确认删除博客吗?

确定
取消

确认删除

您确认删除博客吗?

确认删除

您确认删除评论吗?

温馨提示

登录超时或用户已下线,请重新登录!!!

确定
取消