MODBUS MASTER RTU在STM32上的实现

2023-05-16

MODBUS MASTER RTU在STM32上的实现

1.概述

  • 最近需要将几个信号采集模块通过总线串联起来,这样便于系统模块化。故将目光关注到了工业上经常使用的modbus协议。

  • modbus协议是一种一主多从的拓扑结构,主要是应用层软件协议,有关modbus的相关信息,可以自行google、百度。

  • STM32实现的Master工程代码在github上,点击获取。

2.开发环境

  • STM32F042单片机
  • MDK-KEIL5
  • STM32-CUBE库
  • Modbus slaver测试软件

3.移植来源

  • 信号采集模块作为slaver,采用的是开源的freemodbus协议。关于其的实现大家百度一下都能发现,相关的移植过程介绍也很多,不再一一赘述。值得注意的是:这个freemodbus的源码值得一看,其判断对一帧数据包的接受采用的是定时器判断超时。大体思路是中断接收函数在接收每一个字节数据时会重置定时器,如果定时器发生定时溢出中断,则说明没有新数据到来,代表一个数据包接收完整。

  • 然后就是master的设计实现。freemodbus并没有开源的master实现代码,故这部分需要我们自己开发完成。在github上发现有人发布了ardunio版本的master,但是ardunio的代码采C++语言编写,需要我们做一些C语言的移植和一些硬件底层接口的移植。

    ardunio master的github源工程链接点击,感谢他的分享。

4.移植过程

  • 了解ardunio modbus库的实现思路——很简单明了。打开源工程,里面有源代码和例程代码,不过例程代码需要用ardunio的IDE打开。其大体思路就是每个Modbus Function都用一个函数实现,如

      uint8_t ModbusMaster::readDiscreteInputs(uint16_t u16ReadAddress,uint16_t u16BitQty)
      {
        _u16ReadAddress = u16ReadAddress;
        _u16ReadQty = u16BitQty;
        return ModbusMasterTransaction(ku8MBReadDiscreteInputs);
       }

    这个ModbusMasterTransaction函数就是根据用户选择的功能模块填充数组并且发送,然后等待从机回应的数据(带超时检测),接着解析接收到的数据包,如果成功则将数据放在_u16ResponseBuffer数组中

  • 将ardunio的C++代码移植为C语言

  • 将ardunio相关的serial等函数使用自己的代码实现,serial函数其实就是硬件层接口的函数封装,这也是移植到其他平台必须要根据自身平台做相应的改变。
    (1). 在ModbusMasterTransaction函数中涉及到_serial->read()、_serial->write()、_serial->flush()、_serial->available()、millis()、bitWrite()、bitRead()、word()几种函数,从名字中我们就可以知道什么意思,故我们需要在我们的系统中重新实现这几个函数。
    (2). 我们底层串口的设计思路如下,数据发送采用数据的发送直接采用循环发送,而STM32cube库已经将这个功能封装好API接口,我们再封装一层即可,如下所示

      /**
        * @brief  将数据包发送出去
        * @param
        * @note
        * @retval void
        * @author xiaodaqi
        */
      uint8_t Modbus_Master_Write(uint8_t *buf,uint8_t length)
      {
       if(HAL_UART_Transmit(&huart2 ,(uint8_t *)buf,length,0xff))
       {
         return HAL_ERROR;
       }
          else
          {
            return HAL_OK;
          }
      }

    这句函数就相当于_serial->write()的实现。
    (3). 串口数据的接收:我们采用中断接收的方式,并且在中断处理函数中将接收到的字节采用循环队压人缓冲区,这样子就能实现ardunio的功能代码。

    跟底层相关的移植代码可到我的工程 Modbus_Master--trans_recieve_buff_control.c .h文件查看。

    _serial->read()的变体为:

      /**
        * @brief  读出缓冲区的数据
        * @param
        * @note
        * @retval void
        * @author xiaodaqi
        */
      uint8_t Modbus_Master_Read(void)
      {
          uint8_t cur =0xff;
          if( !rbIsEmpty(&m_Modbus_Master_RX_RingBuff))
          {
                cur = rbPop(&m_Modbus_Master_RX_RingBuff);
          }
          return cur;
      }

    _serial->flush()的变体为:

      /**
        * @brief  清除环形队列
        * @param
        * @note
        * @retval void
        * @author xiaodaqi
        */
      uint8_t Modbus_Master_Rece_Flush(void)
      {
        rbClear(&m_Modbus_Master_RX_RingBuff);
      }

    _serial->available()的变体为:

      /**
        * @brief  判断ringbuffer里面是否有尚未处理的字节
        * @param
        * @note
        * @retval void
        * @author xiaodaqi
        */
      uint8_t Modbus_Master_Rece_Available(void)
      {
          /*如果数据包buffer里面溢出了,则清零,重新计数*/
              if(m_Modbus_Master_RX_RingBuff.flagOverflow==1)
              {
                  rbClear(&m_Modbus_Master_RX_RingBuff);
              }
          return !rbIsEmpty(&m_Modbus_Master_RX_RingBuff);
      }

    millis()的变体为:

      /**
        * @brief  1ms周期的定时器
        * @param
        * @note
        * @retval void
        * @author xiaodaqi
        */
      uint32_t Modbus_Master_Millis(void)
      {
        return HAL_GetTick();
      }

    其余几个函数的变体如下:

      /*模拟ardunio函数*************************************************/
      static inline uint8_t lowByte(uint16_t ww)
      {
        return (uint8_t) ((ww) & 0x00FF);
      }
    
      static inline uint8_t highByte(uint16_t ww)
      {
        return (uint8_t) ((ww) >> 8);
      }
    
      static inline uint16_t word(uint8_t H_Byte,uint8_t L_Byte)
      {
          uint16_t word;
          word = (uint16_t)(H_Byte<<8);
          word = word + L_Byte;
        return word;
      }
    
      #define bitSet(value, bit)  ((value) |= (1UL << (bit))) 
      #define bitClear(value, bit)  ((value) &= ~(1UL << (bit)))
    
      #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
      #define bitRead(value, bit)  (((value) >> (bit)) & 0x01) 

    (4).剩下的就是串口的一些硬件初始化,如波特率等,这些配置由于我是用CUBEMX配置直接生成的代码,这里不做过多阐述。

