找回密码
 立即注册
查看: 183|回复: 3

STC32G8K64,485通讯CRC16校验通不过,89C52移植协议STC32GCRC校验不过

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2026-01-12 10:53:01
已绑定手机

1

主题

1

回帖

7

积分

新手上路

积分
7
发表于 2026-1-12 10:53:01 | 显示全部楼层 |阅读模式
STC32G8K64,485通讯CRC16校验通不过,89C52移植协议STC32GCRC校验不过,在89c可以校验可以通过,移植到STC32G,就校验不过,都不知道哪里出问题了




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);  
}

#include        "config.h"

bit flagBuzzOn;
bit flagOnceTxd = 0;  //单次发送完成标志,即发送完一个字节
bit cmdArrived = 0;   //命令到达标志,即接收到上位机下发的命令

unsigned char cntRxd = 0;
unsigned char pdata bufRxd[40]; //串口接收缓冲区static
unsigned char regGroup[5];  //Modbus寄存器组,地址为0x00~0x04


void DelayX10us(unsigned int t)  //软件延时函数,延时时间(t*10)us
{
    do {
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
    } while (--t);
}

void Delay100us(void)        //@24.000MHz
{
        unsigned long edata i;

        _nop_();
        _nop_();
        _nop_();
        i = 598UL;
        while (i) i--;
}

void Delay800us(void)        //@24.000MHz
{
        unsigned long edata i;

        _nop_();
        _nop_();
        _nop_();
        i = 4798UL;
        while (i) i--;
}
/* 串口动作函数,根据接收到的命令帧执行响应的动作
   buf-接收到的命令帧指针,len-命令帧长度 */
//void UartAction(unsigned char *buf, unsigned char len)
//{
//    //在接收到的数据帧后添加换车换行符后发回
//    buf[len++] = '\r';
//    buf[len++] = '\n';
//    UartWrite1(buf, len);
//}

unsigned char UartRead(unsigned char *buf, unsigned char len) //串口数据读取函数,数据接收指针buf,读取数据长度len,返回值为实际读取到的数据长度
{
    unsigned char i;
   
    if (len > cntRxd) //读取长度大于接收到的数据长度时,
    {
        len = cntRxd; //读取长度设置为实际接收到的数据长度
    }
    for (i=0; i<len; i++) //拷贝接收到的数据
    {
        *buf = bufRxd;
        buf++;
    }
                DelayX10us(1);  //等待最后的停止位完成,延时时间由波特率决定
    cntRxd = 0;  //清零接收计数器
   
    return len;  //返回实际读取长度
}
void UartWrite(unsigned char *buf, unsigned char len) //串口数据写入函数,即串口发送函数,待发送数据指针buf,数据长度len
{
    RS485_DIR = 1;  //RS485设置为发送
    while (len--)   //发送数据
    {
        flagOnceTxd = 0;
                        TX4_write2buff(*buf); //发送文本一个字节数据               
      *buf++;
        while (!flagOnceTxd);
    }
    delay_ms(2);  //等待最后的停止位完成,延时时间由波特率决定
    RS485_DIR = 0;  //RS485设置为接收
}

