运动控制器设计——基于FreeModbus在STM32F4平台实现ModbusTCP和ModbusRTU

本文笔者最近的项目是设计一款运动控制器,MCU使用的是STM32F429,要求是通过Modbus TCP协议实现与示教器通讯,并通过ModbusRTU实现与触摸屏通讯。

本文将介绍在STM32F4上实现 ModbusTCP和ModbusRTU通讯 的过程。笔者才疏学浅,如有错误还请指正。

一、FreeModbus介绍

1.1 FreeModbus的获取

Modbus协议是典型的主-从通讯结构,链路中只能有一台主设备,可以有多台从设备。主设备向从设备发送请求指令,从设备对该指令进行响应。从设备不能主动向主设备发送指令,并且从设备之间也不能进行通信。

FreeModbus是一个开源的Modbus通信协议实现库。可以用于在嵌入式系统中实现Modbus通信协议,支持Modbus RTU、Modbus TCP和ModBus-ASSCII。目前,FreeModbus最新版本是V1.6,可以通过官网下载,链接如下:

FreeMODBUS - A free MODBUS ASCII/RTU and TCP implementation

1.2 FreeModbus文件介绍

解压下载的文件,我们主要关注两个文件夹。一是modbus文件夹(FreeModbus 的协议栈源码),二是demo文件夹(不同平台上移植FreeModbus的案例)

打开ModBus文件夹,里面有五个文件夹和一个C文件,说明如下:

名称说明/描述
ascii这个文件夹包含Modbus-ASCII协议的实现代码
functions这个文件夹主要包括一些功能码对应的处理函数
include里面主要是Modbus协议需要使用的一些头文件和配置文件
rtu这个文件夹包含Modbus-RTU协议的实现代码
tcp这个文件夹包含Modbus-TCP协议的实现代码
mb.c这个是MODBUS协议栈的主文件,这个文件夹只是一个框架,与具体的协议无关。因为Modbus有三种具体的协议,分别为RTU、ASCII和TCP,具体的实现在1、4、5文件夹中,而mb.c在初始化的时候会根据使用情况将指针指向具体的处理函数

在STM32F4平台实现ModbusTCP和ModbusRTU通讯,并不需要ascii这个文件夹,该文件对应ModBus-asscii开发。

1.3 Modbus帧结构

Modbus RTU数据帧由四部分组成,设备地址,功能码,数据和校验。具体介绍见下图。

ModbusTCP的数据帧可分为三部分:报文头(MBAP)+功能代码+数据。相比Modbus RTU数据帧没有校验。各部分分布见下图。

ModbusTCP报文头分为4个域,共7字节,其组成如下:

长度描述
事务源标识符2字节Modbus请求/相应事务处理的识别码
协议标识符2字节0x00:Modbus协议
长度2字节数据长度,单位为字节
单元标识符1字节以太网总线上远程从站的识别码

二、FreeModbus在STM32上的移植

ModbusTCP和ModbusRTU参考博主 ASWaterbenben 在STM32F767的移植案例,博主的介绍很详细,参考博客移植就可以,笔者在这不展开阐述。

基于STM32F767通过STM32CubeMX实现ModbusTCP从站(后续)_str71xtcp_ASWaterbenben的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/ASWaterbenben/article/details/97685006

基于STM32CubeMX移植freeModbusRTU(从站)_embregcoilscb_ASWaterbenben的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/ASWaterbenben/article/details/105549750?ops_request_misc=&request_id=3fbbd9c11cc9443e9ee54cd4256b04d0&biz_id=&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~koosearch~default-5-105549750-null-null.268^v1^control&utm_term=Modbus&spm=1018.2226.3001.4450

三、Modbus TCP的使用方式

3.1 Modbus TCP的工作流程

在Modbus TCP初始化和使能之后,在程序主循环任务中调用调用 eMBPoll() 进行轮询,当获取Modbus TCP事件后(即 xMBPortEventGet( &eEvent ) == TRUE ),根据接收到的功能码对应启动 xFuncHandlers.pxHandler 中相应的功能函数,主要功能码与RTU一样,详见下表:

功能码名称位/字操作操作数量
0x01读线圈状态位操作单个或多个
0x02读离散输入状态位操作单个或多个
0x03读保持寄存器字操作单个或多个
0x04读输入寄存器字操作单个或多个
0x05写线圈状态位操作单个
0x06写单个保持寄存器字操作单个
0x0F写多个线圈位操作多个
0x10写多个保持寄存器字操作多个

