文章目录

  • 1 示例代码
  • 2 freemodbus介绍
  • 2 freemodbus移植
    • 2.1 串口的移植
    • 2.2 定时器的移植
  • 3 源码解析
    • 3.1 eMBEnable 解析
    • 3.2 eMBInit 解析
    • 3.3 eMBPoll 解析
    • 3.4 定时器超时 解析
    • 3.5 发送流程解析
    • 3.6 接收一帧数据流程 解析

STM32F103芯片的 freemodbus RTU的移植和使用。

1 示例代码

  代码示例上传在 gitee上,仓库地址为freemodbus移植示例

2 freemodbus介绍

  Freemodbus是一个奥地利人写的Modbus协议。它是一个针对嵌入式应用的一个免费(自由)的通用MODBUS协议的移植。Modbus是一个工业制造环境中应用的一个通用协议。Modbus通信协议栈包括两层:Modbus应用层协议,该层定义了数据模式和功能;另外一层是网络层。本文以STM32F103ZET6的单片机为例,在Keil环境中讲述单片机作为从机实现 freeModbus RTU 模式的移植。源码的下载地址为https://www.embedded-experts.at/en/freemodbus-downloads/ ,源码主要包括 demo modbus doc tools 四个文件夹。Demo 文件夹中主要free modbus官方为我们新建好的各种平台的测试例程,加快我们的开发进度,其中包括 Win32平台、Linux平台、ARM平台等。本次使用的是STM32的平台,在源码中并没有STM32平台的示例,但是在 demo 中有一个 BARE 文件夹,我们可以在该文件夹的基础上进行源码的移植。Modbus文件夹下,主要放一些关于Modbus自身协议的源码,其中包括Modbus-Rtu、Modbus-Ascii、Modbus-Tcp等。doc主要放一些帮助和说明文件,tools就是放置一些需要的工具,在测试时可以使用Modbus Poll 和 Modbus Slave 进行调试测试。

2 freemodbus移植

  由于freemodbus库没有在STM32上移植的示例,所以在移植STM32平台时只能在demo\BARE\port文件夹中进行从0开始的移植,在Keil工程中新建freemodbus文件夹,然后拷贝port文件夹和modbus文件夹下的所有内容到新建立的文件夹中,拷贝完成的文件夹如下图所示。

  port文件夹下的文件是本次移植要修改的部分,其中 portserial.c 是串口的初始化和收发控制的实现,porttimer.c 是3.5T定时器的实现,portevent.c 无需修改。

2.1 串口的移植

  本次设计使用的是modbus RTU模式,数据传输依靠串口来实现,所以需要将freemodbus库文件的数据的输入和输出定位在单片机的串口中,串口的移植在 portserial.c 中实现,在文件中主要实现了串口的初始化,串口的中断接收和发送的功能。
  串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备得RXD接口,在协议层中规定了数据包的内容,具体包括起始位、主体数据(8位或9位)、校验位以及停止位,通讯的双方必须将数据包的格式约定一致才能正常收发数据。通讯帧格式如下图所示。

  串口是一种最为常见的通讯方式,因为串口是一种全双工的通讯方式,但是modbus是一种主从也就是半双工的通讯方式,所以在移植时要设置串口为半双工的工作方式,即接收时关闭发送,发送时关闭接收。

2.2 定时器的移植

  Modbus协议规定,在RTU模式中,消息的发送和接收至少以3.5个字符时间的停顿间隔为标志。实际使用中,网络设备不断侦测网络总线,计算字符间的停顿间隔时间,判断消息帧的起始点。当接收到第一个域(地址域)时,每个设备都进行解码以判断是否是发给自己的,在最后一个传输字符结束之后,一个至少3.5个字符时间的停顿标志标定了消息的结束,而一个新的消息可在此停顿后开始。初次之外Modbus还规定当串口的波特率小于9600bps时,两个数据帧之间至少有3.5个字符的时间间隔,当波特率大于等于19200bps时,两个数据帧的时间间隔以波特为19200bps时的3.5个字符长度为判断依据。
  在freemodbus源码中,以定时器作为两个数据帧之间时间间隔的判断依据,源码的相关内容为:

/* If baudrate > 19200 then we should use the fixed timer values* t35 = 1750us. Otherwise t35 must be 3.5 times the character time.*/
if( ulBaudRate > 19200 )
{usTimerT35_50us = 35;       /* 1800us. */
}
else
{/* The timer reload value for a character is given by:** ChTimeValue = Ticks_per_1s / ( Baudrate / 11 )*             = 11 * Ticks_per_1s / Baudrate*             = 220000 / Baudrate* The reload for t3.5 is 1.5 times this value and similary* for t3.5.*/usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );
}
if( xMBPortTimersInit( ( USHORT ) usTimerT35_50us ) != TRUE )   // 定时器初始化
{
eStatus = MB_EPORTERR;
}

  分析源码可以看出,源码要求初始化一个50usTimerT35_50us的定时器,原因如下:源码展示了当波特率大于19200时,usTimerT35_50us赋值为35,这样赋值的原因是3.5个字符时35个比特位(每个字符包含一个起始位,8个数据位和一个停止位),所以3.5个字符所需要的发送时间为351/19200≈1823us。

