导言


想象一下,我们的单片机 App 正在稳定地运行着,突然我们想给它升级一下,添加个新功能。我们该如何安全地通知它:“嘿,准备好接收新固件了” ? 这就需要 App 和 Bootloader 之间建立一个可靠的"秘密握手"机制。

整个流程就像一次精心策划的"交接仪式":

  1. 外部通知:上位机(比如我们的电脑)通过串口向正在运行的 App 发送一个预设好的"升级"指令。
  2. 设置信物:App 收到指令后,并不会立刻停止工作,而是在一块共享的 RAM 内存中写入一个"暗号"(我们称之为"升级标志位")。这块内存就像是 App 留给 Bootloader 的一个"秘密信箱"。
  3. 主动重启:留下"暗号"后,App 主动触发一次软件复位,开始"交接"。
  4. 验证信物:系统重启后,控制权首先交给 Bootloader。Bootloader 会立刻检查那个"秘密信箱"。
    • 如果发现了预设的"暗号",它就知道:“哦,App 需要我来执行升级任务”,随即进入 IAP(In-Application Programming)模式,准备接收新固件。
    • 如果信箱是空的,它就认为一切正常,直接跳转到 App,让 App 像往常一样运行。

在这里插入图片描述
为了简化演示,我们约定,当 App 的串口收到字符串 A5A5A5A5 时,就触发这次跳转。

在这里插入图片描述

友情提示:在真实的商业项目中,简单的字符串匹配是远远不够的。为了保证通信的绝对可靠,防止数据干扰导致意外的固件升级,我们必须引入 CRC 校验 等错误检测机制。这里的 A5A5A5A5 只是一个为了教学目的而简化的触发信号。

项目地址:

  • Gitee (国内推荐): https://gitee.com/wallace89/MCU_Develop/tree/main/bootloader11_stm32f103_app_jump_boot
  • GitHub: https://github.com/q164129345/MCU_Develop/tree/main/bootloader11_stm32f103_app_jump_boot

一、App 端代码


现在,我们来看看 App 程序需要增加哪些代码来实现这个"交接仪式"。

1.1、 jump_boot.c

这个文件负责处理从 App 跳转到 Bootloader 的所有核心逻辑。

#include "bootloader_define.h"
#include "flash_map.h"
#include "jump_boot.h"#if defined(__IS_COMPILER_ARM_COMPILER_5__)
volatile uint64_t update_flag __attribute__((at(FIRMWARE_UPDATE_VAR_ADDR), zero_init));#elif defined(__IS_COMPILER_ARM_COMPILER_6__)#define __INT_TO_STR(x)     #x#define INT_TO_STR(x)       __INT_TO_STR(x)volatile uint64_t update_flag __attribute__((section(".bss.ARM.__at_" INT_TO_STR(FIRMWARE_UPDATE_VAR_ADDR))));#else#error "variable placement not supported for this compiler."
#endif/*** @brief  获取固件升级标志位* @note   读取保存于指定RAM地址的升级标志变量(通常用于判断bootloader的运行状态)* @retval uint64_t 固件升级标志的当前值*/
static uint64_t IAP_GetUpdateFlag(void)
{return update_flag;
}/*** @brief  设置固件升级标志位* @param  flag 需要设置的标志值* @note   修改指定RAM地址的升级标志变量* @retval 无*/
static void IAP_SetUpdateFlag(uint64_t flag)
{update_flag = flag;
}/*** @brief  解析串口接收到的数据* @note   根据接收到的数据,判断是否需要跳转到Bootloader*         目标字符串: "A5A5A5A5" (8字节)*         ASCII: 0x41,0x35,0x41,0x35,0x41,0x35,0x41,0x35* @param  data 接收到的数据* @retval 无*/
void IAP_Parse_Command(uint8_t data)
{// 目标字符串"A5A5A5A5"的ASCII码序列static const uint8_t target_sequence[8] = {0x41, 0x35, 0x41, 0x35,  // "A5A5"0x41, 0x35, 0x41, 0x35   // "A5A5"};// 静态变量:记录当前匹配的字节位置static uint8_t match_index = 0;// 检查当前字节是否与目标序列匹配if (data == target_sequence[match_index]) {match_index++;  // 匹配成功,移动到下一个位置// 检查是否接收完整的8字节序列if (match_index >= sizeof(target_sequence)) {// 完整匹配成功,跳转到Bootloadermatch_index = 0;  // 重置状态,为下次做准备//! 设置固件升级标志位IAP_SetUpdateFlag(FIRMWARE_UPDATE_MAGIC_WORD);//! 等待10ms,确保标志位设置成功LL_mDelay(10);//!此函数不会返回,MCU将复位NVIC_SystemReset();}} else {// 不匹配,重置状态机match_index = 0;// 特殊处理:如果当前字节恰好是序列的第一个字节,则开始新的匹配if (data == target_sequence[0]) {match_index = 1;}}
}

