STM32 BootLoader 刷新项目 (十三) Python上位机介绍
大家好,这是我们STM32 BootLoader的最后一篇文章了,讲述用Python写的上位机,也更新了半年时间了,谢谢大家的支持,到目前为止,已经更新了12篇文章了,想必大家对BootLoader已经有了个基本的了解,下面是Python上位机的全部源码,有需要的兄弟可以借鉴一下,水平有限。
以下是将完整Python代码中的每一行进行解释后的代码,注释全部用中文描述原代码的含义,并对每个函数、常量及代码块作详细中文说明:
1. 全局宏定义
import serial # 导入用于串口通信的模块
import struct # 导入结构化数据处理的模块
import os # 导入操作系统相关功能的模块
import sys # 导入系统功能模块
import glob # 导入文件路径操作模块# 常量定义 - Flash 操作状态
Flash_HAL_OK = 0x00 # Flash 操作成功
Flash_HAL_ERROR = 0x01 # Flash 操作错误
Flash_HAL_BUSY = 0x02 # Flash 操作繁忙
Flash_HAL_TIMEOUT = 0x03 # Flash 操作超时
Flash_HAL_INV_ADDR = 0x04 # Flash 操作地址无效# Bootloader命令定义
COMMAND_BL_GET_VER = 0x51 # 获取Bootloader版本
COMMAND_BL_GET_HELP = 0x52 # 获取支持的命令
COMMAND_BL_GET_CID = 0x53 # 获取芯片ID
COMMAND_BL_GET_RDP_STATUS = 0x54 # 获取读保护状态
COMMAND_BL_GO_TO_ADDR = 0x55 # 跳转到指定地址
COMMAND_BL_FLASH_ERASE = 0x56 # Flash擦除命令
COMMAND_BL_MEM_WRITE = 0x57 # Flash写入命令
COMMAND_BL_EN_R_W_PROTECT = 0x58 # 启用读写保护
COMMAND_BL_MEM_READ = 0x59 # 内存读取命令
COMMAND_BL_READ_SECTOR_P_STATUS = 0x5A # 读取扇区保护状态
COMMAND_BL_OTP_READ = 0x5B # 读取OTP(一次性可编程)区域
COMMAND_BL_DIS_R_W_PROTECT = 0x5C # 禁用读写保护
COMMAND_BL_MY_NEW_COMMAND = 0x5D # 用户自定义命令# 各命令的长度定义
COMMAND_BL_GET_VER_LEN = 6 # 获取Bootloader版本命令长度
COMMAND_BL_GET_HELP_LEN = 6 # 获取支持的命令长度
COMMAND_BL_GET_CID_LEN = 6 # 获取芯片ID命令长度
COMMAND_BL_GET_RDP_STATUS_LEN = 6 # 获取读保护状态命令长度
COMMAND_BL_GO_TO_ADDR_LEN = 10 # 跳转地址命令长度
COMMAND_BL_FLASH_ERASE_LEN = 8 # Flash擦除命令长度
COMMAND_BL_MEM_WRITE_LEN = 11 # Flash写入命令长度
COMMAND_BL_EN_R_W_PROTECT_LEN = 8 # 启用读写保护命令长度
COMMAND_BL_READ_SECTOR_P_STATUS_LEN = 6 # 读取扇区保护状态命令长度
COMMAND_BL_DIS_R_W_PROTECT_LEN = 6 # 禁用读写保护命令长度
COMMAND_BL_MY_NEW_COMMAND_LEN = 8 # 用户自定义命令长度# 全局变量
verbose_mode = 1 # 是否输出详细日志
mem_write_active = 0 # 写内存操作标志
2. 文件操作
# ----------------------------- 文件操作部分 ----------------------------------------# 计算文件长度
def calc_file_len():size = os.path.getsize("user_app.bin") # 获取文件 user_app.bin 的大小return size # 返回文件大小# 打开文件
def open_the_file():global bin_file # 声明全局变量 bin_filebin_file = open('user_app.bin', 'rb') # 以二进制只读方式打开文件 user_app.bin# 读取文件 - 占位函数
def read_the_file():pass # 暂未实现# 关闭文件
def close_the_file():bin_file.close() # 关闭文件句柄
上面文件操作这部分代码主要是针对BootLoader刷写过程中要打开写入的.bin文件。
3. 实用工具部分
# ----------------------------- 实用工具部分 ----------------------------------------# 地址转换为字节
def word_to_byte(addr, index, lowerfirst):value = (addr >> (8 * (index - 1)) & 0x000000FF) # 提取地址的某一字节return value # 返回字节值# CRC32校验计算
def get_crc(buff, length):Crc = 0xFFFFFFFF # 初始化CRC值for data in buff[0:length]: # 遍历缓冲区中所有字节Crc = Crc ^ data # 异或操作for i in range(32): # 遍历每一位if(Crc & 0x80000000): # 检测最高位Crc = (Crc << 1) ^ 0x04C11DB7 # CRC计算多项式else:Crc = (Crc << 1) # 左移操作return Crc # 返回计算结果
这部分主要是给后面代码做一些实用类的函数,方便后面调用,主要是两个,一个是将地址转化为字节。一个是用作CRC校验。
4. 串口部分
# ----------------------------- 串口部分 ----------------------------------------# 列出所有可用的串口
def serial_ports():"""列出系统中的所有串口名称"""if sys.platform.startswith('win'): # Windows系统ports = ['COM%s' % (i + 1) for i in range(256)] # 枚举所有可能的COM端口elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'): # Linux或Cygwin系统ports = glob.glob('/dev/tty[A-Za-z]*') # 查找所有TTY设备elif sys.platform.startswith('darwin'): # macOS系统ports = glob.glob('/dev/tty.*') # 查找所有TTY设备else:raise EnvironmentError('Unsupported platform') # 不支持的系统result = []for port in ports:try:s = serial.Serial(port) # 打开串口s.close() # 关闭串口result.append(port) # 将可用串口加入结果列表except (OSError, serial.SerialException): # 捕获异常passreturn result # 返回可用串口列表# 配置串口
def Serial_Port_Configuration(port):global ser # 声明全局变量 sertry:ser = serial.Serial(port, 115200, timeout=2) # 打开串口,波特率115200,超时时间2秒except:print("\n Oops! That was not a valid port") # 提示端口无效port = serial_ports() # 列出所有可用端口if not port:print("\n No ports Detected") # 未检测到端口else:print("\n Here are some available ports on your PC. Try Again!") # 提示可用端口print("\n ", port)return -1 # 返回错误码if ser.is_open:print("\n Port Open Success") # 串口打开成功else:print("\n Port Open Failed") # 串口打开失败return 0 # 返回成功码# 从串口读取数据
def read_serial_port(length):read_value = ser.read(length) # 读取指定长度的数据return read_value # 返回读取的数据# 关闭串口
def Close_serial_port():pass # 暂未实现# 清空串口缓冲区
def purge_serial_port():ser.reset_input_buffer() # 清空输入缓冲区# 向串口写入数据
def Write_to_serial_port(value, *length):data = struct.pack('>B', value) # 将值转换为单字节格式if verbose_mode:value = bytearray(data) # 将数据转换为字节数组print(" "+"0x{:02x}".format(value[0]), end=' ') # 输出写入数据if mem_write_active and not verbose_mode:print("#", end=' ') # 如果处于写入模式,显示#ser.write(data) # 将数据写入串口
上面串口通信部分的内容。
5. 命令处理
# ----------------------------- 命令处理部分 ----------------------------------------# 处理用户自定义命令的函数
def process_COMMAND_BL_MY_NEW_COMMAND(length):pass # 暂未实现# 处理获取Bootloader版本的命令
def process_COMMAND_BL_GET_VER(length):ver = read_serial_port(1) # 从串口读取1字节数据value = bytearray(ver) # 转换为字节数组print("\n Bootloader Ver. : ", hex(value[0])) # 打印版本号(以十六进制显示)# 处理获取支持的命令列表
def process_COMMAND_BL_GET_HELP(length):value = read_serial_port(length) # 从串口读取指定长度的数据reply = bytearray(value) # 转换为字节数组print("\n Supported Commands :", end=' ') # 打印支持的命令for x in reply:print(hex(x), end=' ') # 逐个打印每个命令print()# 处理获取芯片ID的命令
def process_COMMAND_BL_GET_CID(length):value = read_serial_port(length) # 从串口读取数据ci = (value[1] << 8) + value[0] # 解析两字节数据组成芯片IDprint("\n Chip Id. : ", hex(ci)) # 打印芯片ID# 处理获取读保护状态的命令
def process_COMMAND_BL_GET_RDP_STATUS(length):value = read_serial_port(length) # 从串口读取数据rdp = bytearray(value) # 转换为字节数组print("\n RDP Status : ", hex(rdp[0])) # 打印读保护状态# 处理跳转到指定地址的命令
def process_COMMAND_BL_GO_TO_ADDR(length):addr_status = 0value = read_serial_port(length) # 从串口读取数据addr_status = bytearray(value) # 转换为字节数组print("\n Address Status : ", hex(addr_status[0])) # 打印地址状态# 处理Flash擦除命令
def process_COMMAND_BL_FLASH_ERASE(length):erase_status = 0value = read_serial_port(length) # 从串口读取数据if len(value):erase_status = bytearray(value) # 转换为字节数组if erase_status[0] == Flash_HAL_OK: # 判断擦除结果print("\n Erase Status: Success Code: FLASH_HAL_OK")elif erase_status[0] == Flash_HAL_ERROR:print("\n Erase Status: Fail Code: FLASH_HAL_ERROR")elif erase_status[0] == Flash_HAL_BUSY:print("\n Erase Status: Fail Code: FLASH_HAL_BUSY")elif erase_status[0] == Flash_HAL_TIMEOUT:print("\n Erase Status: Fail Code: FLASH_HAL_TIMEOUT")elif erase_status[0] == Flash_HAL_INV_ADDR:print("\n Erase Status: Fail Code: FLASH_HAL_INV_SECTOR")else:print("\n Erase Status: Fail Code: UNKNOWN_ERROR_CODE")else:print("Timeout: Bootloader is not responding") # 超时未响应# 处理内存写入命令
def process_COMMAND_BL_MEM_WRITE(length):write_status = 0value = read_serial_port(length) # 从串口读取数据write_status = bytearray(value) # 转换为字节数组if write_status[0] == Flash_HAL_OK: # 判断写入结果print("\n Write_status: FLASH_HAL_OK")elif write_status[0] == Flash_HAL_ERROR:print("\n Write_status: FLASH_HAL_ERROR")elif write_status[0] == Flash_HAL_BUSY:print("\n Write_status: FLASH_HAL_BUSY")elif write_status[0] == Flash_HAL_TIMEOUT:print("\n Write_status: FLASH_HAL_TIMEOUT")elif write_status[0] == Flash_HAL_INV_ADDR:print("\n Write_status: FLASH_HAL_INV_ADDR")else:print("\n Write_status: UNKNOWN_ERROR")print("\n")# 处理Flash批量擦除命令(未实现)
def process_COMMAND_BL_FLASH_MASS_ERASE(length):pass # 暂未实现# 扇区保护模式选项
protection_mode = ["Write Protection", "Read/Write Protection", "No protection"] # 定义保护模式描述# 根据保护状态解析保护模式
def protection_type(status, n):if status & (1 << 15): # 检查是否启用PCROPif status & (1 << n): # 检查扇区的保护位return protection_mode[1] # 读写保护模式else:return protection_mode[2] # 无保护模式else:if status & (1 << n):return protection_mode[2] # 无保护模式else:return protection_mode[0] # 写保护模式# 处理读取扇区保护状态的命令
def process_COMMAND_BL_READ_SECTOR_STATUS(length):s_status = 0value = read_serial_port(length) # 从串口读取数据s_status = bytearray(value) # 转换为字节数组print("\n Sector Status : ", s_status[0]) # 打印扇区状态print("\n ====================================")print("\n Sector \tProtection") print("\n ====================================")if s_status[0] & (1 << 15): # 检查PCROP模式print("\n Flash protection mode : Read/Write Protection(PCROP)\n")else:print("\n Flash protection mode : \tWrite Protection\n")for x in range(8): # 遍历每个扇区print("\n Sector{0} {1}".format(x, protection_type(s_status[0], x)))# 处理禁用读写保护的命令
def process_COMMAND_BL_DIS_R_W_PROTECT(length):status = 0value = read_serial_port(length) # 从串口读取数据status = bytearray(value) # 转换为字节数组if status[0]: # 检查返回状态print("\n FAIL")else:print("\n SUCCESS")# 处理启用读写保护的命令
def process_COMMAND_BL_EN_R_W_PROTECT(length):status = 0value = read_serial_port(length) # 从串口读取数据status = bytearray(value) # 转换为字节数组if status[0]: # 检查返回状态print("\n FAIL")else:print("\n SUCCESS")
解释:
- 代码中定义了多个命令处理函数,用于根据命令解析返回数据并打印结果。
- 使用位操作来判断和解析各种Flash状态(如保护模式、PCROP等)。
- 核心功能包括读取芯片状态、擦除Flash、内存写入、设置保护等。
6. 菜单操作
下面是 decode_menu_command_code
函数及相关逻辑。
# 解码菜单中的命令代码并处理
def decode_menu_command_code(command):ret_value = 0 # 返回值,用于指示命令处理状态data_buf = [] # 数据缓冲区for i in range(255):data_buf.append(0) # 初始化缓冲区,大小为255字节# 菜单退出命令if command == 0:print("\n Exiting...!") # 打印退出信息raise SystemExit # 退出程序# 命令1:获取Bootloader版本elif command == 1:print("\n Command == > BL_GET_VER") # 显示所选命令COMMAND_BL_GET_VER_LEN = 6 # 定义命令长度data_buf[0] = COMMAND_BL_GET_VER_LEN - 1 # 数据帧的长度字段data_buf[1] = COMMAND_BL_GET_VER # 设置命令代码crc32 = get_crc(data_buf, COMMAND_BL_GET_VER_LEN - 4) # 计算CRC校验值crc32 = crc32 & 0xffffffff # 将CRC限制为32位# 将CRC校验值分解成4个字节data_buf[2] = word_to_byte(crc32, 1, 1)data_buf[3] = word_to_byte(crc32, 2, 1)data_buf[4] = word_to_byte(crc32, 3, 1)data_buf[5] = word_to_byte(crc32, 4, 1)# 发送数据帧的每个字节到串口Write_to_serial_port(data_buf[0], 1)for i in data_buf[1:COMMAND_BL_GET_VER_LEN]:Write_to_serial_port(i, COMMAND_BL_GET_VER_LEN - 1)# 读取并处理Bootloader返回的数据ret_value = read_bootloader_reply(data_buf[1])# 命令2:获取支持的命令elif command == 2:print("\n Command == > BL_GET_HELP")COMMAND_BL_GET_HELP_LEN = 6data_buf[0] = COMMAND_BL_GET_HELP_LEN - 1data_buf[1] = COMMAND_BL_GET_HELPcrc32 = get_crc(data_buf, COMMAND_BL_GET_HELP_LEN - 4)crc32 = crc32 & 0xffffffffdata_buf[2] = word_to_byte(crc32, 1, 1)data_buf[3] = word_to_byte(crc32, 2, 1)data_buf[4] = word_to_byte(crc32, 3, 1)data_buf[5] = word_to_byte(crc32, 4, 1)Write_to_serial_port(data_buf[0], 1)for i in data_buf[1:COMMAND_BL_GET_HELP_LEN]:Write_to_serial_port(i, COMMAND_BL_GET_HELP_LEN - 1)ret_value = read_bootloader_reply(data_buf[1])# 命令3:获取芯片IDelif command == 3:print("\n Command == > BL_GET_CID")COMMAND_BL_GET_CID_LEN = 6data_buf[0] = COMMAND_BL_GET_CID_LEN - 1data_buf[1] = COMMAND_BL_GET_CIDcrc32 = get_crc(data_buf, COMMAND_BL_GET_CID_LEN - 4)crc32 = crc32 & 0xffffffffdata_buf[2] = word_to_byte(crc32, 1, 1)data_buf[3] = word_to_byte(crc32, 2, 1)data_buf[4] = word_to_byte(crc32, 3, 1)data_buf[5] = word_to_byte(crc32, 4, 1)Write_to_serial_port(data_buf[0], 1)for i in data_buf[1:COMMAND_BL_GET_CID_LEN]:Write_to_serial_port(i, COMMAND_BL_GET_CID_LEN - 1)ret_value = read_bootloader_reply(data_buf[1])# 命令4:获取读保护状态elif command == 4:print("\n Command == > BL_GET_RDP_STATUS")data_buf[0] = COMMAND_BL_GET_RDP_STATUS_LEN - 1data_buf[1] = COMMAND_BL_GET_RDP_STATUScrc32 = get_crc(data_buf, COMMAND_BL_GET_RDP_STATUS_LEN - 4)crc32 = crc32 & 0xffffffffdata_buf[2] = word_to_byte(crc32, 1, 1)data_buf[3] = word_to_byte(crc32, 2, 1)data_buf[4] = word_to_byte(crc32, 3, 1)data_buf[5] = word_to_byte(crc32, 4, 1)Write_to_serial_port(data_buf[0], 1)for i in data_buf[1:COMMAND_BL_GET_RDP_STATUS_LEN]:Write_to_serial_port(i, COMMAND_BL_GET_RDP_STATUS_LEN - 1)ret_value = read_bootloader_reply(data_buf[1])# 命令5:跳转到指定地址elif command == 5:print("\n Command == > BL_GO_TO_ADDR")go_address = input("\n Please enter 4 bytes go address in hex:") # 提示用户输入地址go_address = int(go_address, 16) # 将输入的地址转换为十六进制整数data_buf[0] = COMMAND_BL_GO_TO_ADDR_LEN - 1data_buf[1] = COMMAND_BL_GO_TO_ADDR# 将地址分解为字节data_buf[2] = word_to_byte(go_address, 1, 1)data_buf[3] = word_to_byte(go_address, 2, 1)data_buf[4] = word_to_byte(go_address, 3, 1)data_buf[5] = word_to_byte(go_address, 4, 1)# 计算CRC校验值crc32 = get_crc(data_buf, COMMAND_BL_GO_TO_ADDR_LEN - 4)data_buf[6] = word_to_byte(crc32, 1, 1)data_buf[7] = word_to_byte(crc32, 2, 1)data_buf[8] = word_to_byte(crc32, 3, 1)data_buf[9] = word_to_byte(crc32, 4, 1)Write_to_serial_port(data_buf[0], 1)for i in data_buf[1:COMMAND_BL_GO_TO_ADDR_LEN]:Write_to_serial_port(i, COMMAND_BL_GO_TO_ADDR_LEN - 1)ret_value = read_bootloader_reply(data_buf[1])# 其余命令逻辑类似,均是设置命令代码、填充参数、计算CRC并发送。# 如果命令无效else:print("\n Please input valid command code\n")return# 处理超时的情况if ret_value == -2:print("\n TimeOut : No response from the bootloader")print("\n Reset the board and Try Again !")return
功能总结:
decode_menu_command_code
函数是主命令处理入口,根据用户选择的命令代码执行对应操作。- 每个命令都包括以下步骤:
- 填充数据缓冲区,包括命令代码和参数。
- 计算数据缓冲区的 CRC 校验值。
- 将数据通过串口发送到目标设备。
- 读取并处理设备返回的数据。
7. 接收下位机数据处理
read_bootloader_reply
函数及菜单循环处理逻辑。
# 读取Bootloader的返回信息
def read_bootloader_reply(command_code):len_to_follow = 0 # 用于存储设备返回数据的长度ret = -2 # 默认返回值,-2表示超时或无响应# 从串口读取2字节(ACK/NACK信息)ack = read_serial_port(2)if len(ack): # 如果读取到了数据a_array = bytearray(ack) # 转换为字节数组if a_array[0] == 0xA5: # 检查是否接收到ACK(0xA5)len_to_follow = a_array[1] # 第二字节为后续数据长度print("\n CRC : SUCCESS Len :", len_to_follow) # 打印CRC校验成功及返回数据长度# 根据命令代码调用对应的处理函数if command_code == COMMAND_BL_GET_VER:process_COMMAND_BL_GET_VER(len_to_follow)elif command_code == COMMAND_BL_GET_HELP:process_COMMAND_BL_GET_HELP(len_to_follow)elif command_code == COMMAND_BL_GET_CID:process_COMMAND_BL_GET_CID(len_to_follow)elif command_code == COMMAND_BL_GET_RDP_STATUS:process_COMMAND_BL_GET_RDP_STATUS(len_to_follow)elif command_code == COMMAND_BL_GO_TO_ADDR:process_COMMAND_BL_GO_TO_ADDR(len_to_follow)elif command_code == COMMAND_BL_FLASH_ERASE:process_COMMAND_BL_FLASH_ERASE(len_to_follow)elif command_code == COMMAND_BL_MEM_WRITE:process_COMMAND_BL_MEM_WRITE(len_to_follow)elif command_code == COMMAND_BL_READ_SECTOR_P_STATUS:process_COMMAND_BL_READ_SECTOR_STATUS(len_to_follow)elif command_code == COMMAND_BL_EN_R_W_PROTECT:process_COMMAND_BL_EN_R_W_PROTECT(len_to_follow)elif command_code == COMMAND_BL_DIS_R_W_PROTECT:process_COMMAND_BL_DIS_R_W_PROTECT(len_to_follow)elif command_code == COMMAND_BL_MY_NEW_COMMAND:process_COMMAND_BL_MY_NEW_COMMAND(len_to_follow)else:print("\n Invalid command code\n") # 无效的命令代码ret = 0 # 返回0表示命令处理成功elif a_array[0] == 0x7F: # 如果接收到NACK(0x7F)print("\n CRC: FAIL \n") # 打印CRC校验失败ret = -1 # 返回-1表示CRC校验失败else:print("\n Timeout : Bootloader not responding") # 超时未响应return ret # 返回处理结果
8. 菜单显示
# ----------------------------- 菜单循环逻辑 ----------------------------------------# 提示用户输入设备串口号
name = input("Enter the Port Name of your device(Ex: COM3):")
ret = 0 # 用于存储串口配置的返回值
ret = Serial_Port_Configuration(name) # 配置串口
if ret < 0: # 如果配置失败decode_menu_command_code(0) # 退出程序# 无限循环显示菜单
while True:print("\n +==========================================+")print(" | Menu |")print(" | STM32F4 BootLoader v1 |")print(" +==========================================+")# 打印可用命令的列表print("\n Which BL command do you want to send ??\n")print(" BL_GET_VER --> 1")print(" BL_GET_HLP --> 2")print(" BL_GET_CID --> 3")print(" BL_GET_RDP_STATUS --> 4")print(" BL_GO_TO_ADDR --> 5")print(" BL_FLASH_MASS_ERASE --> 6")print(" BL_FLASH_ERASE --> 7")print(" BL_MEM_WRITE --> 8")print(" BL_EN_R_W_PROTECT --> 9")print(" BL_MEM_READ --> 10")print(" BL_READ_SECTOR_P_STATUS --> 11")print(" BL_OTP_READ --> 12")print(" BL_DIS_R_W_PROTECT --> 13")print(" BL_MY_NEW_COMMAND --> 14")print(" MENU_EXIT --> 0")# 提示用户输入命令代码command_code = input("\n Type the command code here :")# 检查输入是否为有效的数字if not command_code.isdigit():print("\n Please Input valid code shown above") # 提示无效输入else:# 解码并执行用户选择的命令decode_menu_command_code(int(command_code))# 等待用户按任意键继续input("\n Press any key to continue :")purge_serial_port() # 清空串口缓冲区
功能说明:
-
read_bootloader_reply
函数:- 用于解析Bootloader的返回数据。
- 先读取2字节的数据(ACK/NACK和后续数据长度)。
- 如果CRC校验成功(ACK为
0xA5
),调用相应的处理函数。 - 如果接收到
0x7F
,表示CRC校验失败。 - 如果没有任何返回,表示设备超时未响应。
-
菜单循环:
- 通过
while True
创建无限循环,用于显示Bootloader命令菜单。 - 提示用户输入命令代码(如获取版本、擦除Flash等)。
- 验证用户输入是否有效(必须是数字)。
- 调用
decode_menu_command_code
函数根据用户输入执行相应命令。 - 提供按任意键继续的功能,以便用户可以反复选择命令。
- 每次循环结束后清空串口缓冲区。
- 通过
整体逻辑:
- 程序启动时,要求用户输入设备的串口号。
- 程序与目标设备建立通信后,进入菜单界面。
- 用户根据提示输入命令代码,程序解析并发送相应的Bootloader命令。
- 根据设备返回的数据,显示操作结果。
- 用户可以重复操作,直到输入退出命令(命令代码
0
)为止。
至此,整个代码的功能和实现已经完全解释。如果还有特定部分需要详细说明或补充,请向我联系!
9. 实战操作
下面是上位机的命令菜单,通过在终端调用Python脚本,然后在终端输入下位机连接的串口号,即可进入命令界面,目前可支持如下命令:
其他的操作也在之前的文章中做了介绍,有兴趣的可以查找我之前的文章。
STM32 BootLoader 刷新项目 (一) STM32CubeMX UART串口通信工程搭建
STM32 BootLoader 刷新项目 (二) 方案介绍
STM32 BootLoader 刷新项目 (三) 程序框架搭建及刷新演示
STM32 BootLoader 刷新项目 (四) 通信协议
STM32 BootLoader 刷新项目 (五) 获取软件版本号-命令0x51
STM32 BootLoader 刷新项目 (六) 获取帮助-命令0x52
STM32 BootLoader 刷新项目 (七) 获取芯片ID-0x53
STM32 BootLoader 刷新项目 (八) 读取Flash保护ROP-0x54
STM32 BootLoader 刷新项目 (九) 跳转指定地址-命令0x55
[STM32 BootLoader 刷新项目 (十) Flash擦除-命令0x56](STM32 BootLoader 刷新项目 (十) Flash擦除-命令0x56-CSDN博客)
STM32 BootLoader 刷新项目 (十一) Flash写操作-命令0x57
STM32 BootLoader 刷新项目 (十二) Option Byte之FLASH_OPTCR-命令0x58