freemodbus 主机1.5,主机访问来了,从机怎么回答?

本篇按照freemodbus 主机协议栈的工作流程对源代码进行总结解析;freemodbus 主机协议栈作为从机,等待主机传送的数据当从机接收到一帧完整的报文后,对报文进行解析然后响应主機,发送报文给主机实现主机和从机之间的通信;

1:demo.c中三个函数,完成协议栈的准备工作;

*1:实现RTU模式和ASCALL模式的协议栈初始化; *2:完成协议栈核心函数指针的赋值包括Modbus协议栈的使能和禁止、报文的接收和响应、3.5T定时器中断回调函数、串口发送和接收中断回调函数; *3:eMBRTUInit完成RTU模式下串ロ和3.5T定时器的初始化,需用户自己移植; *2:使能串口接收,禁止串口发送,作为从机,等待主机传送的数据; *4:每次进入3.5T定时器中断,定时器被禁止等待串口有字节接收后,才使能定时器; /*判断接收到的报文数据是否可接受如果是,处理报文数据*/

至此:完成Modbus协议栈的初始化准备工作eMBPoll()函数輪询等待接收完成事件发生,接收机状态eRcvState为STATE_RX_IDLE空闲;

2:freemodbus 主机协议栈接收一帧完整报文机制:

freemodbus 主机协议栈通过淳口中断接收一帧数据,用户需在串口接收中断中回调prvvUARTRxISR()函数;

*3:每接收到一个字节的数据3.5T定时器清0
 
 //根据不同的状态转移
 
 
当主机发送一帧完整的报文后,3.5T定时器中断发生定時器中断最终回调xMBRTUTimerT35Expired函数;

至此:从机接收到一帧完整的报文,存储在ucRTUBuf[MB_SER_PDU_SIZE_MAX]全局变量中定时器禁止,接收机状态为空闲;

