7.RT-thread 项目实战--FreeModbus协议的移植

在工控设备中,modbus协议是应用非常广泛的,所以我们的demo集成modbus,并通过modbus进行参数的设置及存储。

 

一.基于led的工程进行,modbus RTU功能的实现。

1.打开RT-thread settings功能设置,添加freemodbus 软件包,设置为从机模式

我们先使能一下demo,看下是如何实现的,我们再进行相应的优化,完成自己的modbus 从机模式,实现参数的设置。

2.扩展板的232接口使用的是usart6,使能串口6,并将modbus的接口改为6

 

查看一下rtconfig.h配置文件,确保更改成功。

 

3.PC打开modbus POLL

注意上面两点,demo中默认配置是这样的。

通讯成功。

二.Freemodbus协议解析

studio带给了我们很大的便利性,但同样我们关注的少了,理解就不够深入了,在项目级的开发中,简单配置得到的效果肯定是不满足要求的,我们还需要针对这个工程进行优化,例如将串口改为DMA的方式,查询的方式改为中断阻塞触发的方式,提高效率,减少资源占用。

首先我们对freeModbus进行一个简单的了解,其实modbus并不复杂,我们只需要了解它的各个接口部分,知道怎么优化,怎么和其他组件对接,怎么扩展功能就好,一些基础性的介绍,直接网上搜索就好了。

 

1.modbus基础概念

FreeMODBUS是一个奥地利人写的Modbus协议。从机开源,主机模式收费,armink 大神开发了这款支持主机模式的 FreeModbus 协议栈。

支持RTU,ASCII,TCP等模式

https://github.com/RT-Thread-packages/freemodbus

详细可以查看上面地址。

 

2.modbus基本数据格式

这个是必须了解的,不止freemodbus,所有的modbus协议都要遵从这个结构。

 

3.常用的功能码:

01   读取单个/多个线圈状态(类似DO:数字输出)

02   读取单个/多个离散输入(类似DI:数字输入)

03   读取单个/多个保存寄存器

04   读取单个/多个输入寄存器(类似AI:模拟输入)

05   写单个线圈状态

06   写单个保存寄存器

15   写多个线圈

16   写多个保存寄存器

这个功能码就是我们常用的,我们经常也会说0x,1x,3x,4x寄存器

0x (01,05/15功能码),只有0,1状态,可读可写,主要当做开关,使能标志等控制

1x (02功能码),只读的,可以表示灯的状态,故障状态等,也只有0,1。

3x (04功能码),只读的,可以用于数据值的显示等包含很多中数据类型。

4x (03,06/16功能码),读写,主要用于各种类型的数据的参数设置

 

4.接口解析

打开从机实例(sample_mb_slave.c):

可以看到核心的接口

1eMBInit(MB_RTU, SLAVE_ADDR, PORT_NUM, PORT_BAUDRATE, PORT_PARITY);

初始化RTU模式,从站ID,串口号,波特率,校验位

这样就很明确了,我们初始化配置就是在这个函数实现,之后进行优化,肯定也要进行相应初始化代码的修改及添加。

 

2eMBEnable();

1:设置Modbus协议栈工作状态eMBState为STATE_ENABLED; 

2:调用pvMBFrameStartCur()函数激活协议栈 

 

(3)eMBPoll();

·  1:检查协议栈状态是否使能,eMBState初值为STATE_NOT_INITIALIZED,在eMBInit()函数中被赋值为STATE_DISABLED,在eMBEnable函数中被赋值为STATE_ENABLE; 

·  *2:轮询EV_FRAME_RECEIVED事件发生,若EV_FRAME_RECEIVED事件发生,接收一帧报文数据,上报EV_EXECUTE事件,解析一帧报文,响应(发送)一帧数据给主机; 

 

初始化,使能,轮询状态,就是上面三个函数的功能。

其实不单单是freemodbus,假如让你自己实现个通讯协议,你会怎么实现呢?、

首先初始化一个串口,打开串口发送和接收中断,在串口接收中断中,一个一个的接收数据并放到一个缓冲区中,当接收满一个包之后,置个标志,然后解析函数中检测到包满标志后,进行数据的解析,根据指令返回组包返回数据。

那么怎么判断包结束??

我们一般习惯使用一个定时器,在一定的时间内没有接收到数据,我们就认为包结束了。

其实这就是一个完整的接收解析过程,freemodbus无非是更完善,一些机制更合理而已。

想要找freemodbus的接口在哪里?

肯定是在eMBInit()里啊。

 case MB_RTU:
    pvMBFrameStartCur = eMBRTUStart;  /*使能modbus协议栈*/
    pvMBFrameStopCur = eMBRTUStop;  /*禁用modbus协议栈*/
    peMBFrameSendCur = eMBRTUSend; /*modbus从机响应函数*/
    peMBFrameReceiveCur = eMBRTUReceive; /*modbus报文接收函数*/
    pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
    /*串口接收中断最终调用此函数接收数据*/  
    pxMBFrameCBByteReceived = xMBRTUReceiveFSM; 
    /*串口发送中断最终调用此函数发送数据*/  
    pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM; 
    pxMBPortCBTimerExpired = xMBRTUTimerT35Expired;//报文到达间隔检查
    //初始化RTU,对接底层串口配置
    eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity );
 break;

 

了解接收机制:xMBRTUReceiveFSM

了解发送机制: xMBRTUTransmitFSM

帧数据完成,状态迁移:xMBRTUTimerT35Expired

具体的解释可以参考下面的博客,很详细:

https://blog.csdn.net/u014748120/article/details/80313215

这里我们需要注意的是modbus超时时间的配置,也就是一包完成的判断。

这里通过波特率进行的计算,还是比较合理的,不然很容易出现连包错包。

其实我们在平时的项目中,一个字节一个字节的接收,并且需要任务中不断轮询标志的这种方式是比较占用资源的。我们还习惯使用串口空闲中断+DMA的方式,当串口空闲后判断为接收包完成,发送队列或者信号量,触发任务解析,可以很大的节省系统资源。

下一节,我们对freemodbus进行简单的优化,生成我们的实例版本,方便后期直接使用该模板快速使用modbus进行参数的设置和存储。

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值