对串口发来的字符串,进行CRC校验和数据提取

发布于:2022-08-08 ⋅ 阅读:(378) ⋅ 点赞:(0)

/*==========================================
串口接收CRC校验(程翔宇 chanceller@163.com)
==========================================*/

#include <stdio.h>
#include <string.h>

//对串口接收的数据进行自后向前的移位存储
void shiftMemory(unsigned char *PBuf,unsigned char BufSize,unsigned char bufRec)
{        
        memmove(PBuf,PBuf+1,BufSize-1);//前面的字符左移一位
        memset(PBuf+BufSize-1,bufRec,1);//末端填充新字符
        //memcpy(PBuf+BufSize-1,&bufRec,1);//末端填充新字符    
}

//CRC校验程序
unsigned short CrcCheck(unsigned char*bufOut,unsigned char *buf,unsigned char length)
{
    unsigned short tmp,CRC;
    unsigned char i,j,CRCHi,CRCLo;    
    
     memcpy(bufOut,buf,length);    //前端存储原字符
    bufOut[length+2]='\0';        //后端存储结束符                 
    
    //CRC校验核心代码
    CRC=0xFFFF;
    for(i=0; i<length; i++)
    {        
                
        CRC=buf[i]^CRC;
            
        for(j=0;j<8;j++)
        {    
            tmp=CRC&0x0001;
            CRC=CRC>>1;
            if(tmp)
            CRC=CRC^0xA001;
        }    
    }    
    CRCLo = CRC & 0x00FF;
    CRCHi = CRC >> 8;
    
    bufOut[length]=CRCLo;    //CRC校验码存在原字符后面(低前高后)
    bufOut[length+1]=CRCHi;    //CRC校验码存在原字符后面(低前高后)
    
    return CRC;    //返回CRC校验码(高前低后)
}

/*========================================================
对移位寄存器中的字符串,进行CRC校验后,输出有效数据
    PseRec有效数据输出
    RecSt有效数据起始地址
    RecLe有效数据字节长度
    CrcSt校验位起始地址
    CrcLe校验位字节长度
    PserBuf移位寄存器首地址
========================================================*/
unsigned char seRecCrc(unsigned char *PseRec,unsigned char RecSt,unsigned char RecLe,unsigned char *PserBuf,unsigned char CrcSt,unsigned char CrcLe)
{
    unsigned char i;

    unsigned char buf2[CrcSt+CrcLe+3];    //定义二次校验字节数组
    unsigned short crc2;                //定义二次校验码存储变量

    crc2=CrcCheck(buf2,PserBuf,CrcSt+2);    //二次校验
    
    if(crc2==0)    //二次校验码为零,校验有效
    {
        memcpy(PseRec,PserBuf+RecSt,RecLe);//拷贝有效数据
        return 1;//校验成功
    }
    else
    {
        return 0;//校验失败
    }
}


int main()
{
    unsigned char i,j;
    
    //模拟串口收到的数据
    unsigned char serChar[36] =    {    
        'x','y','1',0x41,0x42,0x61,0x62,0x89,0x3B,'\r','\n','\0',
        'x','z','1',0x43,0x44,0x63,0x64,0xE9,0xD3,'\r','\n','\0',
        'x','a','1',0x45,0x46,0x65,0x66,0xC9,0x11,'\r','\n','\0',
        }; 
        
    unsigned char bufRec;//串口收到的字节
    
    unsigned char BufSize=12;//串口移位缓存大小(9(=7+2)个有效字节)
    unsigned char serBuf[BufSize];//串口移位缓存
    
    unsigned char ch[3][2]={{0x78,0x79},{'x','z'},"xa"};//识别分割字符串(命令头)
    
    //共用体。通过存储的有效字节DP[4],获得实际数据neData
    union dataInt{
        unsigned char DP[4];
        int neData;
    }DataRec;
    
    
    for(i=0;i<36;i++)//模拟串口中断程序接收单字节程序
    {    
        unsigned char CrcS=0;//校验是否成功标志
    
        bufRec=serChar[i];//相当于:bufRec=SBUF,接收串口字符        
        shiftMemory(serBuf,BufSize,bufRec);//自后向前,移位存储        
        
        if(strncmp(serBuf,ch[0],2)==0)//判断是否收到命令头ch[0]
        {
            //CRC校验,并获得有效数据,存放在共用体中
            CrcS=seRecCrc(DataRec.DP,3,4,serBuf,7,2);
            
            //显示有效数据
            if (CrcS)    //CRC校验成功
            {                
                printf("\n收到CH[0]命令\n提取的有效数据:");
                for(j=0;j<4;j++)
                {    
                    printf("%02x ",DataRec.DP[j]);//低前高后
                }
                printf("\n");
                
                printf("转化为整形数据:0x%08x\n",DataRec.neData);//高前低后                
            }
        }
        
        else if(strncmp(serBuf,ch[1],2)==0)//判断是否收到命令头ch[1]
        {
            //CRC校验,并获得有效数据,存放在共用体中
            CrcS=seRecCrc(DataRec.DP,3,4,serBuf,7,2);
            
            //显示有效数据
            if (CrcS)    //CRC校验成功
            {                
                printf("\n收到CH[1]命令\n提取的有效数据:");
                for(j=0;j<4;j++)
                {    
                    printf("%02x ",DataRec.DP[j]);//低前高后
                }
                printf("\n");
                
                printf("转化为整形数据:0x%08x\n",DataRec.neData);//高前低后                
            }
        }
        
        else if(strncmp(serBuf,ch[2],2)==0)//判断是否收到命令头ch[2]
        {
            //CRC校验,并获得有效数据,存放在共用体中
            CrcS=seRecCrc(DataRec.DP,3,4,serBuf,7,2);
            
            //显示有效数据
            if (CrcS)    //CRC校验成功
            {
                printf("\n收到CH[2]命令\n提取的有效数据:");
                for(j=0;j<4;j++)
                {    
                    printf("%02x ",DataRec.DP[j]);//低前高后
                }
                printf("\n");
                
                printf("转化为整形数据:0x%08x\n",DataRec.neData);//高前低后                
            }
        }            
    }
   
   return 0;
}


网站公告

今日签到

点亮在社区的每一天
去签到