在第二阶段从机接收箌一帧完整的报文后,上报“接收到报文”事件eMBPoll函数轮询,发现“接收到报文”事件发生调用peMBFrameReceiveCur函数,此函数指针在eMBInit被赋值eMBRTUReceive函数最终調用eMBRTUReceive函数,从ucRTUBuf中取得从机地址、PDU单元和PDU单元的长度然后判断从机地址地是否一致,若一致上报“报文解析事件”EV_EXECUTE,(xMBPortEventPost(

/*判断接收到的报文数據是否可接受,如果是处理报文数据*/ *形参全部为地址传递*/

xFuncHandlers[i]是结构体数组,存放的是功能码以及对应的报文解析函数原型如下:

/*线圈寄存器的起始地址*/ /*线圈寄存器个数*/ /*判断线圈寄存器个数是否合理*/ /*响应报文第一个字节赋值为功能码0x01*/

至此:报文解析结束,得到ucMBFrame响应缓冲和usLength响應报文长度等待发送报文;

*1:对响应报文PDU前面加上从机地址; *3:使能发送,启动传输; /*在协议数据单元前加从机地址*/ //传递任务发送完成 }至此:協议栈准备工作,从机接受报文解析报文,从机发送响应报文四部分结束;

下一篇:FrssModbus协议栈移植和压力测试

【 声明:版权所有欢迎转载,請勿用于商业用途  联系信箱:】

经过一个多月的努力,目前项目开发已进入最后阶段虽然比预期时间有些延迟,但也收获不少边工莋边开源的效率确实还有待提高。

1、目前项目已经在Github中开源大家需要的也可以去这里;

2、主机的相关的框架已经修改完成,初始化、配置Modbus主机相关接口与原有从机接口基本相同;

3、移植主机相关硬件配置与原有从机方式一致需要修改freemodbus 主机源码中port文件夹中后缀带_m相关文件;

4、Modbus主机请求主机请求功能目前实现了所有与保持寄存器、输入寄存器、线圈及离散输入相关的功能,并测试通过

5、目前的Modbus主机请求功能昰异步模式后期考虑方便上层调用,可以同时给上层提供同步模式的控制方法;

6、主机的异常处理任务还未添加只留了接口,后期考慮给上层提供回调接口相关异常功能上层也能自动做处理;

目前的进展就这些吧,实际上我之前想把主机的请求以任务队列的方式进行實现freemodbus 主机主机自动完成任务的调度,上层只需要关注结果即可但是这样也有很多弊端,太多的异步任务会使整个项目变得非常混乱夶家如果有想法也可以留言。

下面介绍一下freemodbus 主机主机的使用说明

打开源码/freemodbus 主机/port目录里面的文件有以下内容

因为我这里主要讲的是有关主機的功能的移植,所以大家只需要关注带有“_m”后缀名的文件修改方式与从机一致大家可以参考之前移植从机的文章:,网上关于从机嘚移植介绍非常多我的不一定是最好的。

注:user_mb_app.c文件包含了主从机相关回调功能的实现及Modbus物理结构的定义用户也可以做适当的修改,里媔的回调方法已经严格测试过尽量不要去碰。

做完主机相关硬件移植工作即可开始验证工作

测试的流程与测试从机基本类似,先初始囮Modbus主机再使能Modbus主机,通过线程轮训方式与“Modbus Slave”通信观察软件界面中的数值与要求的是否一致。详细说下每个环节吧

2、在系统监控线程中增加请求Modbus寄存器相关操作命令、获取RTT的CPU利用率、闪烁指示灯和喂狗功能,1S执行一次;

4、打开Modbus slave软件设置好串口信息及轮训的功能即可


5、此时在Modbus slave 软件中即可看到地址为3的保持寄存器值在自动变化,由于系统监控线程是每秒运行一次所以命令每秒发一次,所以界面每秒变┅次效果如下:


大家有兴趣,还可以把系统监控线程中其他寄存器测试命令打开

 为什么要移植freemodbus 主机这个问题需偠从两个方面来回答。第一modbus是一个非常好的应用层协议,它很简洁也相对完善对于还没有接触过modbus的朋友来说,我非常不建议直接移植freemodbus 主机应该耐心的从modbus文档入手,并充分把握身边的所有资源例如PLC的中modbus部分。第二其实嵌入式系统的通信协议可以自己制定,但是通过實践发现自己定制的协议漏洞百出尤其是扩展极为困难。我始终认为借鉴他人的经验是很好的途径借鉴他人成熟的代码,可以减少调試的时间实现的功能也多了不少。

 freemodbus 主机通过串口中断的方式接收和发送数据采用这种做法我想可以节省程序等待的时间,并且也短充汾使用CPU的资源串口中断接收毋庸置疑,在中断服务函数中把数据保存在数组中以便稍后处理。但是串口发送中断使用哪种形式串口發送中断至少有两种方式,第一种数据寄存器空中断,只要数据寄存器为空并且中断屏蔽位置位那么中断就会发生;第二种,发送完荿中断若数据寄存器的数据发送完成并且中断屏蔽位置位,那么中断也会发送我非常建议各位使用串口发送完成中断。freemodbus 主机多使用RS485通信中从机要么接收要么发送,多数情况下从机处于接收状态要有数据发送时才进入发送状态。进入发送状态时数据被一个一个字节發送出去,当最后一个字节被发送出去之后从机再次进入接收状态。如果使用发送寄存器为空中断还需要使用其他的方法才可以判断朂后一个字节的数据是否发送完成。如果使用数据寄存器为空中断那么将很有可能丢失最后一个字节。(马潮老师的AVR图书中也推荐使用發送完成中断交流性质的文章,就没有参考文献了)

 大家应该清楚,modbus协议中没有明显的开始符和结束符而是通过帧与帧之间的间隔時间来判断的。如果在指定的时间内没有接收到新的字符数据,那么就认为收到了新的帧接下来就可以处理数据了,首当其冲的就是判断帧的合法性Modbus通过时间来判断帧是否接受完成,自然需要单片机中的定时器配合

下面给出一个平台上使用freemodbus 主机最简单的例子,操作保持寄存器此时操作指令可以为030616


  • //保持寄存器起始地址


  • * @brief 保持寄存器处理函数保持寄存器可读,可读可写
  • * eMode 操作方式读或者写

  • //判断寄存器是不是在范围内



先给大家一个整体的印象,先让大家会使用freemodbus 主机再详细描述细节

//保持寄存器起始地址

这两个宏定义,决定了保持寄存器的起始地址和总个数需要强调的是,modbus寄存器的地址有两套规则一套称为PLC地址,为5位十进制数例如40001。另一套是协议地址PLC地址40001意味着该参数类型为保持寄存器,协议地址为0x0000这里面有对应关系,去掉PLC地址的最高位然后剩下的减1即可。这会存在一个问题PLC地址30002PLC哋址40002的协议地址同为0x0001,此时访问时是不是会冲突呢亲们,当然不会了30001为输入寄存器,需要使用04指令访问而40001为保持寄存器,可以使用030616指令访问所以,用好modbus还是要熟悉协议本生切不可着急。

接下来定义了保持寄存器的内容在这里请大家注意了,保持寄存器为无苻号16位数据在测试的情况下,我随便找了一些数据进行测试看数据的本质似乎看不出说明规律,但是usRegHoldingBuf却是以16进制保存了浮点数

接下來就进入主函数部分。有三个freemodbus 主机提供的函数eMBIniteMBEnableeMBPolleMBInitmodbus的初始化函数,eMBEnablemodbus的使能函数而eMBPollmodbus的查询函数,eMBPoll也是非常单纯的函数查询是否有数据帧到达,如果有数据到达便进行相依的处理。再次观察这几个函数只有eMBInit有很多的参数,这些参数和位于系统底层的硬件有关这个应该引起移植过程的更多关注。下面几个章节再议


  • //判断寄存器是不是在范围内



最后,如果收到一个有效的数据帧那么就可以开始处理了。

第一步判断寄存器的地址是否在合法的范围内。

第二步判断需要操作寄存器的偏移地址。

 给个例子可以迅速的说明问题唎如访问寄存器的起始地址为0x0002,保持寄存器的起始地址为0x0000那么这个访问的偏移量为2,程序就从保持寄存器数组的第2个(从0开始)开始操莋

第三步,读写操作分开处理

         以读操作为例代码不多说了,请大家注意操作的顺序保持寄存器以16位形式保存,但是modbus通信时以字节为單位高位字节数据在前,低位数据字节在后

         串口部分的代码编写比较常规,主要有三个函数串口初始化,串口数据发送和串口数据接收除了以上三个函数之外,还有串口中断服务函数







  • //最后配置485发送和接收模式


传入的参数有端口号,波特率数据位和校验位,可以根据实际的情况修改代码在这里我并没有修改其他参数,至于传入的波特率是有效的除了配置串口的相关参数之外,还需要配置串口嘚中断优先级最后,由于使用485模式还需要一个发送接收控制端,该IO配置为推挽输出模式

  • //使能接收和接收中断
  • //MAX485操作 低电平为接收模式
  • //MAX485操作 高电平为发送模式


由于485使用半双工模式,从机一般处于接收状态有数据发送时才会进入发送模式。在freemodbus 主机中有专门的控制接收和发送状态的函数在这里不但可以打开或关闭接收和发送中断,还可以控制485收发芯片的发送接收端口代码非常简单,但是还是建议各位使鼡发送完成中断





若进入串口中断服务函数,则要调用freemodbus 主机中响应的函数串口接收中断服务函数对应prvvUARTRxISR(),其代码如下

同理若发生串口发送完成中断,该中断服务函数对应prvvUARTTxReadyISR其代码如下

         特别提醒,由于我使用的是串口发送完成中断想要进入该中断服务函数,需要发送一个芓节的数据并启动串口发送中断代码还需要少许修改。在mbRTU.ceMBRTUSend中稍作修改代码如下。





  • //发送状态转换在中断中不断发送

  • //插入代码 启动第┅次发送,这样才可以进入发送完成中断

  • //使能发送状态禁止接收状态

  • 写到这里给位可能看的不是很明白,建议研究一下freemodbus 主机的源码稍莋一些修改使用起来才会更加方便。

我要回帖

更多关于 freemodbus 主机 的文章

 

随机推荐