5.代码调试

完成上述关键代码的移植后就可以进行调试了。

  • 在main函数中增加如下的测试代码

        while (1)
        {
              uint8_t result;
              //测试read input registers功能
              //从机地址0x01 ,连续都2个地址为0x2的寄存器
              result = ModbusMaster_readInputRegisters(0x01,0x2, 2);
              if (result == 0x00)
              {
                  Input_Result[0] = ModbusMaster_getResponseBuffer(0x00);
                  Input_Result[1] = ModbusMaster_getResponseBuffer(0x01);
              }
                  HAL_Delay(1000);
        }
  • 我们使用Modbus Slave软件来模拟从机。并且设置相应的地址里面的数值为1和2。软件使用方法可自行百度、google。下图为软件设置及运行结果。
    FHz8VgM.png

  • 然后我们用keil仿真查看结果Input_Result数组的结果。如下图所示,结果显示modbus通信正确。
    S9kJUOc.png

6.总结

以上即为本次移植的过程,有需要的朋友可以直接使用我的代码,亦可使用ardunio代码自行移植。

转载于:https://www.cnblogs.com/littlebigqi/p/7736945.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MODBUS MASTER RTU在STM32上的实现 的相关文章

  • Push_back() 导致程序在进入 main() 之前停止

    我正在为我的 STM32F3 Discovery 板使用 C 进行开发 并使用 std deque 作为队列 在尝试调试我的代码 直接在带有 ST link 的设备上或在模拟器中 后 代码最终在 main 中输入我的代码之前在断点处停止 然
  • STM32用一个定时器执行多任务写法

    文章目录 main c include stm32f4xx h uint32 t Power check times 电量检测周期 uint32 t RFID Init Check times RFID检测周期 int main Timer
  • HAL库学习

    CMSIS简介 CMSIS Cortex Microcontroller Software Interface Standard 微控制器软件接口标准 由ARM和其合作的芯片厂商 ST NXP 软件工具厂商 KEIL IAR 共同制定的标准
  • STM32F103概要

    The STM32F103x4 STM32F103x6 STM32F103xC STM32F103xD and STM32F103xE are a drop in replacement for STM32F103x8 B medium d
  • 硬件基础-电容

    电容 本质 电容两端电压不能激变 所以可以起到稳定电压作用 充放电 电容量的大小 想使电容容量大 使用介电常数高的介质 增大极板间的面积 减小极板间的距离 品牌 国外 村田 muRata 松下 PANASONIC 三星 SAMSUNG 太诱
  • 解决KEIL编译慢问题

    两种方案 使用v6版本的ARM Compiler 如果v6版本编译不过 必须使用v5版本的 则可以勾选掉Browse Information选项 提升很明显 1分多钟能优化到几秒 看代码量 但是这个有个弊端 在KEIL中会影响函数跳转 建议
  • 解决KEIL编译慢问题

    两种方案 使用v6版本的ARM Compiler 如果v6版本编译不过 必须使用v5版本的 则可以勾选掉Browse Information选项 提升很明显 1分多钟能优化到几秒 看代码量 但是这个有个弊端 在KEIL中会影响函数跳转 建议
  • Modbus TCP Android 应用程序

    我正在开发 Android 应用程序来在 tcp ip modbus 的帮助下控制 PLC 有人对此有很好的教程吗 Modbus协议转义线程 Android Jamod https stackoverflow com questions 1
  • 毕设开题分享 单片机智能教室系统(智能照明+人数统计)

    1 简介 Hi 大家好 今天向大家介绍一个学长做的单片机项目 单片机智能教室系统 智能照明 人数统计 大家可用于 课程设计 或 毕业设计 项目分享 https gitee com feifei1122 simulation project
  • rtu水文专用(支持SL/T427-2021等大部分协议)

    SRTU200 系列是一款集数据采集与 4G NB IoT LoRa GPS 等多种通信功能于一体的 多功能遥测终端机 该设备搭配丰富的采集控制接口 提供 RS232 RS485 以太网 模拟量 输入 开关量输入 开关量输出和继电器等 产品
  • Arm:objcopy 如何知道 elf 中的哪些部分要包含在二进制或 ihex 中?

    我正在开发一个项目 其中涉及解析arm elf 文件并从中提取部分 显然 elf 文件中有很多部分没有加载到闪存中 但我想知道 objcopy 到底如何知道要在二进制文件中包含哪些部分以直接闪存到闪存中 以arm elf文件的以下reade
  • 需要 modbus Java 库 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我需要带有源代码的简单 modbus Java 库 我在谷歌上找到了 但有 jar 文件 并且没有强大的
  • Qt modbus串口流控处理

    我正在通过串行端口使用 QModbusDevice 编写一个小程序 使用QModbusRtuSerialMaster类 并有一些问题 问题之一似乎是串口的流量控制不正确 检查串行端口嗅探器时 我发现工作客户端在发送请求时打开 RTS 然后关
  • 我可以在输入寄存器中写入吗? MODBUS

    我已经在一家公司工作了两个月MODBUS项目现在我发现了一个问题 我的客户要求我写入输入寄存器 地址 30001 到 40000 我认为这对我来说不是什么问题 因为每个modbus文档说 30001 到 40000 寄存器是只读的 甚至可以
  • 带 Spring Boot 项目的 Modbus 脉冲线圈

    必须实施呼叫数字IO with Modbus协议 on 春季启动项目构建者Maven 它应该是在身体上有一定持续时间的脉冲呼叫 例如 5 秒等 以下是规范中的一个片段 关于响应和错误的更多信息 看来这个呼叫应用程序应该表现得像一个大师 在这
  • 使用 STM32F0 ADC 单独读取不同的输入

    STM32F072CBU 微控制器 我有多个 ADC 输入 并且希望单独读取它们 STMcubeMX 生成样板代码 假设我希望按顺序读取所有输入 但我无法弄清楚如何纠正这个问题 这篇博文 http blog koepi info 2015
  • 当端点和 PMA 地址均更改时,CubeMX 生成的 USB HID 设备发送错误数据

    我正在调试我正在创建的复合设备的问题 并在新生成的仅 CubeMX 代码中重新创建了该问题 以使其更容易解决 我添加了少量代码main 让我发送 USB HID 鼠标点击 并在按下蓝色按钮时使 LED 闪烁 uint8 t click re
  • 如何在 iPhone 应用程序中与 Modbus 设备通信?

    我希望能够开发一个可以与 Modbus 设备通信的 iPhone 应用程序 但我不知道如何继续 有没有人有这方面的经验 或者是否有用于此目的的现有图书馆 您首先需要知道如何在您的 iPhone 上创建一个简单的 TCP 客户端 以及如何在您
  • 无法访问超过 255 个的 Modbus 寄存器 SimpleModbus

    我是法国学生 我已经使用 SimpleModbus 1 周了 它工作得很好 直到我尝试实现一个具有大量寄存器 1000needed 使用从站 1 无法访问超过 255 个的寄存器 无论我做什么 一旦寄存器读数超过 255 我就会收到超时错误
  • 读取STM32 MCU SPI数据寄存器的值

    有很多类似的问题 但似乎没有一个问题完全相同 我正在将 STML4 MCU 连接到 6 轴传感器 LSM6DS3 我已经成功地在 I2C 中实现了所有内容 但想要 SPI 的额外速度 和 DMA 如果我能让这些第一步工作起来的话 因此 第一

