简单说几个常用的功01H 03H 06H
地址 | 功能码 | 起始地址高位 | 起始地址低位 | 寄存器数量高位 | 寄存器数量低位 | CRCH | CRCL |
0x01 | 0x01 | 0x00 | 0x00 | 0x00 | 0x05 | FC | 09 |
地址 | 功能码 | 字节数 | 数据 | CRCH | CRCL |
0x01 | 0x01 | 0x01 | 0x15 (0001 0101) | 90 | 47 |
寄存器地址 | 数据 |
0x00 | 1 |
0x01 | 0 |
0x02 | 1 |
0x03 | 0 |
0x04 | 1 |
0x05 | 补0 |
0x06 | 补0 |
0x07 | 补0 |
发送的数据是一个字节,需要0x00-0x04的数据,不足的补0,则0001 0101 (0x15)
地址 | 功能码 | 起始地址高位 | 起始地址低位 | 寄存器数量高位 | 寄存器数量低位 | CRCH | CRCL |
0x01 | 0x03 | 0x00 | 0x00 | 0x00 | 0x02 | 0B | C4 |
地址 | 功能码 | 字节数 | 数据1高位 | 数据1低位 | 数据2高位 | 数据2低位 | CRCH | CRCL |
0x01 | 0x03 | 0x04 | 00 | 12 | 00 | 34 | 5B | E1 |
每个数据两个字节,所以字节数为0x04
地址 | 功能码 | 寄存器地址高位 | 寄存器地址低位 | 写入数据高位 | 写入数据低位 | CRCH | CRCL |
0x01 | 0x06 | 0x00 | 0x00 | 0x00 | 0x02 | 08 | 0B |
地址 | 功能码 | 寄存器地址高位 | 寄存器地址低位 | 写入数据高位 | 写入数据低位 | CRCH | CRCL |
0x01 | 0x06 | 0x00 | 0x00 | 0x00 | 0x02 | 08 | 0B |
modbus协议寄存器地址与状态 | ||||
地址 |
参数定义 |
数据类型 |
数据字节 |
功能码 |
0x00 | 状态1 | 只读 |
1 |
01H |
0x01 | 状态2 | 只读 |
1 |
01H |
0x02 | 状态3 | 读/写 |
1 |
01H、06H |
0x03 | 状态4 | 读/写 |
1 |
01H、06H |
0x04 | 状态5 | 读/写 |
1 |
01H、06H |
0x10 | 数据1 | 只读 |
2 |
03H |
0x11 | 数据2 | 只读 |
2 |
03H |
0x12 | 数据3 | 只读 |
2 |
03H |
0x13 | 数据4 | 只读 |
2 |
03H |
0x14 | 数据5 | 只读 |
2 |
03H |
0x15 | 数据6 | 只读 |
2 |
03H |
0x16 | 数据7 | 只读 |
2 |
03H |
0x20 | 从机地址 |
只写 |
1 |
06H |
#define data_value_Num 7 // 7个数据 每个数据两个字节
#define data_Status_Num 5 // 5个状态 每个状态一个字节
uint8_t addr_slave=0x01;//主机地址
uint8_t DATA_Status_code[data_Status_Num] = {1,1,1,0,0};// 状态码缓存区 用于01功能码读取再发送
// 地址 0x00-0x04
uint8_t DATA_value[data_value_Num*2] = {0x00,0x02, 0x00,0x04, 0x00,0x06, 0x00,0x08, 0x30,0x39, 0x30,0x39, 0x01,0x15,};// 数据缓存区,用于03功能码读取再发送
// 地址 0x10-0x16
uint8_t DATA01_TX[6] = {0X01,0X01,0x01}; // 用于01功能码发送
uint8_t DATA03_TX[data_value_Num*2+5]= {0x01,0x03}; // 用于03功能码发送 14字节数据+5个固定数据(地址、功能码、字节数、CRC)
uint8_t DATA06_TX[8] = {0X01,0X06}; // 用于功能码0x06发送
定义几个数组用于存放数据与发送的数据
#ifndef F_CPU
#define F_CPU 11059200UL
#endif
#include // 端口
#include // 看门狗
#include // 中断
#include // 延时
#include
#include // 配置好的GPIO库调用方便
#include // 端口
#include
#include
#define DE_OUT DDRA|=(1<<(7)) // 输出
#define DE_LOW GPIO_LOW('A',7) // 片选DE=0;
#define DE_HIGH GPIO_HIGH('A',7) // 片选DE=1;
#define data_value_Num 7 // 7个数据 每个数据两个字节
#define data_Status_Num 5 // 5个状态 每个状态一个字节
uint8_t addr_slave=0x01;//主机地址
uint8_t DATA_Status_code[data_Status_Num] = {1,1,1,0,0};// 状态码缓存区 用于01功能码读取再发送
// 地址 0x00-0x04
uint8_t DATA_value[data_value_Num*2] = {0x00,0x02, 0x00,0x04, 0x00,0x06, 0x00,0x08, 0x30,0x39, 0x30,0x39, 0x01,0x15,};// 数据缓存区,用于03功能码读取再发送
// 地址 0x10-0x16
uint8_t DATA01_TX[6] = {0X01,0X01,0x01}; // 用于01功能码发送
uint8_t DATA03_TX[data_value_Num*2+5]= {0x01,0x03}; // 用于03功能码发送 14字节数据+5个固定数据(地址、功能码、字节数、CRC)
uint8_t DATA06_TX[8] = {0X01,0X06}; // 用于功能码0x06发送
void clc_Uart_Buffer() // 清串口缓存
{
uint8_t x;
for (x=0;x<8;x++)
Uart_Buffer[x]=0;
}
void modbus_parse() // modbus 数据解析
{
uint8_t x;
if (Uart_Buffer[0]==addr_slave)//地址判断
{
// 对接收到的串口数据做CRC校验
crc_high8=crc16(Uart_Buffer,6)>>8;//crc高8位
crc_low8=crc16(Uart_Buffer,6) & 0xFF;//crc低8位
if ( crc_high8==Uart_Buffer[6] && crc_low8==Uart_Buffer[7] ) // 校验
{
if (Uart_Buffer[1]==1)// 功能码01 读状态
{
if (Uart_Buffer[5]-1<=0x04-Uart_Buffer[3]) // 连读超过最大地址则退出 列0x01,0x01,0x00,0x00,0x00,0x06 从地址0连读6个超过了5个数据则退出
{
switch(Uart_Buffer[5])
{ // 起始地址Uart_Buffer[3]
case 1: DATA01_TX[3]=DATA_Status_code[Uart_Buffer[3]];break;//只读一个状态
case 2: DATA01_TX[3]=DATA_Status_code[Uart_Buffer[3]+1]*2+DATA_Status_code[Uart_Buffer[3]];break;//只读两个个状态
case 3: DATA01_TX[3]=DATA_Status_code[Uart_Buffer[3]+2]*4+DATA_Status_code[Uart_Buffer[3]+1]*2+DATA_Status_code[Uart_Buffer[3]];break;//只读三个状态
case 4: DATA01_TX[3]=DATA_Status_code[Uart_Buffer[3]+3]*8+DATA_Status_code[Uart_Buffer[3]+2]*4+DATA_Status_code[Uart_Buffer[3]+1]*2+DATA_Status_code[Uart_Buffer[3]];break;//只读四个状态
case 5: DATA01_TX[3]=DATA_Status_code[Uart_Buffer[3]+4]*16+DATA_Status_code[Uart_Buffer[3]+3]*8+DATA_Status_code[Uart_Buffer[3]+2]*4+DATA_Status_code[Uart_Buffer[3]+1]*2+DATA_Status_code[Uart_Buffer[3]];break;//只读五个状态
default:break;
}
DATA01_TX[4]=crc16(DATA01_TX,4)>>8;
DATA01_TX[5]=crc16(DATA01_TX,4) & 0xFF;
DE_HIGH;
usart_send_array(DATA01_TX,6);
DE_LOW;
}
}
else if (Uart_Buffer[1]==6)// 功能码06 写状态 与 该从机地址
{
if (Uart_Buffer[3]<5 && (Uart_Buffer[5]==0||Uart_Buffer[5]==1)) // 地址小于5 && 改的数据只能为0和1
{
DATA_Status_code[Uart_Buffer[3]]=Uart_Buffer[5];//把值赋值给需要修改的地址
DATA06_TX[3]=Uart_Buffer[3];//赋值发送地址
DATA06_TX[5]=DATA_Status_code[Uart_Buffer[3]];//赋值改的数据
}
else if (Uart_Buffer[3]==0x20 && Uart_Buffer[5]<128)// 修改地址 && 小于128
{
addr_slave=Uart_Buffer[5]; // 修改地址
DATA06_TX[3]=Uart_Buffer[3];// 赋值发送地址
DATA06_TX[0]=addr_slave;
}
DATA06_TX[6]=crc16(DATA06_TX,6)>>8;
DATA06_TX[7]=crc16(DATA06_TX,6) & 0xFF;
DE_HIGH;
usart_send_array(DATA06_TX,8);
DE_LOW;
}
else if (Uart_Buffer[1]==3)// 功能码03 读数据
{
if (Uart_Buffer[3]>=0x10&&Uart_Buffer[3]<=0x16&&Uart_Buffer[5]-1<=0x16-Uart_Buffer[3])//不超出地址&&不超过最大个数
{
DATA03_TX[2]=Uart_Buffer[5]*2; // 发送字节数 每个数据两个字节
for (x=0;x>8; // 校验高位
DATA03_TX[Uart_Buffer[5]*2+4]=crc16(DATA03_TX,Uart_Buffer[5]*2+3) & 0xFF; // 校验低位
DE_HIGH;
usart_send_array(DATA03_TX,Uart_Buffer[5]*2+5); // 发送
DE_LOW;
}
}
}
}
clc_Uart_Buffer(); // 清串口缓存
}
int main()
{
init_USART(); // USART 初始化
Time0_init(); // 定时器0初始化
DE_OUT;
DE_LOW ;
while (1)
{
DATA01_TX[0]=addr_slave;
DATA03_TX[0]=addr_slave;
DATA06_TX[0]=addr_slave;
if (star_parse_flag==1)
{
star_parse_flag=0;
modbus_parse(); // modbus 数据解析
}
}
}