先上一下 CRC校驗 的源代碼:
void crc_check(unsigned char *ptr,unsigned int len) //crc為開源函數
{unsigned long wcrc=0XFFFF;//預置16位crc寄存器,初值全部為1unsigned char temp;//定義中間變量int i=0,j=0;//定義計數for(i=0;i<len;i++)//循環計算每個數據{temp=*ptr&0X00FF;//將八位數據與crc寄存器亦或ptr++;//指針地址增加,指向下個數據wcrc^=temp;//將數據存入crc寄存器for(j=0;j<8;j++)//循環計算數據的{if(wcrc&0X0001)//判斷右移出的是不是1,如果是1則與多項式進行異或。{wcrc>>=1;//先將數據右移一位wcrc^=0XA001;//與上面的多項式進行異或}else//如果不是1,則直接移出{wcrc>>=1;//直接移出}}}temp=wcrc;//crc的值L_CRC=wcrc;//crc的低八位H_CRC=wcrc>>8;//crc的高八位
}
這個函數通常用于執行 CRC 校驗,即對輸入的數據指針 ptr
和長度 len
進行 循環冗余校驗(Cyclic Redundancy Check)。CRC 是一種非常常見且高效的數據完整性校驗算法,廣泛應用于:
- 通信協議(如 Modbus、CAN、USB)
- 存儲設備(校驗文件完整性)
- 嵌入式系統(數據包校驗)
CRC 校驗概念
CRC 校驗的作用:檢測數據在傳輸或保存過程中是否被篡改或損壞
原理:將數據看作一個二進制多項式,除以一個“生成多項式”,取余數作為CRC校驗碼
常見類型:
CRC8
CRC16(如 Modbus)
CRC32(如以太網、ZIP)
我們這里以標準的 Modbus CRC16 為例,對詳細代碼進行解析:
uint16_t CRC16_Modbus(uint8_t *data, uint16_t len) {uint16_t crc = 0xFFFF; // 初始值for (uint16_t i = 0; i < len; i++) {crc ^= data[i]; // 將每個字節與 CRC 當前值異或for (uint8_t j = 0; j < 8; j++) {if (crc & 0x0001) {crc >>= 1;crc ^= 0xA001; // 多項式:0x8005 反轉為 0xA001} else {crc >>= 1;}}}return crc;
}
逐步解析:
- 初始化 CRC:
Modbus協議規定初始值為 0xFFFF
:
uint16_t crc = 0xFFFF;
- 遍歷整個數據區:
每個字節與當前 CRC 值低字節異或:
for (i = 0; i < len; i++) {crc ^= data[i];...
}
- 對每個字節進行 8 次移位處理:
如果最低位是1,就右移并異或“生成多項式”;
否則直接右移。
for (j = 0; j < 8; j++) {if (crc & 0x0001) {crc >>= 1;crc ^= 0xA001;} else {crc >>= 1;}
}
需要注意的是:
CRC 校驗是 無錯誤糾正能力 的,只能檢測錯誤。
必須和接收端使用相同的 CRC 算法、多項式、初始值。
對于不同協議(如 Modbus、CAN),CRC 實現略有不同,例如,本文最初提供的便是 Modbus 協議的 CRC校驗。
CRC 的多項式
CRC類型 | 多項式 | 初始值 | 結果異或 | 應用 |
---|---|---|---|---|
CRC-8 | 0x07 | 0x00 | 0x00 | SMBus |
CRC-16 | 0x8005 | 0xFFFF | 0x0000 | Modbus |
CRC-CCITT | 0x1021 | 0xFFFF | 0x0000 | XMODEM |
CRC-32 | 0x04C11DB7 | 0xFFFFFFFF | 0xFFFFFFFF | Ethernet, ZIP |
簡單來說,函數 crc_check(unsigned char *ptr, unsigned int len)
是用來對指定內存塊執行 CRC 校驗的工具函數, 常用于嵌入式通信中驗證數據完整性。
以上,歡迎有從事同行業的電子信息工程、互聯網通信、嵌入式開發的朋友共同探討與提問,我可以提供實戰演示或模板庫。希望內容能夠對你產生幫助!