You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于python-can提取CAN帧Data段第30-46位的技术求助

CAN帧数据字段提取指定位的实现方案

针对你需要从CAN帧64位Data字段提取第30至46位的需求,我们可以通过字节转整数+位运算来实现,以下是具体步骤和修改后的代码:

核心逻辑说明

  1. 字节转64位整数:将CAN帧的8字节data转换为大端字节序的64位无符号整数(CAN总线通常采用大端字节序,即第一个字节为最高位字节)。
  2. 位掩码计算:生成对应目标位范围的掩码,通过&操作保留目标位,再通过>>操作将目标位移到最低位,得到最终数值。

注意:默认位编号从最高位(MSB)开始计数(即第1位是64位数据的最左侧位),若你的位编号从最低位(LSB)开始,可参考下文调整参数。

修改后的代码

import os
import time
import can

mcFilters = [
    {"can_id": 0x08850225, "can_mask": 0x1FFFFFFF, "extended": True},
    {"can_id": 0x08850245, "can_mask": 0x1FFFFFFF, "extended": True},
    {"can_id": 0x08850265, "can_mask": 0x1FFFFFFF, "extended": True},
    {"can_id": 0x08850285, "can_mask": 0x1FFFFFFF, "extended": True},
]


def setup_can_interface():
    print("\n\rCAN Data Parser")
    print("Bring up CAN0....")
    os.system("sudo /sbin/ip link set can0 down")
    os.system("sudo /sbin/ip link set can0 up type can bitrate 250000")
    time.sleep(0.1)
    print("Ready")


def shutdown_can_interface():
    os.system("sudo /sbin/ip link set can0 down")
    print("\n\rCAN interface shut down")


def initialize_bus():
    try:
        bus = can.interface.Bus(
            channel="can0", bustype="socketcan", can_filters=mcFilters
        )
        print("Initialized bus & Filter")
        return bus
    except OSError:
        print("Cannot find PiCAN board.")
        exit()


def parse_can_message(message):
    parsed_data = {
        "timestamp": message.timestamp,
        "arbitration_id": message.arbitration_id,
        "dlc": message.dlc,
        "data": message.data,
    }

    data_str = " ".join(f"{byte:02x}" for byte in message.data)
    parsed_data["data_str"] = data_str

    # 提取第30至46位(MSB开始计数)
    if len(message.data) == 8:
        # 转换为大端64位无符号整数
        data_int = int.from_bytes(message.data, byteorder='big', signed=False)
        
        # 计算目标位参数:共17位,最低位对应0开始的18位
        bit_count = 46 - 30 + 1
        lowest_bit_pos = 63 - (46 - 1)
        # 生成掩码并提取目标位
        mask = ((1 << bit_count) - 1) << lowest_bit_pos
        extracted_value = (data_int & mask) >> lowest_bit_pos
        
        parsed_data["extracted_dec"] = extracted_value
        parsed_data["extracted_hex"] = f"{extracted_value:04x}"

    return parsed_data


def main():
    setup_can_interface()
    print("The setup_can_interface done")
    bus = initialize_bus()
    print("Bus varible is set")

    try:
        print("In the try")
        while True:
            message = bus.recv()
            parsed_message = parse_can_message(message)

            print(f"Timestamp: {parsed_message['timestamp']:.6f}")
            print(f"ID: {parsed_message['arbitration_id']:x}")
            print(f"DLC: {parsed_message['dlc']}")
            print(f"Data: {parsed_message['data_str']}")
            if "extracted_dec" in parsed_message:
                print(f"Extracted 30-46 bits (decimal): {parsed_message['extracted_dec']}")
                print(f"Extracted 30-46 bits (hex): {parsed_message['extracted_hex']}")
            print("-" * 30)

    except KeyboardInterrupt:
        shutdown_can_interface()
        print("\n\rKeyboard interrupt")


if __name__ == "__main__":
    main()

位编号调整说明

如果你的位编号从最低位(LSB)开始计数(第1位是64位数据最右侧位),修改parse_can_message中的目标位参数:

# 第30位对应0开始的29位,共17位
lowest_bit_pos = 30 - 1
bit_count = 46 - 30 + 1
mask = ((1 << bit_count) - 1) << lowest_bit_pos
extracted_value = (data_int & mask) >> lowest_bit_pos

关键代码解释

  • int.from_bytes(..., byteorder='big'):确保字节顺序与CAN总线传输一致,正确还原64位数据。
  • ((1 << bit_count) - 1):生成连续bit_count个1的二进制基础掩码。
  • << lowest_bit_pos:将掩码位移到目标位的对应位置。
  • (data_int & mask) >> lowest_bit_pos:保留目标位并右移到最低位,得到可直接使用的十进制数值。

内容的提问来源于stack exchange,提问作者Nathan Care

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 23:49:54