找回密码
 立即注册
查看: 1424|回复: 4

各位大佬,用stc32F芯片Modbus RTU通信协议该怎么写

[复制链接]

1

主题

1

回帖

31

积分

新手上路

积分
31
发表于 2023-10-26 22:50:18 来自手机 | 显示全部楼层 |阅读模式
想学习一下写modbus RTU通信协议和数据采集,但不知道思路应该怎么样,无从下手
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:57
  • 最近打卡:2025-05-04 08:52:05

718

主题

1万

回帖

1万

积分

管理员

积分
15666
发表于 2023-10-27 17:56:14 | 显示全部楼层
回复 支持 1 反对 0

使用道具 举报 送花

1

主题

1

回帖

31

积分

新手上路

积分
31
发表于 2023-11-21 16:50:51 来自手机 | 显示全部楼层
本帖最后由 qrscn 于 2023-11-21 17:10 编辑

大佬们,这个modbus范例程序,我用stc8h8k64u芯片来测试需要修改代码吗,我烧写进去用串口调试助手测试,发送数据过去没有反应,我用的usb转485模块,然后杜邦线连到单片机对应的io口
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:375
  • 最近打卡:2025-04-26 15:51:33
已绑定手机

27

主题

301

回帖

822

积分

高级会员

积分
822
发表于 2023-11-23 17:10:22 | 显示全部楼层
qrs*** 发表于 2023-11-21 16:50
大佬们,这个modbus范例程序,我用stc8h8k64u芯片来测试需要修改代码吗,我烧写进去用串口调试助手测试,发 ...


可以参考下**********


/**************************************************************************/
/******** 读寄存器操作  **************************************************/
/**************************************************************************/
void Read_Reg()
{
        uchar i,x;
        uint CRC_DATA;
       
        Modbus.Reg_addr = (UART1.RX_data[2] << 8) + UART1.RX_data[3];                        //寄存器地址
        Modbus.Reg_number = (UART1.RX_data[4] << 8) + UART1.RX_data[5];                        //寄存器个数
        if( Modbus.Reg_number >= 0x007D)
        {
                 return ;                //返回错误码
        }
        if(( Modbus.Reg_addr < 0x0060) ||  (Modbus.Reg_addr > 0x00FF))                //寄存器地址范围
        {
                 return ;                //返回错误码
        }
               
        x = 0;
        UART1.TX_data[x++] = 0X01;                                                                                        //地址
        UART1.TX_data[x++] = UART1.RX_data[1];                                                                //功能码
        UART1.TX_data[x++] = Modbus.Reg_number*2;                                                        //数据个数
    for(i = (Modbus.Reg_addr-0X0060); i < ((Modbus.Reg_addr-0X0060)+Modbus.Reg_number); i++ )                       
        {
                UART1.TX_data[x++] = Modbus.Read_buff_data >> 8;
                UART1.TX_data[x++] = Modbus.Read_buff_data ;
        }
        CRC_DATA = GetCRC16( UART1.TX_data , x);
        UART1.TX_data[x++] = CRC_DATA >> 8;
        UART1.TX_data[x++] = 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[UART1.TX_Len];                                                                        //发送数据 中断发送                                                                                                       
}


