OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 1896|回复: 0

低代码物联网开发板RS485串口及Modbus范例可接入机智云

[复制链接]

308

主题

317

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
1211
金钱
1211
注册时间
2020-2-25
在线时间
115 小时
发表于 2023-6-16 15:06:12 | 显示全部楼层 |阅读模式
一、RS485基础通信例程实现的功能描述


开发板通过UART1接口 + SP485EEN芯片实现和电脑端串口调试助手的通信。并实现如下两个收发范例功能:
如果PC端通过485向开发板发送5字节数据,且5字节数据为06 07 08 09 0A,则黄色LED1闪烁一次
开发板每隔1秒通过485向PC端发送5字节数据,01 02 03 04 05


二、本实验教学目的

掌握基于ShineBlink的:
UART通信(占用RX1,TX1)
GPIO控制485转换芯片的方向(D2引脚控制485芯片的方向,高电平)
-GPIO控制LED1亮灭(D8连接黄色LED1)


三、本实验涉及的模块
485接口在开发板上的位置如下:




注意,为了使用485接口,必须将P7和P8跳线帽短接才能让TX1引脚、RX1引脚和485转换芯片连接。


四、完整源代码
以下代码实现了如下功能:
如果PC端通过485向开发板发送5字节数据,且5字节数据为06 07 08 09 0A,则黄色LED1闪烁一次
开发板每隔1秒通过485向PC端发送5字节数据,01 02 03 04 05



  • LIB_GpioOutputConfig("D8","STANDARD") --初始化GPIO控制黄色LED1
  • LIB_GpioOutputConfig("D2","STANDARD") --初始化GPIO控制Max485 RE DE 收发控制
  • --配置Uart1串口波特率为19200,用作485通讯
  • LIB_Uart1Config("BAUDRATE_19200")
  • --使能MAX485发送
  • function SendEn()
  •     LIB_GpioWrite("D2",1)
  • end
  • --使能MAX485接收
  • function RecvEn()
  •     LIB_GpioWrite("D2",0)
  • end
  • --使能10毫秒定时器开始工作
  • LIB_10msTimerConfig("ENABLE")
  • cnt_10ms = 0
  • --定义10毫秒定时器的中断函数
  • function LIB_10msTimerCallback()
  •     cnt_10ms = cnt_10ms + 1
  • end
  • --开始大循环
  • while(GC(1) == true)
  • do
  •     --每1秒发送5字节数据给PC端
  •     if cnt_10ms >= 100 then  --1000ms
  •         cnt_10ms = 0
  •         send_data = {1,2,3,4,5}
  •         SendEn()
  •         LIB_Uart1BlockSend(send_data)
  •         RecvEn()
  •     end
  •     --查询是否收到PC端发来的5字节数据,并验证
  •     recv_flag,recv_data = LIB_Uart1Recv()
  •     if recv_flag == 1 and #recv_data == 5 then
  •         if recv_data[1] == 6 and recv_data[2] == 7 and recv_data[3] == 8 and recv_data[4] == 9 and recv_data[5] == 10 then
  •             LIB_GpioToggle("D8") --切换LED状态
  •         end
  •     end
  • end

[color=rgb(0, 0, 0) !important]复制代码




五、实验现象

将开发板的485接口通过485转USB工具和PC端连接以后,将上面的代码复制到开发板的虚拟TF卡中并开始运行,之后每秒钟可以在PC端串口调试助手收到开发板发来的5字节数据(01 02 03 04 05),并且当调试助手向开发板下发(06 07 08 09 0a)以后,开发板的黄色LED灯会闪烁以下,如下图:






注意:软件需要勾选“HEX显示”和"HEX发送"。
设备和上位机(Modbus主机)通信的实现
简介:
下文介绍了如何用ShineBlink作为设备端(Modbus从机)来和上位机(Modbus主机)来通信,并在ShineBlink设备端实现了0x03功能码(读取多个保持寄存器)和0x05功能码(写单个线圈)的程序代码。
一、实现环境
设备作为Modbus从机通过RS485总线和上位机通信,我们在电脑上运行知名的Modbus Poll调试软件作为上位机来模拟Modbus主机,Modbus Poll软件可以到其官网上下载。
二、设备介绍
设备作为Modbus网络中的其中一个节点有如下特性:串口属性:19200、N、8、1设备地址:21(0x15)设备支持的Modbus功能码:0x05 写单个线圈0x03 读取多个保持寄存器功能介绍:0x05,上位机通过向设备发送0x05功能码,对线圈地址为0x0000的线圈写入值0xFF00时,设备开始运行,对线圈地址为0x0000的线圈写入值0x0000时,设备停止运行。0x03,上位机通过向设备发送0x03功能码,读取保持寄存器起始地址为0x0000的9个保持寄存器(每个保持寄存器值为16bit无符号数据),每个寄存器对应的数据如下:




