CAN通信的时候,每一帧的大小是有固定限制的,所以为了将尽可能多的数据通过一帧frame传输出去,都会将数据尽量压缩到一个frame里面。比如受信的时候,有的数据在代码里面是用char存储的,但是内容可能仅仅是0和1。这样的数据在往frame里面送的时候可能仅仅1个bit就足够了。针对这样的转换,可以使用下面函数来实现。这个函数的概要就是从Buffer所表示的某个frame里面,从StartIndex的BitPosition开始的长度为size的数据给截取出来赋值给某个变量。
uint32 ExtractData(uint8 Buffer[], uint8 StartIndex, uint8 BitPosition, uint8 Size){ uint8 TempData; uint32 RstData; uint8 TempSize; RstData = 0x00; while ((BitPosition + 1) < Size) { /* Calculate size in 1 byte */ TempSize = BitPosition + 1; /* Extract Data in 1 byte */ TempData = ExtractByteData(Buffer[StartIndex], BitPosition, TempSize); /* Update Parameter */ Size = Size - TempSize; RstData = RstData + (TempData << Size); BitPosition = 7; StartIndex++; } /* Extract Data */ RstData = RstData + ExtractByteData(Buffer[StartIndex], BitPosition, Size); return (RstData);}
其中ExtractByteData函数的处理如下uint8, ExtractByteData(uint8 Data, uint8 BitPosition, uint8 Size){ uint8 Value; uint8 Mask; uint8 Shift; if ((0 < Size) && (Size <= 8)) { Shift = BitPosition - (Size - 1); Value = Data >> Shift; Mask = BIT_MASK(Size); Value = Value & Mask; } else if (Size == 0) { Value = 0x00; } else { Value = Data; } return (Value);}BIT_MASK的定义为 #define BIT_MASK(Size) ((1u << (Size)) - 1)下面是将数据压缩到一个frame里面的操作。这个例子里面数据a是一个uint32的数据,想将它里面的值放到frame的4到6里面,4和5占8位,6占2位。每个byte里面都是从第7位开头。DataBuf[4] |= (uint8)(((a / 0x400) & BIT_MASK(8)) << BIT_SHIFT(7,8));DataBuf[5] |= (uint8)(((a / 0x4) & BIT_MASK(8)) << BIT_SHIFT(7,8));DataBuf[6] |= (uint8)(((a) & BIT_MASK(2)) << BIT_SHIFT(7,2));BIT_SHIFT的定义是 BIT_SHIFT(StartPosition, Size) (uint8)((StartPosition) - ((Size) - 1))
//将val的值放到array的pos位置开始的len长度的空间
SetBits(uint8 array[], uint32 pos, uint32 len, uint32 val)
{
uint32 byte_pos = pos / 8;
/* top zone */
if ((pos % 8) > 0)
{
uint32 rem_bits = 8 - (pos % 8);
uint32 tlen = ((len < rem_bits) ? len : rem_bits);
uint32 off = rem_bits - tlen;
len -= tlen;
array[byte_pos] &= (uint8)~((uint32)BIT_MASK(tlen) << off);
array[byte_pos] |= (uint8)((val >> len) << off);
byte_pos += 1;
}
/* byte copy zone */
while (len >= 8)
{
len -= 8;
array[byte_pos] = (uint8)(val >> len);
byte_pos += 1;
}
/* last zone */
if (len > 0)
{
uint32 off = 8 - len;
array[byte_pos] &= (uint8)(~(BIT_MASK(len) << off));
array[byte_pos] |= (uint8)(((uint32)val & BIT_MASK(len)) << off);
}
}