高效的CAN总线信号提取及填充方法

CAN通信矩阵

整车CAN通信矩阵通常由OEM制定及发布,其定义了整车CAN网络中每个通信节点信息交互的格式通信矩阵包含每个信号的具体定义,工程人员通过通信矩阵可以读取及解析整车CAN总线信号。

CAN信号定义

总线信号定义包括: 信号名称、信号长度、起始字节、起始位信号 ,例如查看 EngineDriverRequestTorque信号定义,可知该信号在通信报文中 “第2字节的第3位” 至 “第3字节的第0位”。

Signal Name
信号名称
Start Byte
起始字节
Start Bit
起始位
Bit Length
信号长度
Factor
比例因子 
Offset
偏移量
Unit
单位
Conversion formula
转换公式
EngineDriverRequestTorque23120.25-150NmE=0.25N-150

 

CAN信号提取(传统方法)

根据通信矩阵定义,开发人员通过搭建简单的模型即可提取EngineDriverRequestTorque信号(如下图1所示),但是若信号的定义较另类或者信号数据较多时,则搭建提取信号模型也会变得会费时费力(如下图2所示)。

 

(图1)

(图2)

CAN信号提取(改进方法)

我们可将提取信号封装为统一的函数/class的形式,后续所有的CAN信号提取均可采用统一的形式,调用提取函数并填入该信号定义即可,如图3所示。

(图3)

高效的提取CAN信号方法说明

1、提取bool类型位信号时:填入位信号所在的起始字节idx_byte、起始位idx_bit即可。 

bool getBitSignal(uint8* buf,uint8 idx_byte,uint8 idx_bit)
{
    bool log;
    uint8 offs;

    offs=idx_bit;
    log = (*(buf + idx_byte) >> offs) & 1;
    return log;
}

2、提取长度小于Byte信号时:填入信号所在的起始字节idx_byte、起始位idx_bit、信号长度len即可。 

uint8 getByteSignal(uint8* buf,uint8 idx_byte,uint8 idx_bit,uint8 len)
{
    uint8 offs;
    uint8 msg;
    const uint8 bitmasku8[8] = {0x01,0x03,0x07,0x0F,0x1F,0x3F,0x7F,0xFF}; 

    offs = 8 - (7 - idx_bit) - len;  // offs = sizeof(byte)-(bit_7-idx_bit)-len
    msg = *(buf + idx_byte);
    msg = (msg >> offs) & bitmasku8[len - 1];
    return msg;
}

3、同理提取长度小于2Byte信号时:填入信号所在的起始字节idx_byte、起始位idx_bit、信号长度len即可。 

uint16 getShortSignal(uint8* buf,uint8 idx_byte,uint8 idx_bit,uint8 len)
{
    uint8 offs;
    uint16 msg;
    const uint16 bitmasku16[16] ={0x0001,0x0003,0x0007,0x000F,0x001F,0x003F,0x007F,0x00FF,0x01FF,0x03FF,0x07FF,0x0FFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF};

    offs = 16 - (7 - idx_bit) - len;  // offs = sizeof(short)-(bit_7-idx_bit)-len
    msg = *(buf + idx_byte);
    msg = (msg >> offs) & bitmasku16[len - 1];
    return msg;
}

4、但当提取长度小于2Byte信号且信号位置跨度占据3个Byte时(信号位置如下图所示),则需稍作处理以防止数据的溢出。

而后填入需要位信号所在的起始字节idx_byte、起始位idx_bit以及信号长度len即可。 

 

uint16 getShortSignalExt(uint8* buf,uint8 idx_byte,uint8 idx_bit,uint8 len)
{
    uint8 offs;
    uint32 msg;
    const uint16 bitmasku16[16] ={0x0001,0x0003,0x0007,0x000F,0x001F,0x003F,0x007F,0x00FF,0x01FF,0x03FF,0x07FF,0x0FFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF};

    offs = 32 - (7 - idx_bit) - len;  // offs = sizeof(int)-(bit_7-idx_bit)-len
    msg = *(buf + idx_byte);
    msg = (msg >> offs) & bitmasku16[len - 1];
    return (uint16)msg;
}

 高效的填充CAN信号方法说明

填充CAN信号 较 提取CAN信号 而言稍复杂一些,既要将数据填充到指定的位置又要确保原数据缓冲区其余位置的值保持不变。

1、填充bool类型位信号时:填入位信号所在的起始字节idx_byte、起始位idx_bit、位信号去值log即可。

void setBitSignal(uint8* buf,uint8 idx_byte,uint8 idx_bit,bool log)
{
	uint8 offs;
	uint8 msg;
	uint8 mask;

	offs = idx_bit;
	mask = (~(1 << offs));  // 构造一个除需填充的数据位之外,其他位都是1的数据
	msg = (*(buf + idx_byte)) & mask;
	*(buf + idx_byte) = (msg) | (log << offs);
}

2、填充长度小于Byte信号时:填入信号所在的起始字节idx_byte、起始位idx_bit、信号长度len、信号取值val即可。

void setByteSignal(uint8* buf,uint8 idx_byte,uint8 idx_bit,uint8 len,uint8 val)
{
	uint8 offs;
	uint8 msg;
	uint8 mask;
    const uint8 bitmasku8[8] = { 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };

	offs = 8 - (7 - idx_bit) - len;

	mask = bitmasku8[len - 1];
	mask = (~(mask << offs)); // 构造一个除需填充的数据位之外,其他位都是1的数据
	msg = (*(buf + idx_byte)) & mask;
	*(buf + idx_byte) = (msg) | ((val << offs)&(~mask));
}

 3、同理填充长度小于2Byte信号时:填入信号所在的起始字节idx_byte、起始位idx_bit、信号长度len、信号取值val即可

void setShortSignal(uint8* buf,uint8 idx_byte,uint8 idx_bit,uint8 len,uint16 val)
{
	uint8 offs;
	uint16 msg;
	uint16 mask;
    const uint16 bitmasku16[16] = {0x0001,0x0003,0x0007,0x000F,0x001F,0x003F,0x007F,0x00FF,0x01FF,0x03FF,
0x07FF,0x0FFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF};

	offs = 8 - (7 - idx_bit) - len;

	mask = bitmasku16[len - 1];
	mask = (~(mask << offs)); // 构造一个除需填充的数据位之外,其他位都是1的数据
	msg = (*(buf + idx_byte)) & mask;
	*(buf + idx_byte) = (msg) | ((val << offs)&(~mask));
}

总结:

上述代码虽已在Visual C++上调试通过,但该代码更多的是提供思路借鉴,若需要在正式场合使用时,建议增加断言进行边界检查;并且很多的编译器并不支持指针偏移+强制转换,因此也建议可以通过数组移位+拼接的方式实现。如

uint16 getShortSignal(uint8* buf,uint8 idx_byte,uint8 idx_bit,uint8 len)
{
    uint8 offs;
    uint16 msg=0;

#ifndef RELEASE_VERSION  // 增加断言
	assert(idx_byte > MAX_INDEX_SIGNAL);
	assert(idx_bit > MAX_INDEX_SIGNAL);
	assert(len > MAX_INDEX_LENGTH);
#endif	
	
    offs = 16 - (7 - idx_bit) - len;
    msg = ((uint16)buf[idx_byte]) << 8;
    msg += buf[idx_byte + 1];
    msg = (msg >> offs) & bitmasku16[len - 1];
}

 

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

*菜鸟工程师*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值