三、Modbus通信实现代码实例


以下代码不仅实现了03和05功能码,并实现了将各种异常情况回复给Modbus主机。

  • --程序中用到的全局变量定义
  • Pm25Percent = 0
  • HchoPercent = 0
  • TvocPercent = 0
  • MeshPercent = 0.0
  • Temprature1 = 0.00
  • Temprature2 = 0.00
  • Wind485DisSpeed = 0
  • DevIsRunning = 0 --控制设备运行或停止
  • FaultCode = 0 --故障代码
  • ​
  • --ModBus通信函数定义
  • function ModbusProcess()
  •     local sdata = {}
  •     --查询是否收到Modbus主机发来的消息
  •     flag, data = LIB_Uart1Recv()
  •     if flag == 1 then
  •         --判断消息是不是发给本机,是本机的才理会
  •         if data[1] == PI[2] then --PI[2], Modbus本机地址(1-247)
  •             --判断Modbus功能码
  •             if data[2] == 0x05 then -- 0x05 写单个线圈
  •                 --这里定义线圈地址为0x0000的线圈为开机/关机控制信号
  •                 if data[3] == 0x00 and data[4] == 0x00 then
  •                     if data[5] == 0xff and data[6] == 0x00 then --ON
  •                         DevIsRunning = 1 --置1开机全局变量
  •                     elseif data[5] == 0x00 and data[6] == 0x00 then --OFF
  •                         DevIsRunning = 0 --置0开机全局变量
  •                     else
  •                         --这里需回复非法数据03异常消息(非法数据值),读者可自行完成
  •                     end
  •                     --回复OK,把收到的数据原封不动回传
  •                     LIB_GpioWrite("D2",1) --使能485模块发送
  •                     LIB_Uart1BlockSend(data)
  •                     LIB_GpioWrite("D2",0) --使能485模块接收
  •                 else
  •                     --回复异常消息(非法数据地址)
  •                     sdata[1] = data[1] --本机地址
  •                     sdata[2] = data[2]+0x80 --异常的时候功能码加0x80
  •                     sdata[3] = 0x02 --异常码0x02表示设备不支持此数据地址
  •                     CRC = LIB_CrcCalculate("CRC16_MODBUS", sdata)
  •                     sdata[4] = CRC & 0x00ff --低位在前
  •                     sdata[5] = CRC >> 8 --高位在后
  •                     LIB_GpioWrite("D2",1) --使能485模块发送
  •                     LIB_Uart1BlockSend(sdata)
  •                     LIB_GpioWrite("D2",0) --使能485模块接收
  •                 end
  •             --这里用0x03而不用0x04是因为很多主机只支持03 06 16指令,所以就随大流咯
  •             elseif data[2] == 0x03 then --0x03 读多个保持寄存器
  •                 --这里定义起始地址为0x0000的这些寄存器存放传感器数据,且读取的寄存器个数必须是9个
  •                 if data[3] == 0x00 and data[4] == 0x00 and data[5] == 0x00 and data[6] == 0x09 then
  •                     sdata[1] = data[1] --本机地址
  •                     sdata[2] = data[2] --功能码
  •                     sdata[3] = 18 --数据域字节数: 9个寄存器一共18字节
  •                     sdata[4] = Pm25Percent >> 8
  •                     sdata[5] = Pm25Percent & 0x00ff
  •                     sdata[6] = HchoPercent >> 8
  •                     sdata[7] = HchoPercent & 0x00ff
  •                     sdata[8] = TvocPercent >> 8
  •                     sdata[9] = TvocPercent & 0x00ff
  •                     sdata[10] = math.floor(MeshPercent) >> 8
  •                     sdata[11] = math.floor(MeshPercent) & 0x00ff
  •                     sdata[12] = math.floor(Temprature1) >> 8
  •                     sdata[13] = math.floor(Temprature1) & 0x00ff
  •                     sdata[14] = math.floor(Temprature2) >> 8
  •                     sdata[15] = math.floor(Temprature2) & 0x00ff
  •                     sdata[16] = Wind485DisSpeed >> 8
  •                     sdata[17] = Wind485DisSpeed & 0x00ff
  •                     sdata[18] = DevIsRunning >> 8
  •                     sdata[19] = DevIsRunning & 0x00ff
  •                     sdata[20] = FaultCode >> 8
  •                     sdata[21] = FaultCode & 0x00ff
  •                     CRC = LIB_CrcCalculate("CRC16_MODBUS", sdata)
  •                     sdata[22] = CRC & 0x00ff --低位在前
  •                     sdata[23] = CRC >> 8 --高位在后
  •                     --回复传感器数据
  •                     LIB_GpioWrite("D2",1) --使能485模块发送
  •                     LIB_Uart1BlockSend(sdata)
  •                     LIB_GpioWrite("D2",0) --使能485模块接收
  •                 else
  •                     --回复异常消息(非法数据地址)
  •                     sdata[1] = data[1] --本机地址
  •                     sdata[2] = data[2]+0x80 --异常的时候功能码加0x80
  •                     sdata[3] = 0x02 --异常码0x02表示设备不支持此数据地址
  •                     CRC = LIB_CrcCalculate("CRC16_MODBUS", sdata)
  •                     sdata[4] = CRC & 0x00ff --低位在前
  •                     sdata[5] = CRC >> 8 --高位在后
  •                     LIB_GpioWrite("D2",1) --使能485模块发送
  •                     LIB_Uart1BlockSend(sdata)
  •                     LIB_GpioWrite("D2",0) --使能485模块接收
  •                 end
  •             else
  •                 --回复异常消息(非法功能码)
  •                 sdata[1] = data[1] --本机地址
  •                 sdata[2] = data[2]+0x80 --异常的时候功能码加0x80
  •                 sdata[3] = 0x01 --异常码0x01表示设备不支持此功能码
  •                 CRC = LIB_CrcCalculate("CRC16_MODBUS", sdata)
  •                 sdata[4] = CRC & 0x00ff --低位在前
  •                 sdata[5] = CRC >> 8 --高位在后
  •                 LIB_GpioWrite("D2",1) --使能485模块发送
  •                 LIB_Uart1BlockSend(sdata)
  •                 LIB_GpioWrite("D2",0) --使能485模块接收
  •             end
  •         end
  •     end
  • end
  • ​
  • --开始初始化ShineBlink
  • --配置Uart1串口波特率为19200,接485模块
  • LIB_Uart1Config("BAUDRATE_19200")
  • --485发送和接收控制引脚
  • LIB_GpioOutputConfig("D2","STANDARD")
  • LIB_GpioWrite("D2",0) --使能485模块接收
  • ​
  • --开始大循环
  • while(GC(1) == true)
  • do
  •     --Modbus通信处理
  •     ModbusProcess()
  • end

