CAN通信的打包和解包函数

分享一下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;  // 返回解包结果
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

九层指针

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

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

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

打赏作者

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

抵扣说明:

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

余额充值