代码亮点解析:

  1. update_flag 变量的定义

    • __attribute__((at(...))): 这是告诉编译器:“请务必把 update_flag 这个变量放在 FIRMWARE_UPDATE_VAR_ADDR 这个内存地址上”。这就像给 App 和 Bootloader 一个共同的、固定的"信箱"地址,确保双方都能找到对方。
    • volatile: 这个关键字至关重要。它告诉编译器:“这个变量的值随时可能被意想不到的方式改变(比如被硬件或其他程序),所以你不要自作聪明地去优化它。每次使用它的时候,都必须老老实实地从内存里重新读取”。这可以防止 App 重启后,Bootloader 读到一个被缓存的、不正确的值。
  2. IAP_Parse_Command 函数

    • 这个函数就像一个"哨兵",时刻监听着串口发来的每一个字节。
    • 它内部的 match_index 就像一个进度条,记录着"秘密口令"的匹配进度。每收到一个正确的字符,进度条就加一;一旦收到错误的字符,进度条就清零重来,非常严谨。
    • 当8个字符全部匹配成功,就意味着"口令正确",哨兵就会立刻执行预设的三个步骤:写标志、延时、复位

1.2、jump_boot.h

头文件很简单,主要是声明 IAP_Parse_Command 函数,以便在其他文件中(比如串口中断服务程序中)调用它。

/*** @file    jump_boot.h* @brief   应用程序与Bootloader跳转功能的头文件声明* @author  Wallace.zhang* @date    2025-05-25* @version 1.0.0*/#ifndef __JUMP_BOOT_H
#define __JUMP_BOOT_H#ifdef __cplusplus
extern "C" {
#endif#include <stdint.h>
#include "main.h"
#include <stdbool.h>/*** @brief  解析串口接收到的数据,判断是否需要跳转到Bootloader* @param  data 接收到的单个字节*/
void IAP_Parse_Command(uint8_t data);#ifdef __cplusplus
}
#endif#endif /* __JUMP_BOOT_H */

1.3、myUsartDrive_reg.c

在这里插入图片描述
如上图所示,在USART1的接收ringbuffer里,一个一个字节拿出去解析。

二、功能测试


现在,让我们来验证一下"交接仪式"是否能顺利进行。

2.1、测试 App 跳转到 Bootloader

我们使用一个 Python 脚本来模拟上位机,向单片机发送"秘密口令"。
在这里插入图片描述
操作步骤:

  1. 将 App 程序下载到 STM32 开发板并运行。
  2. 在项目 iap_py 文件夹下打开终端,运行以下指令(请根据你的实际情况修改 COM 口):
    python3 jump_command.py --port COM8 --baud 115200
    
  3. 观察 RTT Viewer 的日志。Bootloader 的日志出现,这表明 App 成功复位并跳转到了 Bootloader!
    在这里插入图片描述

jump_command.py 脚本是做什么的?
它其实很简单,就是通过指定的串口(--port)和波特率(--baud),向上位机发送了一串文本 A5A5A5A5

脚本参数说明:

  • --port: 你的设备所连接的串口号 (必填),例如 COM8 (Windows) 或 /dev/ttyUSB0 (Linux)。
  • --baud: 波特率 (可选),默认为 115200

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/87237.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/87237.shtml
英文地址,请注明出处:http://en.pswp.cn/web/87237.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Explain解释