[color=rgb(0, 0, 0) !important]复制代码



四、Modbus Poll 上位机实验流程
(1)配置0x03读取保持寄存器功能(Setup)





(2)建立Modbus串行通信连接(Connectiong)





(3)建立连接后的数据通信
1. 上位机每秒钟自动下发0x03指令读取设备的起始地址为0x0000的9个保持寄存器的值





通信数据日志:




上面设备回复的23个字节数据举例说明:
例如:15 03 12 00 06 00 00 00 01 00 00 00 16 00 16 00 00 00 00 00 00 D5 16
数据结尾的CRC算法采用Modbus Crc16
  • 本机地址:0x15
  • 功能码:0x03
  • 字节数:18字节(9个16bit无符号寄存器)
  • 寄存器1:0x0006 表示pm25=6
  • 寄存器2:0x0000 表示hch0=0
  • 寄存器3:0x0001 表示tvoc=1
  • 寄存器4:0x0000 表示mesh=6
  • 寄存器5:0x0016 表示temprature1=21度
  • 寄存器6:0x0016 表示temprature2=21度
  • 寄存器7:0x0000 表示windspeed=0
  • 寄存器8:0x0000 表示running=0
  • 寄存器9:0x0000 表示faultcode=0
  • CRC_L:0xD5
  • CRC_H:0x16

[color=rgb(0, 0, 0) !important]复制代码


2. 上位机下发开机命令(功能码0x05,向线圈地址为0x0000处写单个线圈值0xFF00)
通信数据日志:

3. 上位机下发停机命令(功能码0x05, 向线圈地址为0x0000处写单个线圈值0x0000)
上位机发送: 15 05 00 00 00 00 CE DE 设备应回复: 15 05 00 00 00 00 CE DE




正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-24 15:29

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表