| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 嵌入式 -> STM32移植modbus通讯协议简明教程 -> 正文阅读 |
|
[嵌入式]STM32移植modbus通讯协议简明教程 |
目录
?????? 本文简明概要的介绍Modbus通讯协议,并在STM32上实现Modbus协议,通过与Modbus Poll(一种Modbus上位机工具)联合调试以验证程序的正确性。
????????工具与源码下载地址:https://gitee.com/xiaowen_git/modbus
?????? Modbus是主从方式通信,一个总线上只有一个主机,但可以有多个从机(这一点类似于IIC的通讯方式)。简单来说,也就是主机问从机答。问啥呢?主要问两个问题--从机的寄存器(线圈)的数值是多少、主机要求从机修改一下寄存器(线圈)的数值并回答。 ?????? Modbus还可以细分很多种协议,但是主要就是三种: 1、Modbus-RTU(设备必须要有RTU协议!这是Modbus协议上规定的,且默认模式必须是RTU) 2、Modbus-ASCII(人类可读的,冗长的表示方式) 3、Modbus-TCP(以太网作为介质进行传输) ????????其实从本质来讲,这三个都是差不多的,你只要掌握一种,其余两种都可以轻而易举地掌握。本文就讲解Modbus-RTU协议,这个是最常使用的协议。
?????? 结合前面所讲,再来理解一下Modbus通讯协议,我们可以把通讯过程理解为主机叫哪个从机,做什么事情,怎么做,最后主机检查自己描述的对不对。一共四个步骤,也就是每次通讯都需要包含这四个步骤,每一次通讯都需要发送一个帧结构。所以就有 帧结构 = 地址 + 功能码 + 数据 + CRC校验。地址就是相当于哪个从机,功能码就是要干的事情,数据就是要具体怎么做,最后来个CRC校验确保数据是对的。值得注意的是地址: 地址的有效范围是1-247,其他有特殊用途,比如255是广播地址(广播地址就是应答所有地址,正常的需要两个设备的地址一样才能进行查询和回复),而且RTU没有帧头和帧尾,所以协议里明确两帧之间要大于3.5个字节时间间隔,作为一帧结束的判断依据。 ?????? 功能码有很多,但是最主要用到的是01,06,16,而且软件Modbus Poll也主要是使用这几个功能码,掌握这三个功能码,其余码的使用也是大同小异。 ?????? 接着我们理解一下这三个功能码的区别:功能码01是查询寄存器,功能码06修改单个寄存器,功能码16是修改连续的多个寄存器。 ?????? 下面直接实战理解一下。 ?????? ①功能码01实战: ?????? 主机发送: 01 03 00 00 00 01 84 0A ????????从机回复: 01 03 02 01 02 35 15
?????? ?????? ②功能码06实战: ?????? 主机发送: 01 06 00 00 12 34 84 BD ????????从机回复: 01 06 00 00 12 34 84 BD
????????③功能码16实战: ????????主机发送: 01 10 00 00 00 02 04 00 11 22 33 FB 1F ????????从机回复: 01 10 00 00 00 02 41 C8
????????我们使用正点原子的战舰开发板,程序的模板基于正点原子的“实验8 定时器中断实验(HAL库)”进行开发,以串口(USART1)作为介质与上位机Modbus Poll通讯。 ????????先说一下输出部分的程序,这个就最简单的,直接调用HAL库的函数就可以了。代码如下:
????????然后输入部分,不知道读者记不得前文说的“两帧之间要大于3.5个字节时间间隔,作为一帧结束的判断依据”这句话,那么字节时间怎么计算呢?如果波特率为9600,代表1秒可以传送9600 bits的数据,以业内常用的格式是8位数据,无校验位,1位停止位,加上一个必须的1 bit的起始位,那么一字节的串口数据一共是10位。所以每个字节时间为1/(9600/10)秒,也就是1.04ms。两帧之间要大于3.5个字节时间间隔,那么间隔时间设置为4ms即可。 ????????在程序中,我们定义一个变量modbus_time作为间隔时间的标志位,把modbus_time放入定时器中断服务函数(周期:1ms)中,让其一直增加数值,在串口中断函数中只要收到1Byte消息便会把modbus_time清零,当modbus_time大于4(字节间隔了4ms)且串口曾收到数据但没有接收到新的字节便认为一个帧结构数据接收完成。 ????????举个栗子,有01 02 03数据要发送过来,当数据01发送过来时,串口中断清零modbus_time,此时modbus_time=0,然后过了1.04秒后,数据02发了过来,此时modbus_time=1,但是串口中断清零modbus_time,此时modbus_time又变成0,然后过了1.04秒后,数据03发了过来,此时modbus_time=1,但是串口中断清零modbus_time,此时modbus_time又变成0,最后没有数据再发送过来了,此时modbus_time大于4(字节间隔了4ms)且串口曾收到数据但没有接收到新的字节便认为一个帧结构数据接收完成。 ????????此外我们需要修改串口中断服务函数,把接收状态标记USART_RX_STA的接收完成标志bit15相关功能屏蔽(因为正点原子的原本例程是串口收到0x0d 与 0x0a表示收到完整的串口数据),然后将接收状态标记USART_RX_STA的接收完成标志bit15写在定时器中断函数中作为Modbus接收完成标志位。代码如下
????????这一部分考验C语言的功底,只要清楚Modbus-RTU协议并且C语言功底扎实,相信读者自己也可以办到。详细部分看笔者的源码实现。
????????打开上位机Modbus Poll,然后按下图设置便将上位机连接到板卡。 ????????连接成功后,读者会发现10个寄存器的值会发生改变。这十个数值是程序初设设定的寄存器数值。如下图。 ????????然后我们双击上图数值,便可进入快捷修改寄存器数值界面。然后便可以对功能码06和功能码16进行测试,测试结果如下: ????????另外点击右侧的“TC”可以自定义写入数据,我们将教程的数据写入测试可以得到下图结果。而且点击类似查找的按钮可以查看当前发送消息和接收消息内容(可以结合快捷修改寄存器数值界面使用)。 |
|
嵌入式 最新文章 |
基于高精度单片机开发红外测温仪方案 |
89C51单片机与DAC0832 |
基于51单片机宠物自动投料喂食器控制系统仿 |
《痞子衡嵌入式半月刊》 第 68 期 |
多思计组实验实验七 简单模型机实验 |
CSC7720 |
启明智显分享| ESP32学习笔记参考--PWM(脉冲 |
STM32初探 |
STM32 总结 |
【STM32】CubeMX例程四---定时器中断(附工 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 12:27:21- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |