初出茅庐的小李第59篇博客之测试Modbus协议的继电器

1, Modbus RTU指令详解

发送: FF 05 00 00 FF 00 99 E4
字段 含义 注释
FF 设备地址 范围1-255,默认255
05 功能码 写单个线圈
00 00 继电器地址 0x0000–0x0007分别代表#1继电器–#8继电器
FF 00 开/关命令 0x0000为关,0xFF00为开
99 E4 CRC16 CRC-16/MODBUS校验码
原样返回:FF 05 00 00 FF 00 99 E4
字段 含义 注释
FF 设备地址 范围1-255,默认255
05 功能码 写单个线圈
00 00 继电器地址 0x0000–0x0007分别代表#1继电器–#8继电器
FF 00 开/关命令 0x0000为关,0xFF00为开
99 E4 CRC16 CRC-16/MODBUS校验码

初出茅庐的小李第59篇博客之测试Modbus协议的继电器_第1张图片
校验的结果在Modbus报文里要低字节在前高字节在后

E4 99
是校验的结果
99 E4 才是报文的内容

2,关闭1号继电器(手动模式)

发送: FF 05 00 00 00 00 D8 14
字段 含义 注释
FF 设备地址 范围1-255,默认255
05 功能码 写单个线圈
00 00 继电器地址 0x0000–0x0007分别代表#1继电器–#8继电器
00 00 开/关命令 0x0000为关,0xFF00为开
D8 14 CRC16 CRC-16/MODBUS校验码
原样返回:FF 05 00 00 00 00 D8 14
字段 含义 注释
FF 设备地址 范围1-255,默认255
05 功能码 写单个线圈
00 00 继电器地址 0x0000–0x0007分别代表#1继电器–#8继电器
00 00 开/关命令 0x0000为关,0xFF00为开
D8 14 CRC16 CRC-16/MODBUS校验码

3,打开所有继电器

发送:FF 0F 00 00 00 08 01 FF 30 1D
字段 含义 注释
FF 设备地址 范围1-255,默认255
0F 功能码 写多个线圈
00 00 起始地址 #1继电器地址
00 08 继电器数量 要控制的继电器总数量
01 命令字节数 控制命令字长度
FF 控制命令 0x00为全关,0xFF为全开
30 1D CRC16 CRC-16/MODBUS校验码
返回:FF 0F 00 00 00 08 41 D3
字段 含义 注释
FF 设备地址 范围1-255,默认255
0F 功能码 写多个线圈
00 00 起始地址 #1继电器地址
00 08 继电器数量 要控制的继电器总数量
41 D3 CRC16 CRC-16/MODBUS校验码

4,关闭所有继电器

发送:FF 0F 00 00 00 08 01 00 70 5D
字段 含义 注释
FF 设备地址 范围1-255,默认255
0F 功能码 写多个线圈
00 00 起始地址 #1继电器地址
00 08 继电器数量 要控制的继电器总数量
01 命令字节数 控制命令字长度
00 控制命令 0x00为全关,0xFF为全开
70 5D CRC16 CRC-16/MODBUS校验码
返回:FF 0F 00 00 00 08 41 D3
字段 含义 注释
FF 设备地址 范围1-255,默认255
0F 功能码 写多个线圈
00 00 起始地址 #1继电器地址
00 08 继电器数量 要控制的继电器总数量
41 D3 CRC16 CRC-16/MODBUS校验码

5,设置设备地址为255

发送: 00 10 00 00 00 01 02 00 FF EB 80
字段 含义 注释
00 固定值
10 功能码 写多个寄存器
00 00 起始地址
00 01 写寄存器个数
02 写寄存器字节数 写寄存器数据长度
00 FF 寄存器数据 写入设备地址0x00FF,范围:0x0001-0x00FF
EB 80 CRC16 CRC-16/MODBUS校验码
原样返回:00 10 00 00 00 01 02 00 FF EB 80
字段 含义 注释
00 固定值
10 功能码 写多个寄存器
00 00 起始地址
00 01 写寄存器个数
02 写寄存器字节数 写寄存器数据长度
00 FF 寄存器数据 即:写入设备地址0x00FF,范围:0x0001-0x00FF
EB 80 CRC16 CRC-16/MODBUS校验码

6,读取设备地址255

发送: 00 03 00 00 00 01 85 DB
字段 含义 注释
00 固定值
03 功能码 读保持寄存器
00 00 起始地址
00 01 寄存器数量 读寄存器数量
85 DB CRC16 CRC-16/MODBUS校验码
返回: 00 03 02 00 FF C5 C4
字段 含义 注释
00 固定值
03 功能码 读保持寄存器
02 数据字节数 从寄存器读取到的数据长度
00 FF 寄存器数据 读取到设备地址为0x00FF
C5 C4 CRC16 CRC-16/MODBUS校验码

7,读取继电器状态

发送: FF 01 00 00 00 08 28 12
字段 含义 注释
FF 设备地址 范围1-255,默认255
01 功能码 读线圈状态
00 00 起始地址 #1继电器地址
00 08 继电器数量 要读取的继电器总数量为0x0008
28 12 CRC16 CRC-16/MODBUS校验码
返回: FF 01 01 01 A1 A0
字段 含义 注释
FF 设备地址 范围1-255,默认255
01 功能码 读线圈状态
01 数据字节数 读取到的数据长度
01 数据 读取到的数据,Bit0-Bit7分别代表#1继电器–#8继电器状态,0为关,1为开
A1 A0 CRC16 CRC-16/MODBUS校验码

8,读取光耦输入状态

发送: FF 02 00 00 00 08 6C 12
字段 含义 注释
FF 设备地址 范围1-255,默认255
02 功能码 读离散输入状态
00 00 起始地址 #1光耦地址
00 08 光耦数量 要读取的光耦总数量为0x0008
6C 12 CRC16 CRC-16/MODBUS校验码
返回: FF 02 01 01 51 A0
字段 含义 注释
FF 设备地址 范围1-255,默认255
02 功能码 读离散输入状态
01 数据字节数 读取到的数据长度
01 数据 读取到的数据,Bit0-Bit7分别代表#1光耦–#8光耦输入状态,0为高电平,1为低电平
51 A0 CRC16 CRC-16/MODBUS校验码

9,设置波特率为9600

发送: FF 10 03 E9 00 01 02 00 03 8B CC
字段 含义 注释
FF 设备地址 范围1-255,默认255
10 功能码 写多个寄存器
03 E9 起始地址
00 01 写寄存器个数
02 写寄存器字节数 写寄存器数据长度
00 03 寄存器数据 波特率写入值,范围:0x0002–0x0004,其中0x0002, 0x0003, 0x0004分别代表波特率4800, 9600, 19200
8B CC CRC16 CRC-16/MODBUS校验码
返回: FF 10 03 E9 00 01 C5 A7
字段 含义 注释
FF 设备地址 范围1-255,默认255
10 功能码 写多个寄存器
03 E9 起始地址
00 01 写寄存器个数
C5 A7 CRC16 CRC-16/MODBUS校验码

10,读取波特率 返回19200

发送: FF 03 03 E8 00 01 11 A4
字段 含义 注释
FF 设备地址 范围1-255,默认255
03 功能码 读保持寄存器
03 E8 起始地址
00 01 寄存器数量 读寄存器数量
11 A4 CRC16 CRC-16/MODBUS校验码
返回: FF 03 02 00 04 90 53
字段 含义 注释
FF 设备地址 范围1-255,默认255
03 功能码 读保持寄存器
02 数据字节数 从寄存器读取到的数据长度
00 04 寄存器数据 波特率读取值,范围:0x0002–0x0004,其中0x0002, 0x0003, 0x0004分别代表波特率4800, 9600, 19200
90 53 CRC16 CRC-16/MODBUS校验码

11,打开1号继电器(闪闭模式2S)

发送: FF 10 00 03 00 02 04 00 04 00 14 C5 9F
字段 含义 注释
FF 设备地址 范围1-255,默认255
10 功能码 写多个寄存器
00 03 继电器地址 #1继电器–#8继电器地址分别为:0x0003,0x0008,0x000D,0x0012,0x0017,0x001C,0x0021,0x0026
00 02 写寄存器个数
04 写寄存器字节数 写寄存器数据长度
00 04 寄存器1数据 闪闭/闪断值,0x0004代表闪闭,0x0002代表闪断
00 14 寄存器2数据 延时设置值,范围:0x0001–0xFFFF。延时基数为0.1S,故延时
时间为0x0014
0.1=200.1S=2S,#1继电器闭合2S后自动断开
C5 9F CRC16 CRC-16/MODBUS校验码
返回: FF 10 00 03 00 02 A4 16
字段 含义 注释
FF 设备地址 范围1-255,默认255
10 功能码 写多个寄存器
00 03 继电器地址 #1继电器–#8继电器地址分别为:0x0003,0x0008,0x000D,0x0012,0x0017,0x001C, 0x0021,0x0026
00 02 写寄存器个数
A4 16 CRC16 CRC-16/MODBUS校验码

12,关闭1号继电器(闪断模式3S)

发送: FF 10 00 03 00 02 04 00 02 00 1E A5 99
字段 含义 注释
FF 设备地址 范围1-255,默认255
10 功能码 写多个寄存器
00 03 继电器地址 #1继电器–#8继电器地址分别为:0x0003,0x0008,0x000D,0x0012,0x0017,0x001C,0x0021,0x0026
00 02 写寄存器个数
04 写寄存器字节数 写寄存器数据长度
00 02 寄存器1数据 闪闭/闪断值,0x0004代表闪闭,0x0002代表闪断
00 1E 寄存器2数据 延时设置值,范围:0x0001–0xFFFF。延时基数为0.1S,故延时时间为0x001E0.1=300.1S=3S,#1继电器断开3S后自动闭合
A5 99 CRC16 CRC-16/MODBUS校验码
返回: FF 10 00 03 00 02 A4 16
字段 含义 注释
FF 设备地址 范围1-255,默认255
10 功能码 写多个寄存器
00 03 继电器地址 #1继电器–#8继电器地址分别为:0x0003,0x0008,0x000D,0x0012,0x0017,0x001C, 0x0021,0x0026
00 02 写寄存器个数
A4 16 CRC16 CRC-16/MODBUS校验码

**这里面用到了很多功能码01 02 03 05 10 0F 等每种功能码都有其约定的含义具体含义是啥可以不用关心,既然是协议先遵循就好,接下里看如何组包用单片机发送这些命令 **

我现在不关心返回值所以先用简单的方式实现,真正的通信是应该判断通信之后返回的报文的我这里还没有做
安全起见先用调试助手测试

初出茅庐的小李第59篇博客之测试Modbus协议的继电器_第2张图片

这些报文经过测试跟手册说的一样证明这个模块还是比较可靠的

下面就用程序来实现发送

Arduino 控制继电器

const byte RS485_ON1[8]={0xFF,0x05,0x00,0x00,0xFF,0x00,0x99,0xE4};//FF 05 00 00 FF 00 99 E4 
const byte RS485_OFF1[8]={0xFF,0x05,0x00,0x00,0x00,0x00,0xD8,0x14};//FF 05 00 00 00 00 D8 14
const byte RS485_ON2[8]={0xFF,0x05,0x00,0x01,0xFF,0x00,0xC8,0x24};//FF 05 00 01 FF 00 C8 24
const byte RS485_OFF2[8]={0xFF,0x05,0x00,0x01,0x00,0x00,0x89,0xD4};//FF 05 00 01 00 00 89 D4
const byte RS485_ON3[8]={0xFF,0x05,0x00,0x02,0xFF,0x00,0x38,0x24};//FF 05 00 02 FF 00 38 24
const byte RS485_OFF3[8]={0xFF,0x05,0x00,0x02,0x00,0x00,0x79,0xD4};//FF 05 00 02 00 00 79 D4
const byte RS485_ON4[8]={0xFF,0x05,0x00,0x03,0xFF,0x00,0x69,0xE4};//FF 05 00 03 FF 00 69 E4
const byte RS485_OFF4[8]={0xFF,0x05,0x00,0x03,0x00,0x00,0x28,0x14};//FF 05 00 03 00 00 28 14
const byte RS485_ONALL[10]={0xFF,0x0F,0x00,0x00,0x00,0x08,0x01,0xFF,0x30,0x1D};//FF 0F 00 00 00 08 01 FF 30 1D
const byte RS485_OFFALL[10]={0xFF,0x0F,0x00,0x00,0x00,0x08,0x01,0x00,0x70,0x5D};//FF 0F 00 00 00 08 01 00 70 5D

