如何生成vcan_Kinetis.bin文件

本文介绍了一种简单的方法来自动生成vcan_Kinetis.bin文件,这对于测试自己编写的代码至关重要。只需在IAR项目的选项中将输出格式更改为二进制,然后编译程序,bin文件便会自动生成在指定的文件夹下。

前面一片文章提到了如何使用UD下载测试程序,文章中需要使用vcan_Kinetis.bin文件,之前测试用到的是官方提前编译好的文件,现在来看一下如何自己生成vcan_Kinetis.bin文件以便于测试自己写的代码。

方法很简答,Project>>Options>>Output Converter

将Output format改为binary即可,到这里配置部分就结束了。

接下来只要点击编译程序,bin文件就会生成到相应的文件夹中去。

如上图所示,文件将生成到代码文件下的\Prj\IAR\MK66FX18_Debug\Exe文件夹下。

import sys import logging import time import datetime from PyQt5 import QtWidgets, QtCore, QtGui from PyQt5.QtCore import Qt, QThread, pyqtSignal, pyqtSlot import CanBusToolsApi class CanWorker(QThread): """CAN总线工作线程""" log_signal = pyqtSignal(str) data_received = pyqtSignal(list) test_result = pyqtSignal(str, str) # 测试名称, 结果 operation_finished = pyqtSignal(str, bool) # 操作名称, 成功状态 # 添加测试信号 run_test_signal = pyqtSignal(str, int, list, int) def __init__(self, parent=None): super().__init__(parent) self.can_handle = None self.running = False self.device_name = "PCAN_USB_PRO_FD" self.device_index = 0x00 self.can_channel = 0x01 self.can_bus_type = "CANFD" self.baud_rate = 500000 self.baud_rate_fd = 2000000 # 连接测试信号 self.run_test_signal.connect(self.run_sim_test_async) def init_can_device(self): """初始化CAN设备""" try: self.log_signal.emit("正在初始化CAN设备...") self.can_handle = CanBusToolsApi.CanToolsUnifiedInterface( DeviceName=self.device_name, DeviceIndex=self.device_index, FrameType="STANDARD" ) # 打开CAN通道 result = self.can_handle.CanOpen( BusType=self.can_bus_type, Channel=self.can_channel, BaudRate=self.baud_rate, BaudRateFD=self.baud_rate_fd, SocketCfg=["192.168.0.178", 8000, 0x00] ) if result == 0x00: self.log_signal.emit("CAN设备初始化成功") return True else: self.log_signal.emit(f"CAN设备初始化失败,错误代码: 0x{result:02X}") return False except Exception as e: self.log_signal.emit(f"初始化CAN设备时发生错误: {str(e)}") return False def set_filter(self, from_id, to_id): """设置滤波器""" try: result = self.can_handle.CanFilterMessages( Channel=self.can_channel, FromId=from_id, ToId=to_id, ClearFlag=False ) if result == 0x00: self.log_signal.emit(f"滤波器设置成功: 0x{from_id:03X} - 0x{to_id:03X}") else: self.log_signal.emit(f"滤波器设置失败: 0x{result:02X}") return result == 0x00 except Exception as e: self.log_signal.emit(f"设置滤波器时发生错误: {str(e)}") return False def clear_buffer(self): """清空缓冲区""" try: result = self.can_handle.CanClearBuffer(Channel=self.can_channel) if result == 0x00: self.log_signal.emit("缓冲区清空成功") else: self.log_signal.emit(f"缓冲区清空失败: 0x{result:02X}") return result == 0x00 except Exception as e: self.log_signal.emit(f"清空缓冲区时发生错误: {str(e)}") return False def send_message(self, can_id, data, data_len, read_response=True, response_timeout=0.1): """发送CAN消息并可选读取响应""" try: result = self.can_handle.CanWrite( Id=can_id, DataList=data, DataLen=data_len, BusType=self.can_bus_type, Channel=self.can_channel, SelfTxRx=True ) if result == 0x00: data_hex = ' '.join([f'{x:02X}' for x in data]) self.log_signal.emit(f"发送成功: ID=0x{can_id:03X}, Data={data_hex}, Len={data_len}") # 如果需要读取响应 if read_response: time.sleep(response_timeout) # 等待响应 recv_list = self.read_message() if recv_list: # self.log_signal.emit(f"收到 {len(recv_list)} 条响应:") for i, recv_data in enumerate(recv_list): if len(recv_data) >= 3: recv_id = recv_data[0] recv_len = recv_data[1] recv_data_bytes = recv_data[2] recv_data_hex = ' '.join([f'{x:02X}' for x in recv_data_bytes]) self.log_signal.emit( f"响应报文: ID=0x{recv_id:03X}, Len={recv_len}, Data={recv_data_hex}") else: self.log_signal.emit(f"响应报文: 无效格式 {recv_data}") return True, recv_list # 返回成功状态和响应列表 else: self.log_signal.emit("未收到响应数据") return True, [] # 发送成功但无响应 else: return True, [] # 发送成功但不读取响应 else: self.log_signal.emit(f"发送失败: 0x{result:02X}") return False, [] except Exception as e: self.log_signal.emit(f"发送消息时发生错误: {str(e)}") return False, [] def read_message(self): """读取CAN消息""" try: if self.can_handle: return self.can_handle.CanRead( BusType=self.can_bus_type, Channel=self.can_channel ) return [] except Exception as e: self.log_signal.emit(f"读取数据时发生错误: {str(e)}") return [] def log_can_messages_hex(self, recv_list): """将CAN消息列表转换为16进制格式的日志字符串""" if not recv_list: return "无消息" log_lines = [] for i, msg in enumerate(recv_list): if len(msg) >= 3: # 至少包含 can_id, data_length, data_bytes can_id = msg[0] data_length = msg[1] data_bytes = msg[2] # 数据在第三个位置 # 转换为16进制 can_id_hex = f"0x{can_id:03X}" data_hex = ' '.join([f'{x:02X}' for x in data_bytes]) log_lines.append(f"{i + 1}. ID: {can_id_hex}, Len: {data_length}, Data: {data_hex}") else: log_lines.append(f"{i + 1}. 无效消息格式: {msg}") return "\n".join(log_lines) if log_lines else "无效消息格式" def enter_eol_mode(self): """进入EOL模式""" try: self.clear_buffer() send_data = [0x72E, [0x02, 0x10, 0x03], 0x08] self.send_message(send_data[0], send_data[1], send_data[2]) time.sleep(0.1) send_data = [0x72E, [0x02, 0x10, 0x60], 0x08] self.send_message(send_data[0], send_data[1], send_data[2]) time.sleep(0.1) return True except Exception as e: self.log_signal.emit(f"进入EOL模式时发生错误: {str(e)}") return False def eol_read(self, can_id, cmd, dlc): """执行EOL读取,返回CAN响应数据列表""" try: send_data = [can_id, cmd, dlc] SendStatus = self.send_message(send_data[0], send_data[1], send_data[2]) time.sleep(0.1) # 打印接收到的报文(16进制格式) if SendStatus[0] and SendStatus[1]: # 如果发送成功且有响应 hex_log = self.log_can_messages_hex(SendStatus[1]) self.log_signal.emit(f"收到响应:\n{hex_log}") # 检查响应数据 if SendStatus[1] and len(SendStatus[1]) > 0: response_data = SendStatus[1][0][2] # 第一个响应的数据部分 # 转换为16进制进行比较 response_hex = [f'{x:02X}' for x in response_data[:8]] # 只比较前8个字节 expected_hex = ['04', '71', '01', 'C0', 'CD', 'CC', 'CC', 'CC'] if response_hex == expected_hex: self.log_signal.emit("✓ 响应匹配: 04 71 01 C0 CD CC CC CC") RID1 = send_data[1][4] # 0xC0 -> 192 RID2 = send_data[1][5] # 0xCD -> 205 # 发送31 03报文 time.sleep(1) SendData2 = [0x72E, [0x04, 0x31, 0x03, RID1, RID2], 0x08] SendStatus2 = self.send_message(SendData2[0], SendData2[1], SendData2[2]) time.sleep(0.1) # 打印第二次响应的16进制 if SendStatus2[0] and SendStatus2[1]: hex_log2 = self.log_can_messages_hex(SendStatus2[1]) self.log_signal.emit(f"第二次响应:\n{hex_log2}") # 返回实际的CAN响应数据列表 return SendStatus2[1] else: self.log_signal.emit( f"✗ 响应不匹配。期望: {' '.join(expected_hex)},实际: {' '.join(response_hex)}") # 如果没有收到预期的响应,返回空列表 return [] except Exception as e: self.log_signal.emit(f"EOL读取时发生错误: {str(e)}") return [] def dec_list_to_ascii(self, dec_list, replace_char='?'): """ 将10进制列表转换为ASCII字符串 参数: dec_list: 10进制数字列表 replace_char: 对于非ASCII字符的替换字符 返回: ASCII字符串 """ ascii_chars = [] for num in dec_list: if 0 <= num <= 127: # ASCII范围 ascii_chars.append(chr(num)) else: ascii_chars.append(replace_char) return ''.join(ascii_chars) def run_sim_test(self, test_name, can_id, cmd, dlc, expected_data=None, data_range=None): """执行SIM卡测试""" try: self.log_signal.emit(f"开始执行 {test_name}...") # 进入EOL模式 if not self.enter_eol_mode(): self.test_result.emit(test_name, "FAIL") return False # 执行读取,现在result是CAN响应数据列表 result = self.eol_read(can_id, cmd, dlc) if not result or len(result) == 0: self.test_result.emit(test_name, "FAIL") return False # 获取第一个响应的数据部分 if len(result) > 0 and len(result[0]) >= 3: response_data = result[0][2] # 数据在第三个位置 else: self.test_result.emit(test_name, "FAIL") return False if test_name == "SIM卡状态检测": print(response_data) sim_state = response_data[9] if len(response_data) > 6 else -1 status = "PASS" if sim_state == 2 else "FAIL" self.log_signal.emit(f"SIM卡状态: {sim_state} - {status}") self.test_result.emit(test_name, status) return status == "PASS" elif test_name == "IMEI读取": # IMEI数据从第9个字节开始(索引8) sim_imei_rec = response_data[9:24] if len(response_data) > 23 else [] expected = [56, 54, 51, 54] # 8636 imei = self.dec_list_to_ascii(sim_imei_rec) status = "PASS" if sim_imei_rec[:4] == expected else "FAIL" self.log_signal.emit(f"IMEI: {imei} - {status}") self.test_result.emit(test_name, status) return status == "PASS" elif test_name == "ICCID读取": sim_iccid_rec = response_data[9:24] if len(response_data) > 28 else [] expected = [56, 57, 56, 53] # 8985 iccid = self.dec_list_to_ascii(sim_iccid_rec) status = "PASS" if sim_iccid_rec[:4] == expected else "FAIL" self.log_signal.emit(f"ICCID: {iccid} - {status}") self.test_result.emit(test_name, status) return status == "PASS" elif test_name == "IMSI读取": sim_imsi_rec = response_data[9:24] if len(response_data) > 23 else [] expected = [52, 53, 52, 51] # 4543 imsi = self.dec_list_to_ascii(sim_imsi_rec) status = "PASS" if sim_imsi_rec[:4] == expected else "FAIL" self.log_signal.emit(f"IMSI: {imsi} - {status}") self.test_result.emit(test_name, status) return status == "PASS" elif test_name == "SIM卡激活状态检测": sim_network_state = response_data[9] if len(response_data) > 6 else -1 status = "PASS" if sim_network_state == 2 else "FAIL" self.log_signal.emit(f"SIM卡激活状态: {sim_network_state} - {status}") self.test_result.emit(test_name, status) return status == "PASS" self.test_result.emit(test_name, "FAIL") return False except Exception as e: self.log_signal.emit(f"执行 {test_name} 时发生错误: {str(e)}") self.test_result.emit(test_name, "ERROR") return False def close_device(self): """关闭CAN设备""" try: if self.can_handle: result = self.can_handle.CanClose() if result == 0x00: self.log_signal.emit("CAN设备关闭成功") else: self.log_signal.emit(f"CAN设备关闭失败: 0x{result:02X}") except Exception as e: self.log_signal.emit(f"关闭CAN设备时发生错误: {str(e)}") @pyqtSlot() def init_can_device_async(self): """异步初始化CAN设备""" success = self.init_can_device() self.operation_finished.emit("init", success) @pyqtSlot(int, int) def set_filter_async(self, from_id, to_id): """异步设置滤波器""" success = self.set_filter(from_id, to_id) self.operation_finished.emit("filter", success) @pyqtSlot() def clear_buffer_async(self): """异步清空缓冲区""" success = self.clear_buffer() self.operation_finished.emit("clear", success) @pyqtSlot(str, int, list, int) def run_sim_test_async(self, test_name, can_id, cmd, dlc): """异步执行SIM卡测试""" self.run_sim_test(test_name, can_id, cmd, dlc) class SIMTester(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.can_worker = CanWorker() self.test_results = {} self.init_ui() self.connect_signals() # 启动工作线程 self.can_worker.start() def init_ui(self): """初始化用户界面""" self.setWindowTitle("SIM卡测试工具 - CAN总线UDS诊断") self.setGeometry(100, 100, 1000, 700) # 中央部件 central_widget = QtWidgets.QWidget() self.setCentralWidget(central_widget) # 主布局 main_layout = QtWidgets.QVBoxLayout() central_widget.setLayout(main_layout) # 控制面板 control_panel = QtWidgets.QGroupBox("设备控制") control_layout = QtWidgets.QHBoxLayout() self.init_btn = QtWidgets.QPushButton("初始化CAN设备") self.filter_btn = QtWidgets.QPushButton("设置滤波器") self.clear_btn = QtWidgets.QPushButton("清空缓冲区") self.filter_btn.setEnabled(False) self.clear_btn.setEnabled(False) control_layout.addWidget(self.init_btn) control_layout.addWidget(self.filter_btn) control_layout.addWidget(self.clear_btn) control_layout.addStretch() control_panel.setLayout(control_layout) # 测试面板 test_panel = QtWidgets.QGroupBox("SIM卡测试") test_layout = QtWidgets.QGridLayout() # 测试按钮 tests = [ ("SIM卡状态检测", 0x72E, [0x00, 0x3E, 0x31, 0x01, 0xC0, 0xCD, 0x01, 0x01], 0x62), ("IMEI读取", 0x72E, [0x00, 0x3E, 0x31, 0x01, 0xC0, 0xCD, 0x01, 0x02], 0x62), ("ICCID读取", 0x72E, [0x00, 0x3E, 0x31, 0x01, 0xC0, 0xCD, 0x01, 0x03], 0x62), ("IMSI读取", 0x72E, [0x00, 0x3E, 0x31, 0x01, 0xC0, 0xCD, 0x01, 0x04], 0x62), ("SIM卡激活状态检测", 0x72E, [0x00, 0x3E, 0x31, 0x01, 0xC0, 0xCD, 0x01, 0x05], 0x62) ] self.test_buttons = [] for i, (test_name, can_id, cmd, dlc) in enumerate(tests): btn = QtWidgets.QPushButton(test_name) btn.setProperty("test_params", (test_name, can_id, cmd, dlc)) btn.setEnabled(False) self.test_buttons.append(btn) test_layout.addWidget(btn, i // 2, i % 2) # 批量测试按钮 self.batch_test_btn = QtWidgets.QPushButton("执行全部测试") self.batch_test_btn.setEnabled(False) test_layout.addWidget(self.batch_test_btn, 3, 0, 1, 2) test_panel.setLayout(test_layout) # 结果显示面板 result_panel = QtWidgets.QGroupBox("测试结果") result_layout = QtWidgets.QVBoxLayout() self.result_table = QtWidgets.QTableWidget() self.result_table.setColumnCount(3) self.result_table.setHorizontalHeaderLabels(["测试项目", "结果", "时间"]) self.result_table.horizontalHeader().setStretchLastSection(True) result_layout.addWidget(self.result_table) result_panel.setLayout(result_layout) # 日志面板 log_panel = QtWidgets.QGroupBox("日志") log_layout = QtWidgets.QVBoxLayout() self.log_text = QtWidgets.QTextEdit() self.log_text.setReadOnly(True) self.log_text.setMaximumHeight(150) log_layout.addWidget(self.log_text) log_panel.setLayout(log_layout) # 添加到主布局 main_layout.addWidget(control_panel) main_layout.addWidget(test_panel) main_layout.addWidget(result_panel) main_layout.addWidget(log_panel) # 设置样式 self.apply_styles() def apply_styles(self): """应用样式""" self.setStyleSheet(""" QMainWindow { background-color: #f0f0f0; } QGroupBox { font-weight: bold; border: 2px solid #cccccc; border-radius: 5px; margin-top: 1ex; padding-top: 10px; } QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 5px 0 5px; } QPushButton { background-color: #4CAF50; border: none; color: white; padding: 8px 16px; text-align: center; text-decoration: none; font-size: 14px; margin: 4px 2px; border-radius: 4px; } QPushButton:hover { background-color: #45a049; } QPushButton:disabled { background-color: #cccccc; } QTextEdit { background-color: white; border: 1px solid #cccccc; border-radius: 3px; } QTableWidget { background-color: white; border: 1px solid #cccccc; border-radius: 3px; gridline-color: #cccccc; } """) def connect_signals(self): """连接信号和槽""" self.init_btn.clicked.connect(self.init_can_device) self.filter_btn.clicked.connect(self.set_filter) self.clear_btn.clicked.connect(self.clear_buffer) self.can_worker.log_signal.connect(self.add_log) self.can_worker.test_result.connect(self.update_test_result) self.can_worker.operation_finished.connect(self.handle_operation_result) # 连接测试按钮信号 for button in self.test_buttons: test_name, can_id, cmd, dlc = button.property("test_params") button.clicked.connect( lambda checked, tn=test_name, ci=can_id, cm=cmd, dl=dlc: self.run_single_test(tn, ci, cm, dl) ) self.batch_test_btn.clicked.connect(self.run_all_tests) def init_can_device(self): """初始化CAN设备""" self.init_btn.setEnabled(False) self.add_log("正在初始化CAN设备...") self.can_worker.init_can_device_async() def set_filter(self): """设置滤波器""" self.filter_btn.setEnabled(False) self.can_worker.set_filter_async(0x700, 0x7FF) def clear_buffer(self): """清空缓冲区""" self.clear_btn.setEnabled(False) self.can_worker.clear_buffer_async() def run_single_test(self, test_name, can_id, cmd, dlc): """运行单个测试""" self.can_worker.run_test_signal.emit(test_name, can_id, cmd, dlc) def run_all_tests(self): """运行所有测试""" self.batch_test_btn.setEnabled(False) self.add_log("开始执行全部测试...") # 使用QTimer来顺序执行测试,避免阻塞 self.current_test_index = 0 self.timer = QtCore.QTimer() self.timer.timeout.connect(self.execute_next_test) self.timer.start(500) # 500ms后开始第一个测试 def execute_next_test(self): """执行下一个测试""" if self.current_test_index >= len(self.test_buttons): self.timer.stop() self.batch_test_btn.setEnabled(True) self.add_log("全部测试完成") return button = self.test_buttons[self.current_test_index] test_name, can_id, cmd, dlc = button.property("test_params") self.add_log(f"开始执行: {test_name}") self.can_worker.run_test_signal.emit(test_name, can_id, cmd, dlc) self.current_test_index += 1 def handle_operation_result(self, operation, success): """处理操作结果""" if operation == "init": self.init_btn.setEnabled(True) if success: self.filter_btn.setEnabled(True) self.clear_btn.setEnabled(True) for btn in self.test_buttons: btn.setEnabled(True) self.batch_test_btn.setEnabled(True) self.add_log("CAN设备初始化成功,所有功能已启用") else: self.add_log("CAN设备初始化失败") elif operation == "filter": self.filter_btn.setEnabled(True) if success: self.add_log("滤波器设置成功") else: self.add_log("滤波器设置失败") elif operation == "clear": self.clear_btn.setEnabled(True) if success: self.add_log("缓冲区清空成功") else: self.add_log("缓冲区清空失败") def update_test_result(self, test_name, result): """更新测试结果""" timestamp = datetime.datetime.now().strftime("%H:%M:%S") # 更新结果字典 self.test_results[test_name] = (result, timestamp) # 更新表格 self.result_table.setRowCount(len(self.test_results)) for i, (name, (result, time_str)) in enumerate(self.test_results.items()): self.result_table.setItem(i, 0, QtWidgets.QTableWidgetItem(name)) self.result_table.setItem(i, 1, QtWidgets.QTableWidgetItem(result)) self.result_table.setItem(i, 2, QtWidgets.QTableWidgetItem(time_str)) # 设置颜色 if result == "PASS": self.result_table.item(i, 1).setBackground(QtGui.QColor(144, 238, 144)) elif result == "FAIL": self.result_table.item(i, 1).setBackground(QtGui.QColor(255, 99, 71)) else: self.result_table.item(i, 1).setBackground(QtGui.QColor(255, 165, 0)) self.result_table.resizeColumnsToContents() self.result_table.scrollToBottom() def add_log(self, message): """添加日志消息""" timestamp = datetime.datetime.now().strftime("%H:%M:%S.%f")[:-3] log_message = f"[{timestamp}] {message}" self.log_text.append(log_message) # 自动滚动到底部 self.log_text.verticalScrollBar().setValue( self.log_text.verticalScrollBar().maximum() ) def closeEvent(self, event): """关闭事件处理""" self.can_worker.running = False self.can_worker.quit() self.can_worker.wait(2000) # 等待2秒线程结束 self.can_worker.close_device() event.accept() def main(): app = QtWidgets.QApplication(sys.argv) app.setStyle('Fusion') # 设置应用程序信息 app.setApplicationName("测试上位机") app.setApplicationVersion("1.0.0") window = SIMTester() window.show() sys.exit(app.exec_()) if __name__ == "__main__": main()在这份代码中增加以上提到的功能
09-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值