随机推荐

  • 【Http认证方式】——Basic认证

    访问请求 xff1a http 192 168 2 113 8080 geoserver rest workspaces时 xff0c 浏览器弹出窗口需要输入用户名和密码 xff0c 并且 xff0c 如果不输入或者输入错误 xff0c 浏
  • c++ http请求

    平常我们要访问某个URL一般都是通过浏览器进行 xff1a 提交一个URL请求后 xff0c 浏览器将请求发向目标服务器或者代理服务器 xff0c 目标服务器或者代理服务器返回我们所需要的数据 xff0c 浏览器接收到这些数据后保存成文件并
  • libcurl实现http登录功能

    用Fiddler Web Debugger捕捉http数据包 xff1a 观察看看 xff0c POST请求的地址为http passport cnblogs com login aspx ReturnUrl 61 http 3a 2f 2
  • 服务器机柜和网络机柜的区别

    原文转载自 http www fwqtg net 服务器机柜 xff0c 用来组合安装面板 插件 插箱 电子元件 器件和机械零件与部件 xff0c 使其构成一个整体的安装箱 服务器机柜由框架和盖板 xff08 门 xff09 组成 xff0
  • Eclipse+Maven创建webapp项目<一>

    Eclipse 43 Maven创建webapp项目 lt 一 gt 1 开启eclipse xff0c 右键new other xff0c 如下图找到maven project 2 选择maven project xff0c 显示创建ma
  • java日期格式(年月日时分秒毫秒)

    package test remote tools combine import java text SimpleDateFormat import java util Calendar import java util Date impo
  • 游戏中的帧同步要求的计算一致性——定点数(Fixed Point)

    最近做了一款帧同步游戏 xff0c 其寻路算法采用了RVO算法 但是由于是移动端的游戏 需要在不同的设备上运行 xff0c 其所有运算必须符合一致性 即所有客户端运算出来的结果必须一致 但是由于浮点数的特性 xff0c 具有误差 xff0c
  • 敏捷测试驱动模式-项目质量保障体系

    结合敏捷项目管理 xff0c 测试驱动模式 xff0c 让测试跑起来 我给这套体系的定义就是 保障质量的同时保证项目进度 xff0c 四个节点及时反馈及时沟通 xff0c 有效的让产品 研发和测试都动起来 xff0c 避免任意一方的停滞 质
  • angularjs自定义指令函数传参

    问题描述 在编写导入指令的时候 xff0c 需要将函数绑定到指令中 xff0c 并传入一个参数 初步实现 首先指令的js文件如下 xff0c 基本的绑定参数和绑定函数 xff0c 没有什么说的 xff1a angular module 39
  • 浅谈JSONObject解析JSON数据

    个人博客同步文章 https mr houzi com 2018 06 根据一段天气API来说一下JSONObject如何解析json数据 xff0c 尽管现在在开发中使用Gson等 xff0c 对于像我这样初次使用Java做开发的小白 x
  • 能ping通,但是不能wget或curl

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 当出现http接口请求超时时 xff0c 可以从以下几个方面排查问题 xff1a 检查接口服务本身是否正常 xff1b 检查接口所在服务器的防火墙是否开启 xff0c 尝试
  • R语言选择特定的行,对某一列排序

    R语言的数据框跟MySQL 中的表很像 根据某一列的特定值选择相应的行 d是个数据框 xff0c 有一列的名字是name d d name 61 61 34 95 34 这样就选中了 name为 95 的所有行 m 是个数据框 xff0c
  • excel表格公式无效、不生效的解决方案及常见问题、常用函数

    1 表格公式无效 不生效 使用公式时碰到了一个问题 xff0c 那就是公式明明已经编辑好了 xff0c 但是在单元格里不生效 xff0c 直接把公式显示出来了 xff0c 网上资料说有4种原因 xff0c 但是我4种都不是 xff0c 是第
  • JVM_栈详解一

    1 Java虚拟机栈 2 栈的存储单位 栈中存储什么 xff1f 每个线程都有自己的栈 xff0c 栈中的数据都是以栈帧 xff08 Stack Frame xff09 的格式存在 在这个线程上正在执行的每个方法都各自对应一个栈帧 xff0
  • EntLib 3.1学习笔记(6) : Security Application Block

    http www microsoft com china MSDN library enterprisedevelopment softwaredev dnpag2entlib mspx mfr 61 true http msdn2 mic
  • Delphi文件操作所涉及的一些函数 附例子

    判断文件是否存在 FileExists 判断文件夹是否存在 DirectoryExists 删除文件 DeleteFile Windows DeleteFile 删除文件夹 RemoveDir RemoveDirectory 获取当前文件夹
  • 排序算法

    include lt iostream gt include lt cstdlib gt include lt cstdio gt include lt time h gt using namespace std 插入排序 void Ins
  • C++应用中调用YOLOv3(darknet)进行目标检测

    YOLOv3论文 xff1a https pjreddie com media files papers YOLOv3 pdf 官网和代码 xff1a https pjreddie com darknet yolo属于one stage x
  • DJI开发之航线重叠率的计算

    介绍 无人机在规划一块区域的时候 xff0c 我们需要手动的给予一些参数来影响无人机飞行 xff0c 对于一块地表 xff0c 无人机每隔N秒在空中间隔的拍照地表的一块区域 xff0c 在整个任务执行结束后 xff0c 拍到的所有区域照片能
  • MODBUS MASTER RTU在STM32上的实现

    MODBUS MASTER RTU在STM32上的实现 1 概述 最近需要将几个信号采集模块通过总线串联起来 xff0c 这样便于系统模块化 故将目光关注到了工业上经常使用的modbus协议 modbus协议是一种一主多从的拓扑结构 xff