arduino中数据类型跟我们经常在C语言中还是有点不同
这里有两篇博文写的很清楚可以作为参考学习推荐收藏
链接

链接
初出茅庐的小李第59篇博客之测试Modbus协议的继电器_第3张图片
初出茅庐的小李第59篇博客之测试Modbus协议的继电器_第4张图片

红外控制的代码

/*
 * 红外控制函数
 * 函数说明:
 * 传入红外键值
 * 执行对应动作
 */
void IR_Contrl(unsigned int key_val)
{
//  unsigned char data;
//  data = 0x00;
//  /*不能直接写0x00在函数里,否则会报错*/
  switch(key_val)
  {
    case 0xFFA25D:
      {
          Serial.println("CH-");
          mySerial.write(RS485_OFFALL,sizeof(RS485_OFFALL));
//          mySerial.write(0xFF);
//          mySerial.write(0x05);
//          mySerial.write(data);
//          mySerial.write(data);
//          mySerial.write(0xFF);
//          mySerial.write(data);
//          mySerial.write(0x99);
//          mySerial.write(0xE4);
      }
      break;
    case 0xFF629D:
      Serial.println("CH");
      break;
    case 0xFFE21D:
      {
        Serial.println("CH+");
        mySerial.write(RS485_ONALL,sizeof(RS485_ONALL));
//        mySerial.write(0xFF);
//        mySerial.write(0x05);
//        mySerial.write(data);
//        mySerial.write(data);
//        mySerial.write(data);
//        mySerial.write(data);
//        mySerial.write(0xD8);
//        mySerial.write(0x14);
      }
      break;
    case 0xFF22DD:
      {
        Serial.println("PREV");
      }
      break;
    case 0xFF02FD:
      Serial.println("NEXT");
      break;
    case 0xFFC23D:
      Serial.println("PLAY/PAUSE");
      break;
    case 0xFFE01F:
      Serial.println("-");
      break;
    case 0xFFA857:
      Serial.println("+");
      break;
       case 0xFF906F:
      Serial.println("EQ");
      break;
    case 0xFF6897:
      Serial.println("0");
      break;
    case 0xFF30CF:
      {
        Serial.println("1");
        mySerial.write(RS485_ON1,sizeof(RS485_ON1));
      }
      break;
    case 0xFF18E7:
      {
        Serial.println("2");
        mySerial.write(RS485_ON2,sizeof(RS485_ON2));
      }
      break;
    case 0xFF7A85:
      {
        Serial.println("3");
        mySerial.write(RS485_ON3,sizeof(RS485_ON3));
      }
      break;
    case 0xFF10EF:
      {
        Serial.println("4");
        mySerial.write(RS485_ON4,sizeof(RS485_ON4));
      }
      break;
    case 0xFF38C7:
      {
        Serial.println("5");
        mySerial.write(RS485_OFF1,sizeof(RS485_OFF1));
      }
      break;
    case 0xFF5AA5:
      {
        Serial.println("6");
        mySerial.write(RS485_OFF2,sizeof(RS485_OFF2));
      }
      break;
    case 0xFF42BD:
      {
        Serial.println("7");
        mySerial.write(RS485_OFF3,sizeof(RS485_OFF3));
      }
      break;
    case 0xFF4AB5:
      {
        Serial.println("8");
        mySerial.write(RS485_OFF4,sizeof(RS485_OFF4));
      }
      break;
    case 0xFF52AD:
      Serial.println("9");
      break;
    case 0xFF9867:
      Serial.println("100+");
      break;
    case 0xFFB04F:
      Serial.println("200+");
      break;
  }
}                        

最后测试的效果

初出茅庐的小李第59篇博客之测试Modbus协议的继电器_第5张图片

https://www.bilibili.com/video/BV1X5411E7Zj小破站测试结果

接下里可以玩玩这个风扇,据说四线风扇可以PWM调速,那我们或许可以试试编码器调速,或者温度调速,把这个风扇玩起来

这个风扇是我在租房子的时候房东管理员哪里两瓶饮料换来的(其实是他送我的,我也不好意白嫖啊!!!!)

你可能感兴趣的:(笔记,arduino,modbus,继电器,风扇控制)