最近着手於開發RPIMouse的通信協議,第一次接觸CRC校驗,發現有很多問題。32本身是帶有硬件CRC校驗的,但是他的校驗結果和PC算法計算出來的完全不同。在查找解決方法的過程中得知32數據和PC數據的大小端不同,數據計算結果當然不同。什麼是大小端呢?
一、什麼是大小端
大端模式:即高位字節排放在內存地址低地址端,低位字節排放在內存的高地址端。
小端模式:即低位字節排放在內存地址低地址端,高位字節排放在內存的高地址端。
比如:數字0x12 34 56 78 在內存中的表示形式爲:
1)大端模式:
低地址------------------>高地址
0x12 | 0x34 | 0x56 | 0x78
2)小端模式:
低地址------------------>高地址
0x78 | 0x56 | 0x34 | 0x12
3)具體例子:
16bit寬的數0x1234在小端模式及大端模式CPU中存放的方式(假設從0x4000開始存放)爲:
內存地址 | 小端模式存放內容 | 大端模式存放內容 |
0x4000 | 0x34 | 0x12 |
0x4001 | 0x12 | 0x34 |
32bit寬的數0x12345678在小端模式及大端模式CPU中存放的方式(假設地址從0x4000開始存放)爲:
內存地址 | 小端模式存放內容 | 大端模式存放內容 |
0x4000 | 0x78 | 0x12 |
0x4001 | 0x56 | 0x34 |
0x4002 | 0x34 | 0x56 |
0x4003 | 0x12 | 0x78 |
二、數組在大小端下的存儲
以unsigned int value = 0x12345678爲例,分別看看兩種字節序下其存儲情況。我們可以用unsigned char buf[4] 來表示 value
大端模式:
高地址
|
| buf[3] (0x78) 低位
| buf[2] (0x56)
| buf[1] (0x34)
| buf[0] (0x12) 高位
|
低地址
小端模式:
高地址
|
| buf[0] (0x12) 低位
| buf[1] (0x34)
| buf[2] (0x56)
| buf[3] (0x78) 高位
|
低地址
三、判斷機器字節序的方法
一般通過union類型來測試。以下代碼可用來測試編譯器大小端模式。
#include <stdio.h>
int main (void)
{
union
{
short i;
char a[2];
}u;
u.a[0] = 0x11;
u.a[1] = 0x22;
printf ("0x%x\n", u.i); //0x2211 爲小端 0x1122 爲大端
return 0;
}
輸出結果:
0x2211
四、數據轉換方法
對於單字數據(16bit)
#define BigtoLittle16(A) (( ((uint16)(A) & 0xff00) >> 8) | \
(( (uint16)(A) & 0x00ff) << 8))
對於雙字數據(32bit)
#define BigtoLittle32(A) ((( (uint32)(A) & 0xff000000) >> 24) | \
(( (uint32)(A) & 0x00ff0000) >> 8) | \
(( (uint32)(A) & 0x0000ff00) << 8) | \
(( (uint32)(A) & 0x000000ff) << 24))
以上方法及內容來自CSDN:https://blog.csdn.net/ce123_zhouwei/article/details/6971544 ,程序未經測試。
所以,如果想使用32的硬件CRC,首先要將小端數據轉爲大端,得到CRC後與初值(0xFFFF FFFF)按位異或,即可得到主流CRC32-MPEG2的校驗結果。
參考鏈接:
STM32的硬件CRC32使用 https://blog.csdn.net/lan120576664/article/details/47156067
STM32 大小端模式 與 堆棧及其增長方向分析 http://www.openedv.com/thread-24152-1-1.html
How to set STM32 to generate standard CRC32 https://stackoverflow.com/questions/39646441/how-to-set-stm32-to-generate-standard-crc32
STM32內置CRC模塊的使用 http://bbs.21ic.com/icview-111321-1-1.html
至此,32CRC問題解決完畢(大概?),下一步繼續完善項目的通信協議。