表中 涉及到线圈、离散输入、保持、输入四种寄存器,各寄存器介绍如下:

名称介绍操作函数
线圈寄存器可以类比为开关量(继电器状态),每一个bit对应一个信号的开关状态。所以一个byte就可以同时控制8路的信号。比如控制外部8路io的高低。 为可读可写。eMBRegCoilsCB
离散输入寄存器离散输入寄存器就相当于线圈寄存器的只读模式,他也是每个bit表示一个开关量,而他的开关量只能读取输入的开关信号eMBRegDiscreteCB
保持寄存器寄存器单位为两个byte,可以存放具体的数据量,为可读可写。一般对应参数设置eMBRegHoldingCB
 输入寄存器与保持寄存器类似,只支持读而不能写,一般是读取各种实时数据eMBRegInputCB

 在 modbus_CB.c 文件中,有以下的声明,建立了以上四种寄存器,在 eMBRegInputCB eMBRegHoldingCB、 eMBRegCoilsCB eMBRegDiscreteCB 函数中有相关的调用。

uint16_t DB_R[88];		//保持寄存器数值存储空间
uint16_t DB_C[88];		//线圈寄存器数值存储空间
uint16_t DB_I[88];		//输入流数值存储空间
uint16_t DB_D[88];		//离散量数值存储空间

3.2 Modbus TCP测试

第二章节分享的博客中,博主 ASWaterbenben 已经介绍ModbusTool工具的使用过程。笔者在此介绍使用 Matlab 软件进行测试。

将工程编译后下载到开发板,用网线连接开发版和计算机。MATLAB - Modbus TCP客户端中几个关键的函数如下所示:

函数说明
modbus创建MODBUS对象
read从MODBUS服务器读取数据
write对连接的MODBUS服务器执行写操作
writeRead在单个MODBUS事务中对一组保持寄存器执行写然后读操作
maskWrite在保持寄存器上执行掩码写入操作

直接上MATLAB操作代码,方便理解:

mbConnector = modbus('tcpip','127.0.0.1',502);     % 创建modbus连接对象
mbConnector.Timeout = 20;                          % 设置连接超时时间
set(mbConnector,'WordOrder','little-endian');      % 设置为小端模式

% modbus保持寄存器写入数据 
% 参数依次为 (modbus对象、寄存器类型、开始地址、写入数据、数据类型)
% 下列代码表示在保持寄存器的第10个寄存器写入"123",数据类型为int16
write(mbConnector, 'holdingregs', 10, 123, 'int16');
% 下列代码表示在保持寄存器的第20个寄存器依次写入"1 2 3",数据类型为int16
write(mbConnector,'holdingregs',20,[1 2 3],'int16')

% modbus读取保持寄存器数据 
% 参数依次为 (modbus对象、寄存器类型、开始地址、读取数据个数、数据类型)
% 下列代码表示从保持寄存器的第10个寄存器起,读取1个数据,数据类型为int16
data1 = read(mbConnector,'holdingregs',10,1,'int16')
% 下列代码表示从保持寄存器的第20个寄存器起,读取3个数据,数据类型为int16
data2 = read(mbConnector,'holdingregs',20,3,'int16')


% modbus线圈寄存器写入数据
% 下列代码表示从线圈寄存器的第1个寄存器写入1
write(mbConnector, 'coils', 1, 1);

% modbus读取线圈寄存器数据 
% 下列代码表示从线圈寄存器的第1个寄存器起,读取16bit
data3 = read(mbConnector,'coils',1,16)


% modbus读取输入寄存器数据
% 下列代码表示从输入寄存器的第1个寄存器起,读取3个数据,数据类型为int16
data4 = read(mbConnector,'inputregs',1,3,'int16')


% modbus读取离散输入寄存器数据
% 下列代码表示从离散输入寄存器的第1个寄存器起,读取16bit
data5 = read(mbConnector,'input',1,16)


% 断开并清除Modbus连接
clear mbConnector 

四、结语

本文介绍了基于FreeModbus在STM32F4平台实现ModbusTCP,为笔者运动控制器项目中的一环,关于运动控制器的设计可参考本博客。

基于STM32F429 + ECM-XFU搭建运动控制平台,实现EtherCAT通讯_河狸打捞员的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_48501028/article/details/132272572?spm=1001.2014.3001.5501笔者刚接触数控,相关知识欠缺,如有错误还请指正,欢迎一同交流进步!!!

  • 6
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

河狸打捞员

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

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

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

打赏作者

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

抵扣说明:

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

余额充值