通过modbus协议实现arduino与电能表串口通信(仅03功能)

作者

胡子阳

请注意阅读顺序一定要从头到尾!!否则容易忽略一些小细节!!

本人理解的术语解析

  ModbusRS485:一种通信协议,另一种RS232已被淘汰。
  Modbus主站(modbusMaster):主动发出指令,要求读取数据的一端(此实验中为arduino)。
  Modbus从站(modbusslaver):被动接收指令,并随指令读自己寄存器内的信息给主站,或是改写寄存器内的信息(此实验中为DDS283-1ZN电能表)。

相关器件与它们之间的接法

1. DDS283-1ZN电能表(你可以选用其他任意表,只要支持ModbusRS485的都行)图中两根线分别是RS485A与RS485B

RS485B
RS485B

2. RS485转TTL模块
  这个模块与上图电能表的连接方式如图左侧所示。如果你需要远程读表,建议你在RS485A与RS485B之间加一个75欧姆电阻。图的右侧是此模块与Arduino的接法,注意tx要接arduino的rx,rx要接arduino的tx!!!!
另外我想说,看准这块板,成功的关键点在于你是否买对这块板,它的价格在12元左右。不推荐使用其他便宜的板,那会导致数据传输不稳定。

485转ttl
485转ttl

3. arduinoUNO板 这是最常见的板,无图不解释。

4. Lcd1602液晶显示屏(无图)
这款显示屏是日本人发明的,只支持显示英文和日文以及数字,字符等。
关于这款液晶屏的用法,详见我的另一篇文章。本实验lcd1602的接法与那文章中介绍的接法一模一样。
5. 面包板与面包线(无图)
本实验线路复杂,最好使用面包板与面包线。
Arduino代码:

/*
此例子是modbus03功能(读取功能)的lcd1602打印实现。
用arduinoIDE 1.6.7编译通过 ,在在uno板上成功运行。
*/

#include <ModbusMaster.h>//modbusmaster库
#include <LiquidCrystal.h>//arduino自带的库
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);//定义一些引脚接法

uint16_t m_startAddress = 12;//要读取的从站起始地址
uint8_t m_length = 1;//从从站起始地址开始你需要读取的数据的长度
uint8_t result;//串口通信结果,不用明白是什么,只要知道这不是你最终需要的数据就行

ModbusMaster node(1);//对1号从站进行通信

void setup() {
  node.begin(9600);//定义arduino与从站之间的串口波特率
  lcd.begin(16, 2);//初始化lcd1602
}

void loop() {  

  result = node.readHoldingRegisters(m_startAddress, m_length);//调用相关函数
  if (result == node.ku8MBSuccess) {//如果通信成功
    lcd.setCursor(0, 0);//打印lcd第1行信息
    lcd.print("DATA:");
    for (uint8_t j = 0; j < m_length; j++)
    {
      lcd.print( node.getResponseBuffer(j), DEC );//以DEC(十)进制显示你要的数据
    }
  }
  else {
    lcd.setCursor(0, 1);//打印lcd第2行信息
    lcd.print("ERROR:");
    lcd.print(result, HEX);//以HEX(16)进制显示错误信息(E2:你的TX,RX断线,E0:你的485转ttl板子有问题)
  }
delay(500);//延时500毫秒
lcd.clear();//lcd清屏,所以屏幕会闪属正常现象
}

/*
以上代码中的注释仅为个人有限水平的理解,如果有什么说的不对的地方欢迎改写。
*/

  上述代码需要加载两个库。
  一个是#include <LiquidCrystal.h>这是关于lcd的自带库直接用就行。
  另一个是#include <ModbusMaster.h>
  需要手动连网加载,否则程序会显示编译错误。

项目->管理库
库导入

  搜索modbusmaster选择版本0.11.0,点安装。
然后它会自动下载这个库。

搜索库
搜索库

  注意!!!!Very important!!!!在上传数据的时候要先断开rx与tx!!!!

其他要点:

  无论你的从站是电能表还是其他的,你一定要知道它们的每个寄存器里面放的都是什么类型的内容。比如我这个电能表的寄存器情况:
  

地址Address变量名称 Variable读写属性Belong to R/W数据格式Data format符号sign数据类型DataModel
0000H
0001H
当前总电能
Current total energy
R每个电能占用4个字节
Each electric energy occupy 4 byte
无符号
unsigned
Dword
0002H
0003H
保留
Reserved
保留
Reserved
保留
Reserved
无符号
unsigned
Dword
0004H
0005H
保留
Reserved
保留
Reserved
保留
Reserved
无符号
unsigned
Dword
0006H
0007H
保留
Reserved
保留
Reserved
保留
Reserved
无符号
unsigned
Dword
0008H
0009H
当前反向电能
Current reversing energy
R每个电能占用4个字节
Each electric energy occupy 4 byte
无符号
unsigned
Dword
000AH
000BH
当前正向电能
Current_forword_energy
R每个电能占用4个字节
Each electric energy occupy 4 byte
无符号
unsigned
Dword
000CH电压
Voltage
RXXX.X_V无符号
unsigned
Word
000DH电流
Current
RXX.XX_A无符号
unsigned
Word
000EH有功功率
Active power
RXX.XXX_KW有符号
signed
Word
000FH无功功率
Reactive power
RXX.XXX_Kvar有符号
signed
Word
0010H功率因数
Power factor
RX.XXX无符号
unsigned
Word
0011H频率
Frequency
RXX.XX_无符号
unsigned
Word
0012H保留
Reserved
保留
Reserved
保留
Reserved
无符号 unsignedWord
0013H保留
Reserved
保留
Reserved
保留 Reserved无符号
unsigned
Word
0014H保留
Reserved
保留
Reserved
保留 Reserved无符号
unsigned
Word
0015H
高字节
High Byte
通信地址
Communication address
R/W001-247无符号
unsigned
Char
0015H
低字节
Low byte
通信波特率
Communication baudrate
R/W01–9600bps
(默认)(default)
02-4800bps
03–2400bps
04–1200bps
无符号
unsigned
Char

  从中可以看出地址为000CH也就是12号地址的寄存器放的是电压的情况。所以代码中uint16_t m_startAddress = 12;m_startAddress写成地址12 (16位)
uint8_t m_length = 1;读取1个地址的信息(8位)这样就可以愉快地读电压了。(uint16_t 与uint8_t是类型名,类似与int,float….就比如说0100 1001就是一个uint8_t变量,0010 0011 1100 1111 就是一个uint16_t变量)

效果图

效果图

  这是另一个类似的代码实现的,图中“D:2279”表示此时的电压是227.9v “82”是我用于调试的一个无关数据。

  • 25
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 20
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值