参考官方文档&#xff1a;https://dev.mysql.com/doc/refman/5.7/en/explain-output.html explain关键字可以分析你的查询语句的结构和性能。 explain select查询&#xff0c; 执行会返回执行计划的信息。 注意&#xff1a;如果from中有子查询&#xff0c;仍然会执行该子查询…

选择 PDF 转 HTML 转换器的 5 个关键特性

市面上有很多 PDF 转 HTML 的转换器&#xff0c;每一款产品都有不同的功能组合。要理清并理解每个功能可能会让人感到困惑。那么&#xff0c;真正重要的是什么呢&#xff1f; 这篇文章将介绍我们认为在选择最佳 PDF 转 HTML 转换器时最重要的 5 个关键特性&#xff1a; 1. 转换…

使用堡塔在服务器上部署宝塔面板-linux版

使用堡塔在服务器上部署宝塔面板-linux版 使用堡塔多机管理登录服务器 进入宝塔官网&#xff0c;获取安装脚本 wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh && sudo bash install_panel.sh ed8484bec3. 在堡塔多机管理中&#xff0c;…

【Unity高级】Unity多界面游戏场景管理方案详解

引言&#xff1a;游戏界面管理的挑战 在Unity游戏开发中&#xff0c;尤其是包含多个功能界面&#xff08;如主菜单、关卡选择、游戏页面、设置和商城&#xff09;的游戏&#xff0c;如何高效管理场景与界面是架构设计的核心挑战。本文将深入探讨三种主流实现方案&#xff1a;单…

WINDOWS最快布署WEB服务器:apache2

安装JDK下载 https://tomcat.apache.org/ Index of /dist/tomcat/tomcat-9 安装测试 http://localhost:8080/ 替换自己的文件 把自己的文件复制到&#xff1a; C:\Program Files\Apache Software Foundation\Tomcat 9.0\webapps\ROOT

Microsoft Edge 打开无反应、打开后显示兼容性问题、卸载重装 解决方案。一键卸载Microsoft Edge 。

背景&#xff1a;网络上的浏览器修复、重装、恢复默认应用测试后无用&#xff0c;以下卸载重装方案经实测可以正常使用Microsoft Edg。 卸载软件在资源里&#xff0c;请自取。 一、卸载软件&#xff1a;Remove-Edge_GUI.exe 双击卸载等待即可。 二、在微软商店重新安装Micro…

Spring Boot - 参数校验:分组校验、自定义注解、嵌套对象全解析

01 依赖配置 在构建高效的校验体系前&#xff0c;需先完善项目依赖配置。 以下是优化后的依赖示例&#xff1a; <dependencies><!-- Web 依赖&#xff0c;提供 RESTful 接口支持 --><dependency><groupId>org.springframework.boot</groupId>…

深入浅出多模态》(十一)之多模态经典模型:Flamingo系列

&#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系的学习资料&#xff0c;配有全面而有深度的专栏内容&#xff0c;包括不限于 前沿论文解读、…

基于Pandas和FineBI的昆明职位数据分析与可视化实现(三)- 职位数据统计分析

文章目录 一、职位数据分析1. 一级分类职位数量统计分析2. 职位二级分类分布分析3. 职位分布分析4. 工作经验需求分布分析5. 学历要求职位分布分析6. 企业职位供给前507. 不同规模公司的职位数量统计8. 区域职位分布分析9. 各区域平均薪资范围分布分析10. 不同工作经验平均薪资…

大数据Hadoop之——安装部署hadoop

目录 前期准备 一、JDK的安装 1、安装jdk 2、配置Java环境变量 3、加载环境变量 4、进行校验 二、hadoop的环境搭建 1、hadoop的下载安装 2、配置文件设置 2.1. 配置 hadoop-env.sh 2.2. 配置 core-site.xml 2.3. 配置 hdfs-site.xml 2.4. 配置 yarn-site.xml 2.…

