本文笔者最近的项目是设计一款运动控制器,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博客https://blog.csdn.net/ASWaterbenben/article/details/97685006
基于STM32CubeMX移植freeModbusRTU(从站)_embregcoilscb_ASWaterbenben的博客-CSDN博客https://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,为笔者运动控制器项目中的一环,关于运动控制器的设计可参考本博客。文章来源:https://www.toymoban.com/news/detail-755373.html
基于STM32F429 + ECM-XFU搭建运动控制平台,实现EtherCAT通讯_河狸打捞员的博客-CSDN博客https://blog.csdn.net/weixin_48501028/article/details/132272572?spm=1001.2014.3001.5501笔者刚接触数控,相关知识欠缺,如有错误还请指正,欢迎一同交流进步!!!文章来源地址https://www.toymoban.com/news/detail-755373.html
到了这里,关于运动控制器设计——基于FreeModbus在STM32F4平台实现ModbusTCP和ModbusRTU的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!