分享一下CAN通信的打包和解包函数。
打包函数
// CAN信号打包核心函数
Pack_CAN_Signal Rx_CAN_Frame_CAN_Signal_to_Data_Buff_Fun(
uint64_t Signal_Value, // 输入:待打包的原始信号值
uint8_t* data_buff, // 输入/输出:CAN数据缓冲区指针(将在此填充信号值)
uint8_t signal_start_bit, // 输入:信号起始位(0~63)
uint8_t signal_length, // 输入:信号长度(1~32位)
ByteEndian_t signal_byte_order, // 输入:字节序类型(0:Intel小端; 1:Motorola大端)
uint8_t frame_length) // 输入:目标CAN帧长度(1~8字节)
{
Pack_CAN_Signal can_signal; // 声明打包结果结构体(包含状态和信号值)
uint8_t i = 0; // 通用循环计数器
uint8_t byte_num = 0; // 字节遍历计数器
uint8_t low_data_byte = 0; // 信号占据的最低字节索引(小端序使用)
uint8_t high_data_byte = 0; // 信号占据的最高字节索引(大端序使用)
uint8_t low_data_byte_position = 0; // 起始字节内的位偏移量
uint8_t high_data_byte_position = 0; // 高位字节内的位偏移量
uint8_t remaining_bit_number = 0; // 信号剩余待处理的位数(多字节处理)
uint8_t remaining_byte_number = 0; // 信号剩余待处理的字节数(多字节处理)
uint64_t can_signal_mask = SIGNAL_INIT_MASK; // 用于处理和截断信号的位掩码
// 初始化打包结果结构体
can_signal.Signal_State = CAN_SIGNAL_NORMAL; // 默认状态:正常
can_signal.Signal_Value = Signal_Value; // 保存原始信号值
// 检查帧长度有效性
if(frame_length == FRAME_ZERO_DLC) // 检查CAN帧长度是否为0(无效)
{
can_signal.Signal_State = CAN_SIGNAL_NO_VALUE; // 设置状态:无有效帧数据
}
else if(frame_length > FRAME_MAX_DLC) // 检查帧长度是否超过最大值(8字节)
{
can_signal.Signal_State = CAN_FRAME_DLC_OUT_OF_RANGE; // 设置状态:帧长度超限
}
// 检查信号长度有效性
else if(
(signal_length > (frame_length * 8)) // 信号长度超过帧总位数(帧长度*8)
|| (signal_length > SIGNAL_MAX_LENGTH) // 信号长度超过系统支持的最大值(32位)
|| (signal_length == SIGNAL_ZERO_LENGTH) // 信号长度为零(无效)
)
{
can_signal.Signal_State = INVALID_INPUT_PARAMETERS; // 设置状态:参数无效
}
else // 所有基本参数有效,开始信号打包处理
{
// 创建信号掩码(确保信号值在有效位数范围内)
can_signal_mask = 0; // 重置掩码
// 创建信号掩码(屏蔽高位,防止信号超长)
for(i = 0; i < signal_length; i++) /**信号修剪掩码生成**/
{
can_signal_mask |= 0x1 << i; // 按位构建掩码(如信号长12位,则生成0xFFF)
}
// 应用掩码确保信号值不超出有效长度范围
can_signal.Signal_Value &= can_signal_mask;
/** 字节序处理:Intel格式(小端序) **/
if(signal_byte_order == SIGNAL_BYTE_ORDER_INTEL)
{
/** 计算信号占用的字节范围(低字节到高字节)**/
low_data_byte = signal_start_bit / 8; // 起始字节索引
// 结束字节索引计算(考虑位偏移):
// 示例:2+6-1/8=0; 2+7-1/8=1; 2+14-1/8=1; 2+15-1/8=2
high_data_byte = (signal_start_bit + signal_length - 1) / 8;
// 检查信号是否超出帧范围
if((high_data_byte + 1) > frame_length) /** 信号超出帧数据范围 **/
{
can_signal.Signal_State = CAN_FRAME_DLC_OUT_OF_RANGE; // 设置状态:信号越界
}
else // 信号在帧范围内,开始处理
{
// 计算起始字节内的位偏移量
low_data_byte_position = signal_start_bit % 8;
/** 情况1:信号完全在一个字节内 **/
if(low_data_byte == high_data_byte)
{
can_signal_mask = 0; // 重置掩码(用于当前字节)
// 创建保护掩码(保留不修改的位置)
for(i = 0; i < low_data_byte_position; i++)
{
can_signal_mask |= 0xFF >> i; // 例:bit_offset=2,则掩码=0x03(保留低位)
}
// 准备写入位置(清空目标位区域)
data_buff[low_data_byte] &= (can_signal_mask); // 保留不需要修改的部分
// 写入信号(移位对齐并插入到目标位置)
data_buff[low_data_byte] |= (uint8_t)(can_signal.Signal_Value << low_data_byte_position);
}
/** 情况2:信号跨越多个字节 **/
else
{
// 遍历信号涉及的每个字节(从低到高)
for(byte_num = low_data_byte; byte_num <= high_data_byte; byte_num++)
{
// 处理起始字节(最低字节)
if(byte_num == low_data_byte)
{
can_signal_mask = 0; // 重置掩码
// 创建掩码(保护低位的位)
for(i = 0; i < low_data_byte_position; i++)
{
can_signal_mask |= 0xFF >> i;
}
// 准备写入位置(清空目标区域)
data_buff[byte_num] &= (can_signal_mask);
// 写入起始字节的信号部分(移位对齐)
data_buff[byte_num] |= (uint8_t)(can_signal.Signal_Value << low_data_byte_position);
}
// 处理后续字节(非起始字节)
else
{
// 计算当前字节在信号中的移位量
uint8_t shift = ((byte_num - low_data_byte - 1) * 8 + (8 - low_data_byte_position));
can_signal_mask = 0; // 重置掩码
// 创建掩码(保护低位不被修改)
for(i = 0; i < shift; i++)
{
can_signal_mask |= 0xFF << i;
}
// 准备写入位置(清空目标区域)
data_buff[byte_num] &= (can_signal_mask);
// 写入信号值(高位部分,移位对齐)
data_buff[byte_num] |= (uint8_t)(can_signal.Signal_Value >> shift);
}
}
}
}
}
/** 字节序处理:Motorola格式(大端序) **/
else /** signal_byte_order == SIGNAL_BYTE_ORDER_MOTOROLA **/
{
/** 计算起始字节位置(大端序从高字节开始)**/
high_data_byte = signal_start_bit / 8; // 高位字节索引
// 检查信号是否超出帧范围
if((high_data_byte + 1) > frame_length) /** 信号超出帧数据范围 **/
{
can_signal.Signal_State = CAN_FRAME_DLC_OUT_OF_RANGE; // 设置状态:信号越界
}
else // 信号在帧范围内,开始处理
{
// 计算高位字节内的位偏移量
high_data_byte_position = signal_start_bit % 8;
/** 情况1:信号完全在一个字节内 **/
if(signal_length <= (8 - high_data_byte_position))
{
can_signal_mask = 0; // 重置掩码
// 创建保护掩码(保留不修改的位置)
for(i = 0; i < high_data_byte_position; i++)
{
can_signal_mask |= 0xFF >> i;
}
// 准备写入位置(清空目标位区域)
data_buff[high_data_byte] &= can_signal_mask;
// 写入信号(移位对齐并插入到目标位置)
data_buff[high_data_byte] |= (uint8_t)(can_signal.Signal_Value << high_data_byte_position);
}
/** 情况2:信号跨越多个字节 **/
else
{
// 计算剩余需要处理的位数(首字节处理后的剩余位数)
remaining_bit_number = signal_length - (8 - high_data_byte_position);
// 示例:12 - (8 - 2) = 6
// 计算剩余字节数(考虑位对齐)
if((remaining_bit_number % 8) != 0) // 如果位不能整字节对齐
{
remaining_byte_number = remaining_bit_number / 8 + 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--)
{
// 处理起始字节(最高字节)
if(byte_num == high_data_byte)
{
can_signal_mask = 0; // 重置掩码
// 创建掩码(保护低位不被修改)
for(i = 0; i < high_data_byte_position; i++)
{
can_signal_mask |= 0xFF >> i;
}
// 准备写入位置(清空目标区域)
data_buff[high_data_byte] &= can_signal_mask;
// 写入信号的高位部分
data_buff[high_data_byte] |= ((uint8_t)can_signal.Signal_Value) << high_data_byte_position;
}
// 处理后续字节(非首字节)
else
{
// 计算当前字节的移位量
uint8_t shift = ((high_data_byte - byte_num - 1) * 8 + (8 - high_data_byte_position));
can_signal_mask = 0; // 重置掩码
// 创建掩码(保护高位不被修改)
for(i = 0; i < shift; i++)
{
can_signal_mask |= 0xFF << i;
}
// 准备写入位置(清空目标区域)
data_buff[byte_num] &= can_signal_mask;
// 写入信号值的剩余部分
data_buff[byte_num] |= (uint8_t)(can_signal.Signal_Value >> shift);
}
// 防止字节索引下溢(到达缓冲区起始)
if(byte_num == 0)
{
break; // 提前终止循环
}
}
}
}
}
}
// 返回打包操作的结果(包含状态和信号值)
return can_signal;
}
解包函数
/* CAN信号解包核心函数 */
Unpack_CAN_Signal Rx_CAN_Frame_Data_Buff_to_CAN_Signal_Hex_Fun(
uint8_t* data_buff, /** CAN数据缓冲区指针 **/
uint8_t signal_start_bit, /** 信号起始位(0~63) **/
uint8_t signal_length, /** 信号长度(1~32位) **/
ByteEndian_t signal_byte_order, /** 字节序类型(Intel/Motorola) **/
uint8_t frame_length) /** 帧数据长度(1~8字节) **/
{
Unpack_CAN_Signal can_signal; // 定义解包结果结构体
uint8_t i = 0; // 循环计数器
uint8_t byte_num = 0; // 字节序号变量
uint8_t low_data_byte = 0; // 信号最低有效字节位置
uint8_t high_data_byte = 0; // 信号最高有效字节位置
uint8_t low_data_byte_position = 0; // 字节内低位偏移
uint8_t high_data_byte_position = 0; // 字节内高位偏移
uint8_t remaining_bit_number = 0; // 剩余位数
uint8_t remaining_byte_number = 0; // 剩余字节数
uint64_t can_signal_mask = SIGNAL_INIT_MASK; // 信号掩码初始化
// 初始化信号状态和值
can_signal.Signal_State = CAN_SIGNAL_NORMAL;
can_signal.Signal_Value = SIGNAL_INIT_VALUE;
// 检查帧数据长度有效性
if(frame_length == FRAME_ZERO_DLC) // 空帧处理
{
can_signal.Signal_State = CAN_SIGNAL_NO_VALUE;
}
else if(frame_length > FRAME_MAX_DLC) // 帧长度超限
{
can_signal.Signal_State = CAN_FRAME_DLC_OUT_OF_RANGE;
}
// 检查信号长度有效性
else if((signal_length > (frame_length * 8)) // 信号长度超过帧容量
|| (signal_length > SIGNAL_MAX_LENGTH) // 超过最大支持长度
|| (signal_length == SIGNAL_ZERO_LENGTH) // 信号长度为零
)
{
can_signal.Signal_State = INVALID_INPUT_PARAMETERS;
}
else // 参数有效,开始解包处理
{
// Intel格式(小端序)处理
if(signal_byte_order == SIGNAL_BYTE_ORDER_INTEL)
{
// 计算信号跨越的字节范围
low_data_byte = signal_start_bit / 8; // 起始字节位置
high_data_byte = (signal_start_bit + signal_length - 1) / 8; // 结束字节位置
// 检查信号是否在帧范围内
if((high_data_byte + 1) > frame_length) // 信号超出帧范围
{
can_signal.Signal_State = CAN_FRAME_DLC_OUT_OF_RANGE;
}
else
{
// 生成信号掩码(根据信号长度)
for(i = 0; i < signal_length; i++)
{
can_signal_mask |= 0x0000000000000001 << i;
}
// 计算字节内起始位偏移
low_data_byte_position = signal_start_bit % 8;
// 单字节信号处理
if(low_data_byte == high_data_byte)
{
// 提取并掩码处理单字节信号
can_signal.Signal_Value = (((uint64_t)data_buff[low_data_byte]) >> low_data_byte_position) & can_signal_mask;
}
// 跨多字节信号处理
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_t)data_buff[low_data_byte]) >> low_data_byte_position;
}
else // 后续字节处理
{
// 移位拼接后续字节数据
can_signal.Signal_Value |= ((uint64_t)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;
}
}
}
// Motorola格式(大端序)处理
else // signal_byte_order == SIGNAL_BYTE_ORDER_MOTOROLA
{
// 计算起始字节位置
high_data_byte = signal_start_bit / 8;
// 检查信号是否在帧范围内
if((high_data_byte + 1) > frame_length) // 信号超出帧范围
{
can_signal.Signal_State = CAN_FRAME_DLC_OUT_OF_RANGE;
}
else
{
// 生成信号掩码(根据信号长度)
for(i = 0; i < signal_length; i++)
{
can_signal_mask |= 0x0000000000000001 << i;
}
// 计算字节内起始位偏移
high_data_byte_position = signal_start_bit % 8;
// 单字节信号处理
if(signal_length <= (8 - high_data_byte_position))
{
// 提取并掩码处理单字节信号
can_signal.Signal_Value = (((uint64_t)data_buff[high_data_byte]) >> high_data_byte_position) & can_signal_mask;
}
// 跨多字节信号处理
else
{
// 计算剩余需要处理的位数
remaining_bit_number = signal_length - (8 - high_data_byte_position);
// 计算剩余字节数
if((remaining_bit_number % 8) != 0)
{
remaining_byte_number = remaining_bit_number / 8 + 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--)
{
if(byte_num == high_data_byte) // 起始字节处理
{
// 提取起始字节有效位
can_signal.Signal_Value |= ((uint64_t)data_buff[high_data_byte]) >> high_data_byte_position;
}
else // 后续字节处理
{
// 移位拼接后续字节数据
can_signal.Signal_Value |= ((uint64_t)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; // 返回解包结果
}