3 源码解析

  FreeModbus协议栈作为从机,等待主机传送的数据,当从机接收到一帧完整的报文后,对报文进行解析,然后响应主机,发送报文给主机,实现主机和从机之间的通信。为了更好的实现整个代码的设计,本文对FreeModbus源码进行简单的分析。在源码的demo.c中主要有三个函数分别是eMBInit(),eMBEnable()和eMBPoll(),接下来将对这三个函数分别进行解析。
  源码解析图的源文件在仓库的 stm32f1xx_freemodbus/source_code_analysis 目录下

3.1 eMBEnable 解析

  eMBInit()主要实现的功能是实现RTU模式和ASCALL模式的协议栈初始化,完成协议栈核心函数指针的赋值,包括Modbus协议栈的使能和禁止、报文的接收和响应、3.5T定时器中断回调函数、串口发送和接收中断回调函数,eMBRTUInit完成RTU模式下串口和3.5T定时器的初始化,需依据不同的开发板平台进行移植,本次设计的串口的波特率位9600,从机地址为0x05,主要函数的调用关系如下图所示。

3.2 eMBInit 解析

  eMBEnable()函数主要设置Modbus协议栈工作状态eMBState为STATE_ENABLED;调用pvMBFrameStartCur()函数激活协议栈,函数调用关系如下图所示。

3.3 eMBPoll 解析

  eMBPoll()函数主要查询事件的状态,根据不同的状态执行相应的处理函数,调用关系如下图所示。eMBPoll()函数在while(1)被不断的调用,使用switch来不断的对检测到的事件进行分类处理,当接收到一帧完整的数据时,此时在3.5T定时器中断中会将事件状态修改为EV_FRAME_RECEIVED,表示接收到一帧数据,然后会调用eMBRTUReceive()函数将数据从接收缓冲区中取出,判断接收的数据帧的地址是否和本机地址一致如果一致的情况下,则将事件状态修改为EV_EXECUTE,开始对数据帧进行解析处理。
  在EV_EXECUTE状态下会首先遍历一个大小为16的结构体数组xFuncHandlers,寻找不同的功能码对应的执行函数,本文以读写保持寄存器为例进行解析,在eMBFuncReadHoldingRegister()函数中会对将数据帧进行拆分,取出功能码,寄存器地址,寄存器数量等数据,然后调用eMBRegHoldingCB()这个回调函数,这个函数源码库并没有实现,需要依据不同的功能进行编写,在编写时可以参考源码在其他平台下的移植实例,最终实现的效果是将数据从内存中取出放入对应的寄存器中,然后依据是否应答执行发送函数。

3.4 定时器超时 解析

  FreeModbus是通过定时器判断启动接收准备完成和一帧数据接收结束的,所有的处理均在定时器的中断中进行,定时器中断的处理流程如下图所示。定时器中断的入口函数是prvvTIMERExpiredISR(),最终调用的接口是xMBRTUTimerT35Expired(),在中断处理函数中依据接收状态机的状态,执行不同的处理流程。如果接收模式处于初始化状态则释放一个EV_REDAY信号,然后关闭定时器并将接收状态机修改为空闲模式;如果接收机处于STATE_RX_RCV状态,表示此时完成了一个数据帧的接收,此时将释放一个EV_FRAME_RECEIVED接收完成信号,然后关闭定时器并将接收状态机修改为空闲模式,待eMBPoll()轮询后发现接收完成事件,对接收的内容进行解析和处理。

3.5 发送流程解析

  本小节将详细说明发送过程的处理逻辑,发送的执行过程如下图所示。在eMBPoll()函数处理完接收的数据后开始调用发送函数peMBFrameSendCur()进行发送,最终调用的发送函数实际为eMBRTUSend(),在该发送函数中进行数据的组帧工作,同时修改发送状态机为eSndState为STATE_TX_XMIT,然后启动串口的发送字节函数xMBPortSerialPutByte()进行发送同时打开串口的发送功能关闭串口的接收功能,在每发送完一个字节的数据后会进入串口的发送中断处理函数中,最终调用的函数为xMBRTUTransmitFSM(),在该函数中会依据要发送的字节数循环的进行发送处理,待所有的要发送的内容发送完毕后,会释放EV_FRAME_SENT事件按,然后关闭串口的发送功能,打开串口的接收功能,等待接收下一个数据帧。

3.6 接收一帧数据流程 解析

  接收过程的流程如下图所示。在串口的接收中断处理函数中执行具体的接收过程,最终调用的接收处理函数为xMBRTUReceiveFSM(),在这个函数中会根据不同的接收状态机执行相应的函数。
  因为在初始化时,调用了eMBEnable()函数,在这个函数中启动了3.5T定时器,然后定时器中断将eRcvState状态修改为STATE_RX_IDLE,所以收到第一个字节的数据后首先执行case STATE_RX_IDLE中的内容,在这个分支里将收到的第一个数据存储到了ucRTUBuf接收缓冲区的第一个位置,然后将接收状态机修改为STATE_RX_RCV,接着每产生一个接收中断,就将收到的数据依次存储在ucRTUBuf接收缓冲区中。待主机发送完所有的数据后,子机端因为3.5T定时器的作用在一段时间内没有收到数据产生一个定时器中断,定时器中断中将释放一个接收完成信号,将xEventInQueue修改为TRUE,待eMBPoll()轮询到接收完成事件后进行接收数据的解析和处理。