void UartDriver() //串口驱动函数,检测接收到的命令并执行相应动作
{
    unsigned char i;
    unsigned char cnt;
    unsigned char len;
    unsigned char buf[30];
    unsigned char str[4];
    static unsigned int  crc;
    static unsigned char crch, crcl;

    if (cmdArrived) //有命令到达时,读取处理该命令
    {
        cmdArrived = 0;
        len = UartRead(buf, sizeof(buf)); //将接收到的命令读取到缓冲区中
                          UartWrite(buf,len);
        if (buf[0] == 0x01)  //核对地址以决定是否响应命令,本例中的本机地址为0x01
        {
                        crc = GetCRC16(buf, len-2);   // 3. 计算CRC
            crch = crc >> 8;
            crcl = crc & 0xFF;
                                                //delay_ms(1);
                                          //DelayX10us(100);
                                          Delay800us();
           if ((buf[len-2] == crch) && (buf[len-1] == crcl)) //判断CRC校验是否正确
            {
                                                                 printf("CRC计算结果: ");
                                                    printf("0x%02X 0x%02X\r\n",crch,crcl); // 打印高字节 0x48, 打印低字节 0x0A
                                                          delay_ms(50);
                                                                           //UartWrite(mor,8);
                switch (buf[1]) //按功能码执行操作
                {
                    case 0x03:  //读取一个或连续的寄存器
                        if ((buf[2] == 0x00) && (buf[3] <= 0x05)) //寄存器地址支持0x0000~0x0005
                        {
                            if (buf[3] <= 0x04)
                            {
                                i = buf[3];      //提取寄存器地址
                                cnt = buf[5];    //提取待读取的寄存器数量
                                buf[2] = cnt*2;  //读取数据的字节数,为寄存器数*2,因Modbus定义的寄存器为16位
                                len = 3;
                                while (cnt--)
                                {
                                    buf[len++] = 0x00;          //寄存器高字节补0
                                    buf[len++] = regGroup[i++]; //寄存器低字节
                                }
                            }
                            else  //地址0x05为蜂鸣器状态
                            {
                                buf[2] = 2;  //读取数据的字节数
                                buf[3] = 0x00;
                                buf[4] = flagBuzzOn;
                                len = 5;
                            }
                            break;
                        }
                        else  //寄存器地址不被支持时,返回错误码
                        {
                            buf[1] = 0x83;  //功能码最高位置1
                            buf[2] = 0x02;  //设置异常码为02-无效地址
                            len = 3;
                            break;
                        }
                        
                    case 0x06:  //写入单个寄存器
                        if ((buf[2] == 0x00) && (buf[3] <= 0x05)) //寄存器地址支持0x0000~0x0005
                        {
                            if (buf[3] <= 0x04)
                            {
                                i = buf[3];             //提取寄存器地址
                                regGroup = buf[5];   //保存寄存器数据
                                cnt = regGroup >> 4; //显示到液晶上
                                if (cnt >= 0xA)
                                    str[0] = cnt - 0xA + 'A';
                                else
                                    str[0] = cnt + '0';
                                cnt = regGroup & 0x0F;
                                if (cnt >= 0xA)
                                    str[1] = cnt - 0xA + 'A';
                                else
                                    str[1] = cnt + '0';
                                str[2] = '\0';
                                //LcdShowStr(i*3, 0, str);
                            }
                            else  //地址0x05为蜂鸣器状态
                            {
                                flagBuzzOn = (bit)buf[5]; //寄存器值转换为蜂鸣器的开关
                                                                                                                          P36 ^=(bit)buf[5]; //寄存器值转换为蜂鸣器的开关
                            }
                            len -= 2; //长度-2以重新计算CRC并返回原帧
                            break;
                        }
                        else  //寄存器地址不被支持时,返回错误码
                        {
                            buf[1] = 0x86;  //功能码最高位置1
                            buf[2] = 0x02;  //设置异常码为02-无效地址
                            len = 3;
                            break;
                        }
                        
                    default:  //其它不支持的功能码
                        buf[1] |= 0x80;  //功能码最高位置1
                        buf[2] = 0x01;   //设置异常码为01-无效功能
                        len = 3;
                        break;
                }
                crc = GetCRC16(buf, len); //计算CRC校验值
                buf[len++] = crc >> 8;    //CRC高字节
                buf[len++] = crc & 0xFF;  //CRC低字节
                UartWrite(buf, len);      //发送响应帧
            }
        }
    }
}

void UartRxMonitor(unsigned char ms)  //串口接收监控函数
{
    static unsigned char cntbkp = 0;
    static unsigned char idletmr = 0;

    if (cntRxd > 0)  //接收计数器大于零时,监控总线空闲时间
    {
        if (cntbkp != cntRxd)  //接收计数器改变,即刚接收到数据时,清零空闲计时
        {
            cntbkp = cntRxd;
            idletmr = 0;
        }
        else
        {
            if (idletmr < MODBUS_KOZ)  //接收计数器未改变,即总线空闲时,累积空闲时间
            {
                idletmr += ms;
                if (idletmr >= MODBUS_KOZ)  //空闲时间超过4个字节传输时间即认为一帧命令接收完毕
                {
                    cmdArrived = 1; //设置命令到达标志
                                                                          //UartWrite(0xAA, 1);      //发送响应帧
                }
            }
        }
    }
    else
    {
        cntbkp = 0;
    }
}

回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:725
  • 最近打卡:2026-03-30 12:09:34
已绑定手机

97

主题

7246

回帖

1万

积分

超级版主

积分
13798
发表于 2026-1-12 12:17:40 | 显示全部楼层
全局变量不要声明时赋值
没有STARTUP.A251,也不要假设变量默认为0,必须给初始值
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2026-01-12 10:53:01
已绑定手机

1

主题

1

回帖

7

积分

新手上路

积分
7
发表于 2026-1-12 12:29:17 | 显示全部楼层
Debu*** 发表于 2026-1-12 12:17
全局变量不要声明时赋值
没有STARTUP.A251,也不要假设变量默认为0,必须给初始值
...

不明白?可以讲明白,全局变量不要赋值0?,这个有影响?

点评

全局变量在main里面开头赋值  详情 回复 发表于 2026-1-12 13:49
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:725
  • 最近打卡:2026-03-30 12:09:34
已绑定手机

97

主题

7246

回帖

1万

积分

超级版主

积分
13798
发表于 2026-1-12 13:49:41 | 显示全部楼层
mopc*** 发表于 2026-1-12 12:29
不明白?可以讲明白,全局变量不要赋值0?,这个有影响?

全局变量在main里面开头赋值
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-4-4 17:41 , Processed in 0.125688 second(s), 59 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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