基于STM32的CRC校验说明

///*****************************************************************************
//下面是test.c里面的函数
///*****************************************************************************
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//串口猎人用的程序                                                        //////////
//值得说明的是,CRC协议同样适用于串口猎人适用,也就是”协议”是通用的        ////////
//    USART1->DR=num;                                                    ////////
//串口猎人只能发送hex值,即只能发送16进制的数据,才能显示出波形            /////////
//    while((USART1->SR&0X40)==0);                                          ////////
//    delay_ms(500);                                                        ////////
//    num-=1;                                                            ////////
//    if(num==0x00)                                                        ////////
//    num=0xff;                                                            ///////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//值得说明的是,CRC协议同样适用于串口猎人适用,也就是”协议”是通用的        ////////
//串口助手用的程序                                                        ////////
//    printf("%d ",0XA5);                                                    ////////
//    printf("%d ",t);                                                        ////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//    Visualscope串口示波器的程序                                            ////////
                                                                        ////////
    for(i=0;i<4;i++)//先装载数据                                            ////////
    {                                                                    ////////
        OutData[i]= num;                                                    ////////
        num-=70;                                                            ////////
    }                                                                    ////////
    num=0xff;                                                            ////////
    OutPut_Data();//调用主函数                                                ////////
    delay_ms(10);//定义发送频率                                            ////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////




///*****************************************************************************
//下面是USART.H里面的函数
///*****************************************************************************
//串口示波器的变量
extern float OutData[4];//这是全局变量
unsigned short CRC_CHECK(unsigned short *Buf, unsigned short CRC_CNT);
void voTxIsr(void);
void OutPut_Data();





///*****************************************************************************//下面的是USART.C里面的文件
//这里用到了串口接收数据中断函数,所以需要把原先的数据串口中断函数屏蔽了
///*****************************************************************************
//the following is MCU code for CRC16 ,please refer.
//-------------------------------------------------------------------------------------------
#define ULONG unsigned long
#define RxCountMax 18
//float OutData[4];    这个是全局变量,在main函数和USART.H中都有定义
unsigned short TxBuf[10];
unsigned short RxBuf[RxCountMax];
unsigned short RxCnt;
unsigned short TxCnt;
unsigned short Rx50msCnt;
unsigned long pAddr1,pAddr2,pAddr3,pAddr4;

//CRC16校验算法
unsigned short CRC_CHECK(unsigned short *Buf, unsigned short CRC_CNT)
{
    unsigned short CRC_Temp;
    unsigned char i,j;
    CRC_Temp = 0xffff;

    for (i=0;i<CRC_CNT; i++){      
        CRC_Temp ^= Buf[i];        
        for (j=0;j<8;j++) {
            if (CRC_Temp & 0x01)
                CRC_Temp = (CRC_Temp >>1 ) ^ 0xa001;
            else
                CRC_Temp = CRC_Temp >> 1;
        }
    }
    return(CRC_Temp);
}

//Receive interrupt routine 串口接收中断函数
void USART1_IRQHandler(void)
{
    unsigned short i,CRC_RX,CRC_Tmp;
    RxBuf[RxCnt] = USART1->DR;        //acquire data    接收数据
    RxCnt++;
        
    if(RxCnt == RxCountMax) {
        CRC_Tmp =  CRC_CHECK(RxBuf,16);      //CRC Calculation    计算接收到的数据的CRC校验值
        CRC_RX = ((unsigned short)RxBuf[RxCountMax-1]<<8) + RxBuf[RxCountMax-2];    //接收的数据中的最后两位就是CRC校验值
        if(CRC_Tmp == CRC_RX){        //比较两个校验值是否相同
            LED0=~LED0;    //这里是我做的一个现象,通信成功就亮/灭一下灯
            pAddr1 = ((ULONG)(RxBuf[0x3])<<24)|((ULONG)(RxBuf[0x2])<<16)|((ULONG)(RxBuf[0x1])<<8)|RxBuf[0x0];    //然后把数据保存起来
            pAddr2 = ((ULONG)(RxBuf[0x7])<<24)|((ULONG)(RxBuf[0x6])<<16)|((ULONG)(RxBuf[0x5])<<8)|RxBuf[0x4];
            pAddr3 = ((ULONG)(RxBuf[0xB])<<24)|((ULONG)(RxBuf[0xA])<<16)|((ULONG)(RxBuf[0x9])<<8)|RxBuf[0x8];
            pAddr4 = ((ULONG)(RxBuf[0xF])<<24)|((ULONG)(RxBuf[0xE])<<16)|((ULONG)(RxBuf[0xD])<<8)|RxBuf[0xC];        
        }
        RxCnt = 0;  
    }
    Rx50msCnt = 0;
//to add--Clear Receive Data Register Fll flag;
//    USART1->DR=res;
//    while((USART1->SR&0X40)==0);//

} 

//Transfer interrupt routine    串口发送数据函数
void voTxIsr(void)
{
    if(TxCnt <= 9)
    {
        USART1->DR = TxBuf[TxCnt];
        //Clear Tx interrupt flag
        TxCnt++;
        if(TxCnt >= 10)
        {
            //send interrupt disable        
            TxCnt=0;
        }
    }
}


//-------------------------------------------------------------------------------------------
//Monitor routine Execute every T Period time    应用函数,在主函数中直接调用这个就可以了
void OutPut_Data()
{
    int temp[4] = {0};
    unsigned int temp1[4] = {0};
    unsigned short databuf[10] = {0};
    unsigned char i;
    unsigned short CRC16 = 0;
    for(i=0;i<4;i++)
    {
    temp[i]  = (u16)OutData[i]; //把要发送的数据传过来
    temp1[i] = (u16)temp[i];    //并复制一份数据,进行下面的处理
    }

    for(i=0;i<4;i++) 
    {
    databuf[i*2]   = (u8)(temp1[i]%256);    //高低位处理
    databuf[i*2+1] = (u8)(temp1[i]/256); 
    }

    CRC16 = CRC_CHECK(databuf,8);   //计算要发送数据的CRC16校验值
    databuf[8] = CRC16%256;         //并保存在databuf的8 9里面
    databuf[9] = CRC16/256;

    for(i=0;i<10;i++)//把数据和校验位一起发送出去
    {
//        voTxIsr();
        if(TxCnt <= 9)
        {
            USART1->DR = databuf[TxCnt];//发送数据给寄存器
            while((USART1->SR&0X40)==0);//直到发送完成才结束发送  
            TxCnt++;
            if(TxCnt >= 10)
            {
                TxCnt=0;    //准备下次发送数据    
            }
        }
    }
}
原文地址:https://www.cnblogs.com/qidaiymm/p/6073188.html