stm32f1xx-freemodbus-RTU 移植相关推荐

  1. FreeModbus RTU 移植指南

    FreeModbus 简介 FreeModbus 是一个免费的软件协议栈,实现了 Modbus 从机功能: 纯 C 语言 支持 Modbus RTU/ASCII 支持 Modbus TCP 本文介绍 ...

  2. STM32F103/107 移植Freemodbus RTU

    1.简介 FreeMODBUS一个奥地利人写的Modbus协议.它是一个针对嵌入式应用的一个免费(自由)的通用MODBUS协议的移植.Modbus是一个工业制造环境中应用的一个通用协议.Modbus通 ...

  3. FreeModbus的移植

    FreeModbus V1.6 主机使用说明 一.简述 FreeModbus是一款开源的Modbus协议栈,但是只有从机开源,主机源码是需要收费的.同时网上也没有发现比较好的开源的Modbus主机协议 ...

  4. 基于STM32F407+W5500的freemodbus tcp移植与实现

    环境:STM32CUBEMX6.6.1  MDK532 freemodbus1.6 首先是创建能驱动W5500的工程 主要用到硬件为SPI UART SPI速度建议不要太快,SPI1可以设置到40M, ...

  5. FreeModbus RTU传输

    首先,在使能modbus协议栈的时候,会调用pvMBFrameStartCur函数 /* 使能modbus */ eMBErrorCode eMBEnable(void) {eMBErrorCode ...

  6. 手把手教你移植FreeModbus到STM32【看评论区引导,领取全套资料包】

    为什么要移植freemodbus 大家好,近期由于一个小项目的需要,要用到Modbus协议进行通信.相信各位工作的小伙伴们,或多或少都要跟Modbus打交道吧.那么,Modbus协议的重要性我自不必多 ...

  7. FreeModbus开源协议栈的(五)野火指南者+Keil+FreeModbus 的Modbus RTU从站

    在网上关于STM32F103+FreeModbus 的Modbus RTU从站移植的移植有很多,在此记录一下自己在野火的指南者开发板上基于FreeModbus的Modbus RTU从站的过程. 文章目 ...

  8. 单片机移植freemodbus从机(STM32、GD32、瑞萨、国民技术等)

    从github下载:https://github.com/cwalter-at/freemodbus 无法下载或者下载太慢可以用资源下载,无需积分.[freeModbus从机源码下载] 示例代码 一. ...

  9. FreeModbus读/写寄存器小Bug

    备注:经过评论区网友批评指正,协议栈没有Bug.这里只是一种临时解决问题的思路,可能带来其他问题,请各位朋友谨慎使用. 在STM32F401中移植了FreeModBus,移植教程参考了这里:http: ...

最新文章

  1. 在Ruby中使用&运算符(new_array- arr&old_Array)创建数组实例
  2. 深度系统安装移动硬盘启动_深度系统如何安装_电脑知识
  3. 删除文件部分内容 php,php实现遍历目录并删除指定文件中指定内容_php技巧
  4. HALCON:lines_gauss用法解析
  5. java split空值也保留_Java内存大家都知道,但你知道要怎么管理Java内存吗?
  6. 基于uFUN开发板的RGB调色板
  7. 计算机地址如何表达,计算机中的地址是表示
  8. XOCDE构建提示Command /usr/bin/codesign failed with exit code 1的解决办法
  9. Android Java 颜色代码 对照表
  10. dubbo源码解析(二)springBoot+dubbo案例整合
  11. 批处理学习笔记3:使用echo命令输出空格行
  12. 华为笔记本没有网线口_笔记本电脑没有网线接口的怎么办?
  13. 学习笔记(2):模拟登陆抽屉网(ajax)
  14. [USACO07DEC]泥水坑Mud Puddles BFS BZOJ 1627
  15. Symmetric Matrices
  16. 超详细教程:YOLO_V3(yolov3)训练自己的数据
  17. html圆角半径,CSS3 / 绘制四个角不同半径的圆角边框 - 汇智网
  18. Python从入门到实战,我觉着拥有这三本书很有必要
  19. 两个简单的画验证码图形程序
  20. gvdp哪个工厂用_BTP、BTD与FSS三种线束设计业务模式的区别

热门文章

  1. 客户服务专员认证考试
  2. 我对软件测试行业的看法
  3. 开放教育公共事业管理(教育管理)本科综合实践环节实施方案
  4. 2019-05-22 SSS扫描器;SSS扫描器指南;
  5. 《别告诉我你懂PPT》--北京大学出版社
  6. 采用先进先出的退货问题
  7. 坏道的基本介绍及恢复方法
  8. 政府云计算的构建选择-刘鑫(政务云 云平台)
  9. [框架]PureMVC--核心层源码
  10. Windows XP 超级140个技巧(转)