Spring IoC DI介绍

文章目录 IoC & DI 介绍IoC介绍DI 介绍 组件注册Bean 命名约定方法注解 Bean总结 扫描路径DI 详解属性注入构造方法注入Setter 注入三种注入优缺点分析 当同一类型存在多个Bean时,直接使用Autowired会存在问题使用Primary注解使用Qualifier注解使用Bean的名称使用Resource注…

【Flutter】解决 flutter_inappwebview在 Windows 上使用导致应用闪退问题

问题背景 在 Windows 11 上运行 Flutter 桌面应用时&#xff0c;应用出现闪退现象。通过系统事件日志分析&#xff0c;发现是 MSVCP140.dll 模块的访问冲突异常&#xff08;错误代码 c0000005&#xff09;导致的崩溃。 问题分析 1. 错误现象 应用启动后立即闪退Windows 事件…

使用 JavaScript、Mastra 和 Elasticsearch 构建一个具备代理能力的 RAG 助手

作者&#xff1a;来自 Elastic JD Armada 了解如何在 JavaScript 生态系统中构建 AI 代理。 Elasticsearch 与业界领先的生成式 AI 工具和服务商有原生集成。查看我们的网络研讨会&#xff0c;了解如何超越 RAG 基础&#xff0c;或使用 Elastic 向量数据库构建可投入生产的应用…

Active Directory 环境下 Linux Samba 文件共享服务建设方案

Active Directory 环境下 Linux Samba 文件共享服务建设方案 目录 需求分析方案总体设计技术架构与选型详细部署规划共享文件性能测试非域终端共享配置运维与权限安全管理建议1. 需求分析 因某公司(编的)新增多个部门,各部门之间存在多类型终端系统,但又有同时访问文件库…

Python爬虫网安-项目-简单网站爬取

源码&#xff1a; https://github.com/Wist-fully/Attack/tree/pc pc_p1 目标&#xff1a; 1.进入列表页&#xff0c;顺着列表爬取每个电影详情页 2.利用正则来提取&#xff0c;海报&#xff0c;名称&#xff0c;类别&#xff0c;上映的时间&#xff0c;评分&#xff0c;剧…

Golang中的数组

Golang Array和以往认知的数组有很大不同。有点像Python中的列表 1. 数组&#xff1a;是同一种数据类型的固定长度的序列。 2. 数组定义&#xff1a;var a [len]int&#xff0c;比如&#xff1a;var a [5]int&#xff0c;数组长度必须是常量&#xff0c;且是类型的组成部分。一…

《Origin画百图》之矩阵散点图

矩阵散点图的作用 一、直观展示多变量间的两两关系 矩阵散点图的基本单元是两两变量的散点图&#xff0c;每个散点图对应矩阵中的一个单元格&#xff0c;可直接反映变量间的&#xff1a; 相关性方向&#xff1a;正相关&#xff08;散点向右上倾斜&#xff09;或负相关&#x…

Flask文件下载send_file中文文件名处理解决方案

Flask文件下载send_file中文文件名处理解决方案 Flask文件下载中文文件名处理解决方案问题背景问题分析核心问题常见症状 解决方案技术实现关键技术点 完整实现示例 Flask文件下载中文文件名处理解决方案 问题背景 在Web应用开发中&#xff0c;当用户下载包含中文字符的文件时…

新手指南:在 Ubuntu 上安装 PostgreSQL 并通过 VS Code 连接及操作

本文档记录了一个初学者在 Ubuntu 系统上安装、配置 PostgreSQL 数据库&#xff0c;并使用 Visual Studio Code (VS Code) 作为客户端进行连接和操作的全过程。其中包含了遇到的常见错误、分析和最终的解决方案&#xff0c;旨在为新手提供一个清晰、可复现的操作路径。 最终目…

二刷 苍穹外卖day10(含bug修改)

Spring Task Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑 cron表达式 一个字符串&#xff0c;通过cron表达式可以定义任务触发的时间 **构成规则&#xff1a;**分为6或7个域&#xff0c;由空格分隔开&#xff0c;每个域代表一个含义 …