基于python-can提取CAN帧Data段第30-46位的技术求助
CAN帧数据字段提取指定位的实现方案
针对你需要从CAN帧64位Data字段提取第30至46位的需求,我们可以通过字节转整数+位运算来实现,以下是具体步骤和修改后的代码:
核心逻辑说明
- 字节转64位整数:将CAN帧的8字节data转换为大端字节序的64位无符号整数(CAN总线通常采用大端字节序,即第一个字节为最高位字节)。
- 位掩码计算:生成对应目标位范围的掩码,通过
&操作保留目标位,再通过>>操作将目标位移到最低位,得到最终数值。
注意:默认位编号从最高位(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
相关产品推荐
相关产品推荐

