各位大佬,用stc32F芯片Modbus RTU通信协议该怎么写
想学习一下写modbus RTU通信协议和数据采集,但不知道思路应该怎么样,无从下手【新提醒】视频回放-ModBus从入门到实战 - 串行口,DMA支持的4组串口,RS232,RS485 - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)
本帖最后由 qrscn 于 2023-11-21 17:10 编辑
大佬们,这个modbus范例程序,我用stc8h8k64u芯片来测试需要修改代码吗,我烧写进去用串口调试助手测试,发送数据过去没有反应,我用的usb转485模块,然后杜邦线连到单片机对应的io口 qrscn 发表于 2023-11-21 16:50
大佬们,这个modbus范例程序,我用stc8h8k64u芯片来测试需要修改代码吗,我烧写进去用串口调试助手测试,发 ...
可以参考下**********
/**************************************************************************/
/******** 读寄存器操作**************************************************/
/**************************************************************************/
void Read_Reg()
{
uchar i,x;
uint CRC_DATA;
Modbus.Reg_addr = (UART1.RX_data << 8) + UART1.RX_data; //寄存器地址
Modbus.Reg_number = (UART1.RX_data << 8) + UART1.RX_data; //寄存器个数
if( Modbus.Reg_number >= 0x007D)
{
return ; //返回错误码
}
if(( Modbus.Reg_addr < 0x0060) ||(Modbus.Reg_addr > 0x00FF)) //寄存器地址范围
{
return ; //返回错误码
}
x = 0;
UART1.TX_data = 0X01; //地址
UART1.TX_data = UART1.RX_data; //功能码
UART1.TX_data = Modbus.Reg_number*2; //数据个数
for(i = (Modbus.Reg_addr-0X0060); i < ((Modbus.Reg_addr-0X0060)+Modbus.Reg_number); i++ )
{
UART1.TX_data = Modbus.Read_buff_data >> 8;
UART1.TX_data = Modbus.Read_buff_data ;
}
CRC_DATA = GetCRC16( UART1.TX_data , x);
UART1.TX_data = CRC_DATA >> 8;
UART1.TX_data = CRC_DATA ;
while( UART1.TX_Busy ); //串口空闲
UART1.TX_Busy = 1; //串口置1 忙标志
UART1.TX_Len = 0;
UART1.TX_Count = x; //发送数据位数
Enable_485_1_TX();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); //空操作 短延时
SBUF = UART1.TX_data; //发送数据 中断发送
}
/**************************************************************************/
/******** 写单个或多个寄存器数据**************************************************/
/**************************************************************************/
void Write_Reg()
{
uchar i,x;
uchar addr; //数组位置
uint CRC_DATA; //CRC数据
dat_uiChange; //数据转换
fucDataBuf databuf0;
fucDataBuf databuf1; //结构体定义
float f;
if(( Modbus.Reg_addr < 0x0060) ||(Modbus.Reg_addr > 0x00FF)) //寄存器地址范围
{
return ; //返回错误码
}
else
{
addr = Modbus.Reg_addr - 0x0060; //获取存储地址 = 寄存器地址-偏移量
if( Modbus.Cmd== 0x06 ) //写单个寄存器
{
Change.dat_uchar = UART1.RX_data;
Change.dat_uchar = UART1.RX_data; //数据转换
Modbus.Write_buff_data[ addr ] = Change.dat_uint; //将数据写入对应寄存器位置
// Modbus.Read_buff_data[ addr ] = Change.dat_uint;
}
else if( Modbus.Cmd== 0x10 ) //写多个寄存器
{
Modbus.Reg_number =UART1.RX_data;
Modbus.Reg_number = Modbus.Reg_number << 8;
Modbus.Reg_number = Modbus.Reg_number + UART1.RX_data; //寄存器个数
Modbus.Data_number = UART1.RX_data; //数据长数
if( Modbus.Reg_number >= 0x007D) //判断寄存器个数
{
return ; //返回错误码
}
else
{
x = 7; //临时变量,数据从第七位开始
for( i = addr; i <( addr + Modbus.Reg_number ); i++)
{
Change.dat_uchar = UART1.RX_data;
Change.dat_uchar = UART1.RX_data; //数据转换
Modbus.Write_buff_data = Change.dat_uint; //将数据写入对应寄存器位置
//Modbus.Read_buff_data = Change.dat_uint;
}
}
}
switch( Modbus.Reg_addr ) //根据下发寄存器执行相应的功能
{
case 0x0064:MK.Cmd_flag = 1; MK.Cmd_Mode = 1; break; //修改地址
case 0x0068:MK.Cmd_flag = 1; MK.Cmd_Mode = 2; break; //标定零点
case 0x006E:MK.count += 3 ; break; //标定系数1
case 0x0070:MK.count += 5 ; break; //标定系数2
case 0x0076:MK.Cmd_flag = 1; MK.Cmd_Mode = 10; break; //清密
case 0x007E:EA = 0; //标定协议改变,程序重启
Protocol = Modbus.Write_buff_data;
IapEraseSector(EEPROM_Protocol); //扇区擦除
IapProgramByte(EEPROM_Protocol,(Protocol<<8)); IapProgramByte(EEPROM_Protocol+1,Protocol);//存储
IAP_CONTR = 0X60; //重启
P36 = P37 = 0;
while(1); //死循环
break;
/***************************以下为多点标定 ******************************************************/
case 0x0080: databuf0.ucDataBuf = Modbus.Write_buff_data; // 0x0080 系数1 寄存器
databuf0.ucDataBuf = Modbus.Write_buff_data; // 0X0081
f = databuf0.fDataBuf;
databuf0.fDataBuf = f/10000.0; //系数缩小10000倍
Modbus.Write_buff_data = databuf0.ucDataBuf;
Modbus.Write_buff_data = databuf0.ucDataBuf;
MK.Cmd_flag = 1; MK.Cmd_Mode = 4;
break;
case 0x0082: databuf0.ucDataBuf = Modbus.Write_buff_data; // 0x0082 系数2 寄存器
databuf0.ucDataBuf = Modbus.Write_buff_data; // 0X0083
f = databuf0.fDataBuf;
databuf0.fDataBuf = f/10000.0; //系数缩小10000倍
Modbus.Write_buff_data = databuf0.ucDataBuf;
Modbus.Write_buff_data = databuf0.ucDataBuf;
MK.Cmd_flag = 1; MK.Cmd_Mode = 5;
break;
case 0x0084: databuf0.ucDataBuf = Modbus.Write_buff_data; // 0x0084 系数3 寄存器
databuf0.ucDataBuf = Modbus.Write_buff_data; // 0X0085
f = databuf0.fDataBuf;
databuf0.fDataBuf = f/10000.0; //系数缩小10000倍
Modbus.Write_buff_data = databuf0.ucDataBuf;
Modbus.Write_buff_data = databuf0.ucDataBuf;
MK.Cmd_flag = 1; MK.Cmd_Mode = 6;
break;
case 0x0086: databuf0.ucDataBuf = Modbus.Write_buff_data; // 0x0086 系数4 寄存器
databuf0.ucDataBuf = Modbus.Write_buff_data; // 0X0087
f = databuf0.fDataBuf;
databuf0.fDataBuf = f/10000.0; //系数缩小10000倍
Modbus.Write_buff_data = databuf0.ucDataBuf;
Modbus.Write_buff_data = databuf0.ucDataBuf;
MK.Cmd_flag = 1; MK.Cmd_Mode = 7;
break;
case 0x0088: databuf0.ucDataBuf = Modbus.Write_buff_data; // 0x0088 系数5 寄存器
databuf0.ucDataBuf = Modbus.Write_buff_data; // 0X0089
f = databuf0.fDataBuf;
databuf0.fDataBuf = f/10000.0; //系数缩小10000倍
Modbus.Write_buff_data = databuf0.ucDataBuf;
Modbus.Write_buff_data = databuf0.ucDataBuf;
MK.Cmd_flag = 1; MK.Cmd_Mode = 8;
break;
case 0x008A: databuf0.ucDataBuf = Modbus.Write_buff_data; // 0x008A 系数6 寄存器
databuf0.ucDataBuf = Modbus.Write_buff_data; // 0X008B
f = databuf0.fDataBuf;
databuf0.fDataBuf = f/10000.0; //系数缩小10000倍
Modbus.Write_buff_data = databuf0.ucDataBuf;
Modbus.Write_buff_data = databuf0.ucDataBuf;
MK.Cmd_flag = 1; MK.Cmd_Mode = 9;
break;
default: break;
}
if(MK.count==8)
{
MK.Cmd_flag = 1;
MK.Cmd_Mode = 3;
MK.count =0;
//系数1
databuf0.ucDataBuf = Modbus.Write_buff_data; // 0x006E 系数1 寄存器
databuf0.ucDataBuf = Modbus.Write_buff_data; // 0X006F
Modbus.xishu_1 = databuf0.fDataBuf;
//系数2
databuf1.ucDataBuf = Modbus.Write_buff_data; //0X0070 系数2 寄存器
databuf1.ucDataBuf = Modbus.Write_buff_data; //0X0071
Modbus.xishu_2 = databuf1.fDataBuf;
//缩小2次10000倍
databuf0.fDataBuf = Modbus.xishu_1/100000000.0;
databuf1.fDataBuf = Modbus.xishu_2/100000000.0;
//系数1
Modbus.Write_buff_data = databuf0.ucDataBuf;
Modbus.Write_buff_data = databuf0.ucDataBuf;
//系数2
Modbus.Write_buff_data = databuf1.ucDataBuf;
Modbus.Write_buff_data = databuf1.ucDataBuf;
}
}
for( i = 0; i < 6; i++) //Modbus 返回值
{
UART1.TX_data = UART1.RX_data;
}
CRC_DATA = GetCRC16( UART1.TX_data , i ); //CRC计算
UART1.TX_data = CRC_DATA >> 8;
UART1.TX_data = CRC_DATA ;
while( UART1.TX_Busy ); //串口1空闲
UART1.TX_Busy = 1; //串口置1 忙标志
UART1.TX_Len = 0;
UART1.TX_Count = i;
Enable_485_1_TX();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
SBUF = UART1.TX_data; //发送数据 中断发送 //标志赋0
}
/****************** CRC 计算 ******************************************************/
unsigned int GetCRC16(unsigned char *ptr,unsigned char len)
{
unsigned int index;
unsigned char crch = 0xFF;//高CRC字节
unsigned char crcl = 0xFF;//低CRC字节
unsigned char code TabH[] = {//CRC高位字节值表
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
} ;
unsigned char code TabL[] = {//CRC低位字节值表
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40
} ;
while (len--)//计算指定长度的CRC
{
index = crch ^ *ptr++;
crch = crcl ^ TabH;
crcl = TabL;
}
return ((crch<<8) | crcl);
} qrscn 发表于 2023-11-21 16:50
大佬们,这个modbus范例程序,我用stc8h8k64u芯片来测试需要修改代码吗,我烧写进去用串口调试助手测试,发 ...
代码发出来看看呗,这个东西其实简单
页:
[1]