杂记-记录一些平时遇到的疑惑解答

一、串行通信中,对端如何判别传过来的数据的头和尾?

背景:两个芯片通过串行总线进行通信时,判定接收数据的头和尾。

方法:数据通过编码,以非零作为数据头,零作为数据尾。

原始数据中的0怎么处理?

编码时,“0”通过其在数据中的位置表征。数据的位置从1开始。解码时再根据位置将“0”添加回数据。

=====================================

原来上面说的是cobs:Consistent Overhead Byte Stuffing,是自己菜了。。。

======================================

二、大小端模式

1、首先大小端问题在你折腾一个字节的时候是不存在的,无论是大端还是小端,都是从bit0到bit7这样存放

typedef struct a_Tag
{
    char a:2;
    char b:6;
    char c:3;
    char d:5;
}A_st;

如这样一个结构体,编译器从上到下存放,先a后b,a和b占用1个byte,a在0、1bit,b在2bit-7bit,c、d同理,如下

A_st
byte01
badc
bit7654321076543210

所以,大小端对齐问题来源于人类数字的书写方法和计算机记录数字的方法有所不同而导致的。

人类这样记录一个十六进制数:0x1234,就这个数字本身而言(不谈计算机),我们知道1是高位,4是低位。

而计算机设计的时候,最小的存储单位为字节,0x1234占了计算机的两个字节,这两个字节怎么存放0x1234就成了大小端模式问题。

简化一下问题:

现在有一个变量 uint16 a16 = 0x1234;有一个指向它的指针 uint8* p = &a16,

无论是大端还是小端,都满足 p < p+1

我们称p为小地址,p+1为大地址。此时*p 和 *(p+1)(或者p[0]、p[1])到底是什么?

结论是这样的:首先选择一个比较的基准,这个基准就是小地址(p[0]),

小地址存放高位数就是大端对齐,小地址存放低位数就是小端对齐。

模式p[0]p[1]
小端0x340x12
大端0x120x34

很显然大端模式符合人类的习惯。

同时,我们看到,1和2的位置,3和4的位置并没有颠倒,或者说0x12(8'b00010010)并没有变成0x48(8'b01001000)

这是因为上面提到的,计算机在折腾一个字节的时候,规则的一定的,从bit0开始存放,一直到bit7。

我也不知道你们能不能听明白,反正我看了很对讲解的,很难能够读完就懂的。

=========================================================================

三、数组的生长方向

无论是大端对齐还是小端对齐,数组的生长方向都是由小到大,即int a[10],int* p = a,p == &a[0],而(p++) == &a[1]。

四、关于CRC

4.1 从最crc32开始

几个问题:

1、平时我们在网上查到的CRC32的计算,其实都是安装大端的方式进行计算的,如下面的例子。

当我们想要计算0x12345678的CRC32时,会先将这个数字转换成一个u8的数组,如u8 data[4] = {0x12,0x34,0x56,0x78},然后将data传递给CRC32计算的接口进行计算。这其实就是一种大端计算方式。

u32 crc32_be_generic(u32 crc, u8 const *p, u32 len, u32 polynomial)
{
	int i;
	while (len--) {
		crc ^= *p++ << 24;
		for (i = 0; i < 8; i++)
			crc = (crc << 1) ^ ((crc & 0x80000000) ? polynomial : 0);
	}
	return crc;
}

#define CRCPOLY_BE 0x04c11db7
int main(void)
{
    u8 data[4] = {0x12,0x34,0x56,0x78};
    u32 crc = crc32_be_generic(~0,data,4,CRCPOLY_BE)^0xffffffff;
}

但是,在实际的硬件当中,我们发送0x12345678的时候,如arm中,其实数据是从0x78进行发送的,而接收端在接收的同时就要进行CRC校验了,这个时候怎么办?

此时我们就得使用CRC32的小端的计算方法了。

u32 crc32_le_generic(u32 crc, u8 const *p, u32 len, u32 polynomial)
{
	int i;
	while (len--) {
		crc ^= *p++;
		for (i = 0; i < 8; i++)
			crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);
	}

	return crc;
}

#define CRCPOLY_LE 0xedb88320
int main(void)
{
    u8 data[4] = {0x78,0x56,0x34,0x12};
    u32 crc = crc32_le_generic(~0, data, 4, CRCPOLY_LE)^0xffffffff;
    return 0;
}

期初,我发现大端计算方法和小端计算方法的多项式是bit reverse的,计算的数据也有颠倒的关系,且大小端计算的实现方法中也有逆向的感觉。所以我猜测,是不是{0x12,0x34,0x56,0x78}使用大端计算和{0x78,0x56,0x34,0x12}使用小端计算的结果是一样的呢?但是,经过我的测试,发现这两个结果并不相同。

Q:这里留下一个疑惑,同一个数据0x12345678,通过大端计算crc32和小端计算crc32有什么关系?

4.2 CRC的切片计算

对于64bit位宽的数据,我们可以采用CRC32 SLICE BY 8进行计算,对于32bit位宽的数据可以采用CRC32 SLICE BY 4进行计算。

可以看出规律,分片后的单个数据为一个byte,我并不知道为什么会这样,但是这让我想起了,可能跟查表发有关系。

所以,留下两个问题:

什么是分片计算CRC32?

如何从查表法中窥探分片法的原来?

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值