/**************************************************************************/
/******** 写单个或多个寄存器数据  **************************************************/
/**************************************************************************/
void Write_Reg()
{
        uchar i,x;
        uchar addr;                                                        //数组位置
        uint CRC_DATA;                                                //CRC数据
        dat_ui  Change;                                                //数据转换
        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[0] = UART1.RX_data[4];
                        Change.dat_uchar[1] = UART1.RX_data[5];                                                                //数据转换
                        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[4];
                        Modbus.Reg_number = Modbus.Reg_number << 8;
                        Modbus.Reg_number = Modbus.Reg_number + UART1.RX_data[5];                                        //寄存器个数
                        Modbus.Data_number = UART1.RX_data[6];                                                                        //数据长数
                        if( Modbus.Reg_number >= 0x007D)                                                                         //判断寄存器个数
                        {
                                return ;                        //返回错误码
                        }               
                        else
                        {
                                x = 7;                                //临时变量,数据从第七位开始
                                for( i = addr; i <  ( addr + Modbus.Reg_number ); i++)                       
                                {
                                        Change.dat_uchar[0] = UART1.RX_data[x++];
                                        Change.dat_uchar[1] = UART1.RX_data[x++];                                                        //数据转换                               
                                        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[Pro_Name_Reg];
                                                  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[0] = Modbus.Write_buff_data[W_Xs1_H_Reg];                 // 0x0080   系数1 寄存器
                                                        databuf0.ucDataBuf[1] = Modbus.Write_buff_data[W_Xs1_L_Reg];                // 0X0081               
                                                        f = databuf0.fDataBuf;
                                                        databuf0.fDataBuf = f/10000.0;                                        //系数缩小10000倍
                                                        Modbus.Write_buff_data[W_Xs1_H_Reg] = databuf0.ucDataBuf[0];                
                                                        Modbus.Write_buff_data[W_Xs1_L_Reg] = databuf0.ucDataBuf[1];
                                                        MK.Cmd_flag = 1; MK.Cmd_Mode = 4;                                        
                                                        break;
                        case 0x0082:          databuf0.ucDataBuf[0] = Modbus.Write_buff_data[W_Xs2_H_Reg];                 // 0x0082   系数2 寄存器
                                                        databuf0.ucDataBuf[1] = Modbus.Write_buff_data[W_Xs2_L_Reg];                // 0X0083               
                                                        f = databuf0.fDataBuf;
                                                        databuf0.fDataBuf = f/10000.0;                                        //系数缩小10000倍
                                                        Modbus.Write_buff_data[W_Xs2_H_Reg] = databuf0.ucDataBuf[0];                
                                                        Modbus.Write_buff_data[W_Xs2_L_Reg] = databuf0.ucDataBuf[1];
                                                        MK.Cmd_flag = 1; MK.Cmd_Mode = 5;
                                                        break;
                        case 0x0084:          databuf0.ucDataBuf[0] = Modbus.Write_buff_data[W_Xs3_H_Reg];                 // 0x0084   系数3 寄存器
                                                        databuf0.ucDataBuf[1] = Modbus.Write_buff_data[W_Xs3_L_Reg];                // 0X0085               
                                                        f = databuf0.fDataBuf;
                                                        databuf0.fDataBuf = f/10000.0;                                        //系数缩小10000倍
                                                        Modbus.Write_buff_data[W_Xs3_H_Reg] = databuf0.ucDataBuf[0];                
                                                        Modbus.Write_buff_data[W_Xs3_L_Reg] = databuf0.ucDataBuf[1];
                                                        MK.Cmd_flag = 1; MK.Cmd_Mode = 6;
                                                        break;
                        case 0x0086:          databuf0.ucDataBuf[0] = Modbus.Write_buff_data[W_Xs4_H_Reg];                 // 0x0086   系数4 寄存器
                                                        databuf0.ucDataBuf[1] = Modbus.Write_buff_data[W_Xs4_L_Reg];                // 0X0087               
                                                        f = databuf0.fDataBuf;
                                                        databuf0.fDataBuf = f/10000.0;                                        //系数缩小10000倍
                                                        Modbus.Write_buff_data[W_Xs4_H_Reg] = databuf0.ucDataBuf[0];                
                                                        Modbus.Write_buff_data[W_Xs4_L_Reg] = databuf0.ucDataBuf[1];
                                                        MK.Cmd_flag = 1; MK.Cmd_Mode = 7;        
                                                        break;
                        case 0x0088:          databuf0.ucDataBuf[0] = Modbus.Write_buff_data[W_Xs5_H_Reg];                 // 0x0088   系数5 寄存器
                                                        databuf0.ucDataBuf[1] = Modbus.Write_buff_data[W_Xs5_L_Reg];                // 0X0089               
                                                        f = databuf0.fDataBuf;
                                                        databuf0.fDataBuf = f/10000.0;                                        //系数缩小10000倍
                                                        Modbus.Write_buff_data[W_Xs5_H_Reg] = databuf0.ucDataBuf[0];                
                                                        Modbus.Write_buff_data[W_Xs5_L_Reg] = databuf0.ucDataBuf[1];
                                                        MK.Cmd_flag = 1; MK.Cmd_Mode = 8;                
                                                        break;
                        case 0x008A:          databuf0.ucDataBuf[0] = Modbus.Write_buff_data[W_Xs6_H_Reg];                 // 0x008A   系数6 寄存器
                                                        databuf0.ucDataBuf[1] = Modbus.Write_buff_data[W_Xs6_L_Reg];                // 0X008B               
                                                        f = databuf0.fDataBuf;
                                                        databuf0.fDataBuf = f/10000.0;                                        //系数缩小10000倍
                                                        Modbus.Write_buff_data[W_Xs6_H_Reg] = databuf0.ucDataBuf[0];                
                                                        Modbus.Write_buff_data[W_Xs6_L_Reg] = databuf0.ucDataBuf[1];
                                                        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[0] = Modbus.Write_buff_data[W_Bdxs1_H_Reg];                 // 0x006E   系数1 寄存器
                        databuf0.ucDataBuf[1] = Modbus.Write_buff_data[W_Bdxs1_L_Reg];                // 0X006F               
                        Modbus.xishu_1 = databuf0.fDataBuf;
                        //系数2
                        databuf1.ucDataBuf[0] = Modbus.Write_buff_data[W_Bdxs2_H_Reg];                //0X0070        系数2 寄存器
                        databuf1.ucDataBuf[1] = Modbus.Write_buff_data[W_Bdxs2_L_Reg];                //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[W_Bdxs1_H_Reg] = databuf0.ucDataBuf[0];
                        Modbus.Write_buff_data[W_Bdxs1_L_Reg] = databuf0.ucDataBuf[1];
                        //系数2
                        Modbus.Write_buff_data[W_Bdxs2_H_Reg] = databuf1.ucDataBuf[0];
                        Modbus.Write_buff_data[W_Bdxs2_L_Reg] = databuf1.ucDataBuf[1];
                }
        }
        for( i = 0; i < 6; i++)                                                                                                                //Modbus 返回值
        {
                UART1.TX_data = UART1.RX_data;
        }               
        CRC_DATA = GetCRC16( UART1.TX_data , i );                                                                        //CRC计算
        UART1.TX_data[i++] = CRC_DATA >> 8;
        UART1.TX_data[i++] = 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[UART1.TX_Len];                                                                                        //发送数据 中断发送                                                                                                                        //标志赋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[index];
        crcl = TabL[index];
    }
   
    return ((crch<<8) | crcl);  
}
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:375
  • 最近打卡:2025-04-26 15:51:33
已绑定手机

27

主题

301

回帖

822

积分

高级会员

积分
822
发表于 2023-11-30 08:35:33 | 显示全部楼层
qrs*** 发表于 2023-11-21 16:50
大佬们,这个modbus范例程序,我用stc8h8k64u芯片来测试需要修改代码吗,我烧写进去用串口调试助手测试,发 ...

代码发出来看看呗,这个东西其实简单
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-4 23:04 , Processed in 0.172929 second(s), 77 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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