案例背景(共15页精讲):
该篇博文将告诉您,CAN DBC转换C语言代码Demo,只需传递对应CAN信号关联参数,无需每个信号"左移"和"右移",并举例介绍:在CANoe/Canalyzer中CAPL中的应用:对接收报文,进行解包。其它场景的应用,也可参考该篇。
目录
1 背景:CAN信号在CAN 报文/Frame中位置的决定因素
2 讲解:CAN DBC转换C语言代码Demo
2.1 定义一些宏定义
2.2 定义一些结构体
2.3 API接口函数原型
2.4 对CANFD DBC的支持
2.5 如何使用该API接口
3 举例:在CANoe/Canalyzer中CAPL中的应用:对接收报文,进行解包
3.1 信号的字节顺序Byte Order: Intel小端模式
3.1.1 CAPL文件can的完整代码
3.1.2 系统变量定义
3.1.3 测试结果
3.2信号的字节顺序Byte Order: Motorola大端模式
3.2.1 CAPL文件can的完整代码
3.2.2 系统变量定义
3.2.3 测试结果
结尾
优质博文推荐阅读(单击下方链接,即可跳转):
Vector工具链
CAN Matrix DBC
CAN Matrix Arxml
1 背景:CAN信号在CAN 报文/Frame中位置的决定因素
一个CAN信号在CAN 报文/Frame中的位置,由3个条件决定,见图1-1:
- 信号的起始位Startbit:默认为信号的Lsb;
- 信号的长度Length;
- 信号的字节顺序Byte Order: Intel小端模式和Motorola大端模式。
详见博文“【DBC专题】-4-DBC文件中的Signal信号字节顺序Motorola和Intel介绍https://blog.csdn.net/qfmzhu/article/details/111561710”,这里不再重复讲解。
下面我们根据这个背景,来设计一个通用算法,封装成一个函数,只需输入几个参数,即可得到对应的信号值。
图1-1
2 讲解:CAN DBC转换C语言代码Demo
2.1 定义一些宏定义
#define FRAME_TJW_ZERO_DLC 0 // unit:Byte
#define FRAME_TJW_MAX_DLC 8 // unit:Byte
#define SIGNAL_TJW_ZERO_LENGTH 0 // unit:Bit
#define SIGNAL_TJW_MAX_LENGTH 64 // unit:Bit
#define SIGNAL_TJW_INIT_VALUE 0
#define SIGNAL_TJW_INIT_MASK 0
#define SIGNAL_TJW_BYTE_ORDER_INTEL 0
#define SIGNAL_TJW_BYTE_ORDER_MOTOROLA 1
#define CAN_SIGNAL_TJW_NORMAL 0
#define CAN_SIGNAL_TJW_NO_VALUE 1
#define CAN_FRAME_TJW_DLC_OUT_OF_RANGE 2
#define INVALID_INPUT_PARAMETERS_TJW 3
/** 使用该Demo需注明出处,以表对作者的尊重 **/
/** 版权归CSDN博客“汽车电子助手”所有,https://blog.csdn.net/qfmzhu **/
2.2 定义一些结构体
typedef struct
{
uint8 Signal_State; // Describes the state of a signal
uint64 Signal_Value; // Describes the value of a signal
} Unpack_CAN_Signal;
/** 使用该Demo需注明出处,以表对作者的尊重 **/
/** 版权归CSDN博客“汽车电子助手”所有,https://blog.csdn.net/qfmzhu **/
2.3 API接口函数原型
/** 使用该Demo需注明出处,以表对作者的尊重 **/
/** 版权归CSDN博客“汽车电子助手”所有,https://blog.csdn.net/qfmzhu **/
Unpack_CAN_Signal Rx_CAN_Frame_Data_Buff_to_CAN_Signal_Hex_Fun(
uint8* data_buff, /**Byte array of CAN data field**/
uint8 signal_start_bit, /**Rang:0~(FRAME_TJW_MAX_DLC * 8 - 1)**/
uint8 signal_length, /**Rang:1~SIGNAL_TJW_MAX_LENGTH**/
boolean signal_byte_order, /**0:Intel;1:Motorola**/
uint8 frame_length) /**Rang:1~FRAME_TJW_MAX_DLC**/
{
Unpack_CAN_Signal can_signal;
uint8 i = 0;
uint8 byte_num = 0;
uint8 low_data_byte = 0;
uint8 high_data_byte = 0;
uint8 low_data_byte_position = 0;
uint8 high_data_byte_position = 0;
uint8 remaining_bit_number = 0;
uint8 remaining_byte_number = 0;
uint64 can_signal_mask = SIGNAL_TJW_INIT_MASK;
can_signal.Signal_State = CAN_SIGNAL_TJW_NORMAL;
can_signal.Signal_Value = SIGNAL_TJW_INIT_VALUE;
if(frame_length == FRAME_TJW_ZERO_DLC) /**DLC of CAN frame is 0**/
{
can_signal.Signal_State = CAN_SIGNAL_TJW_NO_VALUE;
}
else if(frame_length > FRAME_TJW_MAX_DLC) /**DLC of CAN frame is out of range**/
{
can_signal.Signal_State = CAN_FRAME_TJW_DLC_OUT_OF_RANGE;
}
else if(
(signal_length > (frame_length * 8)) /**Invalid signal_length: The length of the signal is not in the range of DLC**/
|| (signal_length > SIGNAL_TJW_MAX_LENGTH) /**Invalid signal_length: The length of the signal exceeds the maximum Unsigned of C language**/
|| (signal_length == SIGNAL_TJW_ZERO_LENGTH) /**Invalid signal_length: The length of the signal is not equal to 0**/
)
{
can_signal.Signal_State = INVALID_INPUT_PARAMETERS_TJW;
}
else
{
/**Byte Order: Intel**/
if(signal_byte_order == SIGNAL_TJW_BYTE_ORDER_INTEL)
{
/**Bytes used by CAN signal,Byte[0] is low byte,Byte[frame_length] is high byte**/
low_data_byte = signal_start_bit / 8;
high_data_byte = (signal_start_bit + signal_length - 1) / 8; // 2 + 6 - 1 /8 = 0; 2 + 7 - 1 /8 = 1 ; 2 + 14 - 1 /8 = 1 ; 2 + 15 - 1 /8 = 2
if((high_data_byte + 1) > frame_length) /** CAN signal is not in the range of DLC**/
{
can_signal.Signal_State = CAN_FRAME_TJW_DLC_OUT_OF_RANGE;
}
else
{
for(i = 0;i < signal_length;i++) /**Generate signal mask according to signal length**/
{
can_signal_mask |= 0x0000000000000001 << i;
}
low_data_byte_position = signal_start_bit % 8; /**Distance from the lowest bit of each byte**/
/**CAN Signal is in a bytes**/
if(low_data_byte == high_data_byte)
{
can_signal.Signal_Value = (((uint64)data_buff[low_data_byte]) >> low_data_byte_position) & can_signal_mask;
}
/**CAN Signal in multiple bytes**/
else
{
for(byte_num = low_data_byte;byte_num <= high_data_byte;byte_num++)
{
if(byte_num == low_data_byte)
{
can_signal.Signal_Value |= ((uint64)data_buff[low_data_byte]) >> low_data_byte_position;
}
else
{
can_signal.Signal_Value |= ((uint64)data_buff[byte_num]) << ((byte_num - low_data_byte - 1) * 8 + (8 - low_data_byte_position));
}
}
can_signal.Signal_Value = can_signal.Signal_Value & can_signal_mask;
}
}
}
/**Byte Order: Motorola**/
else /**signal_byte_order == SIGNAL_TJW_BYTE_ORDER_MOTOROLA**/
{
/**Bytes used by CAN signal,Byte[0] is low byte,Byte[frame_length] is high byte**/
high_data_byte = signal_start_bit / 8;
if((high_data_byte + 1) > frame_length) /** CAN signal is not in the range of DLC**/
{
can_signal.Signal_State = CAN_FRAME_TJW_DLC_OUT_OF_RANGE;
}
else
{
for(i = 0;i < signal_length;i++) /**Generate signal mask according to signal length**/
{
can_signal_mask |= 0x0000000000000001 << i;
}
high_data_byte_position = signal_start_bit % 8; /**Distance from the lowest bit of each byte**/
/**CAN Signal is in a bytes**/
if(signal_length <= (8 - high_data_byte_position))
{
can_signal.Signal_Value = (((uint64)data_buff[high_data_byte]) >> high_data_byte_position) & can_signal_mask;
}
/**CAN Signal in multiple bytes**/
else
{
remaining_bit_number = signal_length - (8 - high_data_byte_position); // 剩余bit = 12 - (8 - 2) = 6
if((remaining_bit_number % 8) != 0)
{
remaining_byte_number = remaining_bit_number / 8 + 1; // remaining_byte_number = 1
}
else
{
remaining_byte_number = remaining_bit_number / 8;
}
for(byte_num = high_data_byte;byte_num >= (high_data_byte - remaining_byte_number);byte_num--) // high_data_byte = 2 remaining_byte_number = 1
{
if(byte_num == high_data_byte)
{
can_signal.Signal_Value |= ((uint64)data_buff[high_data_byte]) >> high_data_byte_position;
}
else
{
can_signal.Signal_Value |= ((uint64)data_buff[byte_num]) << ((high_data_byte - byte_num - 1) * 8 + (8 - high_data_byte_position));
}
if(byte_num == 0)
{
break;
}
}
can_signal.Signal_Value = can_signal.Signal_Value & can_signal_mask;
}
}
}
}
return can_signal;
}
/** 使用该Demo需注明出处,以表对作者的尊重 **/
/** 版权归CSDN博客“汽车电子助手”所有,https://blog.csdn.net/qfmzhu **/
2.4 对CANFD DBC的支持
只需将宏定义FRAME_TJW_MAX_DLC的值由8调整为64,即可适配CANFD DBC。
2.5 如何使用该API接口
1、提供的demo,使用了uint8,uint64,boolean类型,在将该代码集成至开发环境中,需要注意这些类型的替换:
- typedef unsigned char uint8
- typedef unsigned long long uint64
2、调用函数Rx_CAN_Frame_Data_Buff_to_CAN_Signal_Hex_Fun时,需要确认传参data_buff,signal_start_bit,signal_length,signal_byte_order,frame_length的准确性,需与DBC保持一致,这样您可以得到对应信号的状态与值;
3 举例:在CANoe/Canalyzer中CAPL中的应用:对接收报文,进行解包
CAPL语法和C语言有一些差异,我们将第2.3章节中的demo稍作修改,以满足测需要。其它场景的应用与其类似。
3.1 信号的字节顺序Byte Order: Intel小端模式
3.1.1 CAPL文件can的完整代码
/** 使用该Demo需注明出处,以表对作者的尊重 **/
/** 版权归CSDN博客“汽车电子助手”所有,https://blog.csdn.net/qfmzhu **/
/*@!Encoding:936*/
includes
{
}
variables
{
byte CAN_Data_Byte[8];
byte Signal_State;
word Signal_Value;
}
on message 0x100
{
CAN_Data_Byte[0] = this.byte(0);
CAN_Data_Byte[1] = this.byte(1);
CAN_Data_Byte[2] = this.byte(2);
CAN_Data_Byte[3] = this.byte(3);
CAN_Data_Byte[4] = this.byte(4);
CAN_Data_Byte[5] = this.byte(5);
CAN_Data_Byte[6] = this.byte(6);
CAN_Data_Byte[7] = this.byte(7);
@sysvar::CAN_Frame::sysvar_Test_Signal_1 = Rx_CAN_Frame_Data_Buff_to_CAN_Signal_Hex(0,2,8);
@sysvar::CAN_Frame::sysvar_Test_Signal_2 = Rx_CAN_Frame_Data_Buff_to_CAN_Signal_Hex(50,12,8);
@sysvar::CAN_Frame::sysvar_Test_Signal_3 = Rx_CAN_Frame_Data_Buff_to_CAN_Signal_Hex(62,2,8);
}
word Rx_CAN_Frame_Data_Buff_to_CAN_Signal_Hex(
byte signal_start_bit, /**Rang:0~(8 * 8 - 1)**/
byte signal_length, /**Rang:1~64**/
byte frame_length) /**Rang:1~8**/
{
byte i = 0;
byte byte_num = 0;
byte low_data_byte = 0;
byte high_data_byte = 0;
byte low_data_byte_position = 0;
byte high_data_byte_position = 0;
byte remaining_bit_number = 0;
byte remaining_byte_number = 0;
word can_signal_mask = 0;
Signal_State = 0;
Signal_Value = 0;
if(frame_length == 0) /**DLC of CAN frame is 0**/
{
Signal_State = 1;
}
else if(frame_length > 8) /**DLC of CAN frame is out of range**/
{
Signal_State = 2;
}
else if(
(signal_length > (frame_length * 8)) /**Invalid signal_length: The length of the signal is not in the range of DLC**/
|| (signal_length > 16) /**Invalid signal_length: The length of the signal exceeds the maximum Unsigned of C language**/
|| (signal_length == 0) /**Invalid signal_length: The length of the signal is not equal to 0**/
)
{
Signal_State = 3;
}
else
{
/**Byte Order: Intel**/
{
/**Bytes used by CAN signal,Byte[0] is low byte,Byte[frame_length] is high byte**/
low_data_byte = signal_start_bit / 8;
high_data_byte = (signal_start_bit + signal_length - 1) / 8; // 2 + 6 - 1 /8 = 0; 2 + 7 - 1 /8 = 1 ; 2 + 14 - 1 /8 = 1 ; 2 + 15 - 1 /8 = 2
if((high_data_byte + 1) > frame_length) /** CAN signal is not in the range of DLC**/
{
Signal_State = 2;
}
else
{
for(i = 0;i < signal_length;i++) /**Generate signal mask according to signal length**/
{
can_signal_mask |= 0x0000000000000001 << i;
}
low_data_byte_position = signal_start_bit % 8; /**Distance from the lowest bit of each byte**/
/**CAN Signal is in a bytes**/
if(low_data_byte == high_data_byte)
{
Signal_Value = (((word)CAN_Data_Byte[low_data_byte]) >> low_data_byte_position) & can_signal_mask;
}
/**CAN Signal in multiple bytes**/
else
{
for(byte_num = low_data_byte;byte_num <= high_data_byte;byte_num++)
{
if(byte_num == low_data_byte)
{
Signal_Value |= ((word)CAN_Data_Byte[low_data_byte]) >> low_data_byte_position;
}
else
{
Signal_Value |= ((word)CAN_Data_Byte[byte_num]) << ((byte_num - low_data_byte - 1) * 8 + (8 - low_data_byte_position));
}
}
Signal_Value = Signal_Value & can_signal_mask;
}
}
}
}
return Signal_Value;
}
/** 使用该Demo需注明出处,以表对作者的尊重 **/
/** 版权归CSDN博客“汽车电子助手”所有,https://blog.csdn.net/qfmzhu **/
3.1.2 系统变量定义
3.1.3 测试结果
使用的DBC:
CAN DBC中信号与系统变量的解析结果一致:
3.2信号的字节顺序Byte Order: Motorola大端模式
3.2.1 CAPL文件can的完整代码
/** 使用该Demo需注明出处,以表对作者的尊重 **/
/** 版权归CSDN博客“汽车电子助手”所有,https://blog.csdn.net/qfmzhu **/
/*@!Encoding:936*/
includes
{
}
variables
{
byte CAN_Data_Byte[8];
byte Signal_State;
word Signal_Value;
}
on message 0x100
{
CAN_Data_Byte[0] = this.byte(0);
CAN_Data_Byte[1] = this.byte(1);
CAN_Data_Byte[2] = this.byte(2);
CAN_Data_Byte[3] = this.byte(3);
CAN_Data_Byte[4] = this.byte(4);
CAN_Data_Byte[5] = this.byte(5);
CAN_Data_Byte[6] = this.byte(6);
CAN_Data_Byte[7] = this.byte(7);
@sysvar::CAN_Frame::sysvar_Test_Signal_4 = Rx_CAN_Frame_Data_Buff_to_CAN_Signal_Hex(6,2,8);
@sysvar::CAN_Frame::sysvar_Test_Signal_5 = Rx_CAN_Frame_Data_Buff_to_CAN_Signal_Hex(10,12,8);
@sysvar::CAN_Frame::sysvar_Test_Signal_6 = Rx_CAN_Frame_Data_Buff_to_CAN_Signal_Hex(56,2,8);
}
word Rx_CAN_Frame_Data_Buff_to_CAN_Signal_Hex(
byte signal_start_bit, /**Rang:0~(8 * 8 - 1)**/
byte signal_length, /**Rang:1~64**/
byte frame_length) /**Rang:1~8**/
{
byte i = 0;
byte byte_num = 0;
byte low_data_byte = 0;
byte high_data_byte = 0;
byte low_data_byte_position = 0;
byte high_data_byte_position = 0;
byte remaining_bit_number = 0;
byte remaining_byte_number = 0;
word can_signal_mask = 0;
Signal_State = 0;
Signal_Value = 0;
if(frame_length == 0) /**DLC of CAN frame is 0**/
{
Signal_State = 1;
}
else if(frame_length > 8) /**DLC of CAN frame is out of range**/
{
Signal_State = 2;
}
else if(
(signal_length > (frame_length * 8)) /**Invalid signal_length: The length of the signal is not in the range of DLC**/
|| (signal_length > 16) /**Invalid signal_length: The length of the signal exceeds the maximum Unsigned of C language**/
|| (signal_length == 0) /**Invalid signal_length: The length of the signal is not equal to 0**/
)
{
Signal_State = 3;
}
else
{
/**Byte Order: Motorola**/
{
/**Bytes used by CAN signal,Byte[0] is low byte,Byte[frame_length] is high byte**/
high_data_byte = signal_start_bit / 8;
if((high_data_byte + 1) > frame_length) /** CAN signal is not in the range of DLC**/
{
Signal_State = 2;
}
else
{
for(i = 0;i < signal_length;i++) /**Generate signal mask according to signal length**/
{
can_signal_mask |= 0x0000000000000001 << i;
}
high_data_byte_position = signal_start_bit % 8; /**Distance from the lowest bit of each byte**/
/**CAN Signal is in a bytes**/
if(signal_length <= (8 - high_data_byte_position))
{
Signal_Value = (((word)CAN_Data_Byte[high_data_byte]) >> high_data_byte_position) & can_signal_mask;
}
/**CAN Signal in multiple bytes**/
else
{
remaining_bit_number = signal_length - (8 - high_data_byte_position); // 剩余bit = 12 - (8 - 2) = 6
if((remaining_bit_number % 8) != 0)
{
remaining_byte_number = remaining_bit_number / 8 + 1; // remaining_byte_number = 1
}
else
{
remaining_byte_number = remaining_bit_number / 8;
}
for(byte_num = high_data_byte;byte_num >= (high_data_byte - remaining_byte_number);byte_num--) // high_data_byte = 2 remaining_byte_number = 1
{
if(byte_num == high_data_byte)
{
Signal_Value |= ((word)CAN_Data_Byte[high_data_byte]) >> high_data_byte_position;
}
else
{
Signal_Value |= ((word)CAN_Data_Byte[byte_num]) << ((high_data_byte - byte_num - 1) * 8 + (8 - high_data_byte_position));
}
if(byte_num == 0)
{
break;
}
}
Signal_Value = Signal_Value & can_signal_mask;
}
}
}
}
return Signal_Value;
}
/** 使用该Demo需注明出处,以表对作者的尊重 **/
/** 版权归CSDN博客“汽车电子助手”所有,https://blog.csdn.net/qfmzhu **/
3.2.2 系统变量定义
3.2.3 测试结果
使用的DBC:
CAN DBC中信号与系统变量的解析结果一致:
结尾
获取更多“汽车电子资讯”和“工具链使用”,
请关注CSDN博客“汽车电子助手”,做您的好助手。