基于STM32f103芯片的应用程序在线升级功能框架的实现

目录

基于STM32f103芯片的应用程序在线升级功能框架的实现

一、原理简介

二、KEIL软件主要设置

三、应用程序app部分

四、Bootloader部分

五、补充部分


基于STM32f103芯片的应用程序在线升级功能框架的实现

一、原理简介

我们在使用stm32的过程中,如果需要对芯片的软件程序进行在线升级,一般会将软件程序分为bootloader程序以及应用程序app。
在bootloader程序中,系统上电后,通过进行条件判断确定是否需要对硬件板卡进行软件升级,如果不需要进行升级就直接跳转到app程序进行执行。如果需要进行软件升级,那么就在bootloader中完成对软件的升级操作。这里以stm32f103ze系列进行说明。    

二、KEIL软件主要设置

这里将软件程序分为bootloader和app两部分。
其中bootloader代码部分的起始地址为:0x08000000,大小为0x4000(16KB);
app部分的代码起始地址为:0x08004000,大小为0x7C000(512KB-16KB)。    //芯片flash总大小为512KB
在keil软件的魔术棒下的Target设置框下,按照以上信息在IROM1中分别设置好软件程序对应的起始地址和大小即可。

三、应用程序app部分

1、固定版本号信息
在应用程序app中,可以通过固化app程序版本号的位置作为后续判断硬件板卡是否需要升级的条件。具体代码如下:  
//在app中固定硬件板卡版本号V1.00的存储位置为0x0800F800。
const unsigned char Ver[6] __attribute__ ((at(0x0800F800)))= {'V','1','.','0','0'};
固定好硬件板卡的版本号信息后,我们后续在bootloader中通过读取该位置的版本号信息进行判断是否需要进行升级操作。
2、升级前擦除版本号所在的flash页内容。
关于对stm32的flash进行擦除的操作,不同的芯片操作方式可能有所不同。有的芯片是按页进行擦除有的芯片是按照扇区进行擦除。这里使用的stm32f103是采用页擦除的方式。具体代码如下:void RunUpdateCommand()
{uint8_t *p;p = (uint8_t *)((uint32_t)0x0800F800);printf("擦除前FLASH地址0x0800F800存放的字符为:%c\n",*p);FLASH_Unlock();if(FLASH_ErasePage(0x0800F800) == FLASH_COMPLETE){FLASH_Lock();printf("擦除后FLASH地址0x0800F800存放的字符为:%c\n",*p);  }printf("================进入bootloader程序===============\n");NVIC_SystemReset();while(1);
}
​
这里在app程序中,进入bootloader程序执行升级操作前首先会擦除原来的版本号所在的flash页内容。然后使用函数NVIC_SystemReset()进行复位操作从而进入到bootloader程序中。
3、app的主函数部分代码
应用程序app主函数main的主要代码如下:void main()
{SystemInit();   //系统初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);     //设置优先级分组NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x4000);     //设置app程序的向量表偏移位置__disable_irq();/* 在这里进行硬件外设的初始化操作*/__enable_irq();while(1){//应用程序的代码部分    }
}

四、Bootloader部分

bootloader部分的核心代码如下:
​
typedef void (*pFunction)(void);    //定义函数指针pFunction,用于实现函数的跳转
​
//定义APP版本号地址,需要和app中的存储地址对应
#define APP_VERSION_ADDR    ((uint32_t)0x0800F800)  
​
//定义APP的起始地址,需要和keil软件中的设置对应并且和app主函数中的向量表的偏移地址对应。
//这里可知偏移地址为0x08004000 - 0x08000000 = 0x4000。
#define Application_Address ((uint32_t)0x08004000)
​
uint32_t JumpAddress;
​
pFunction Jump_To_Application;
​
void main()
{uint8_t ch1;SystemInit();   //系统初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);     //设置优先级分组__disable_irq();/* 在这里进行硬件外设的初始化操作*//*对于仅仅用于升级流程的初始化操作也可以放到while(1)前进行初始化*///通讯串口初始化//调试串口初始化等等__enable_irq();//================================================================================ch1 = *(uint8_t *)(APP_VERSION_ADDR)if(ch1 == 'V')  {JumpAddress = *(__IO uint32_t *)(Application_Address + 4);  //app程序复位的地址Jump_To_Application = (pFunction)JumpAddress;__set_MSP(*(__IO uint32_t *)Application_Address);           //初始化app的栈指针printf("================进入应用程序APP===============\n");Jump_To_Application();  //跳转到app程序while(1);}//备注:双线之间的程序是通过读取应用程序存储在0x0800F800地址的版本号V1.00中的字符'V'//是否存在来判断是否需要执行程序升级的。//如果字符'V'依旧存在那就不需要升级直接跳转进入app程序即可。//如果字符'V'不存在(因为在进入boorloader升级之前在app中已经把对应页擦除掉了),//表示app程序需要进行升级操作,那么就不再跳转进入app程序,而是接着执行升级程序的操作。//================================================================================//这里可以初始化那些仅仅用于升级流程的初始化操作,比如初始化队列,或者初始化系统指示灯等。while(1){/*升级程序的代码实现操作*/ //注意在升级完成后,同样可以使用函数NVIC_SystemReset()进行复位操作//使得系统重新由bootloader跳转到app中。 }    
}

五、补充部分

补充一:对于bootloader中升级程序的代码实现思路,我这边是通过串口与上位机通讯进行操作的,在串口接收中断中将上位机发来的数据存放到队列中,然后根据升级流程从队列中读取相关内容。整个升级流程大致分为:1、握手(联机)2、擦除app的FLASH空间内容3、对之前擦除的FLASH写入新的升级程序数据,该步骤又可以细分为:①接收每次写入flash的起始地址②接收每次写入flash的数据长度③接收每次写入的具体数据并进行数据校验④调用接口将升级数据写入flash4、升级成功,调用函数接口NVIC_SystemReset()重启系统由bootloader进入app程序。以上的各步骤都可以和上位机之间添加应答机制。进一步保证通讯的可靠性。补充二:如果在bootloader程序跳转进入到app程序后发现在app中无法进入中断,可能是因为app主函数中的以下代码的顺序有问题:SystemInit();   //系统初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);     //设置优先级分组NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x4000);     //设置app程序的向量表偏移位置
​在app的main函数中要确保SystemInit()系统初始化函数放在NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x4000)设置向量表偏移位置函数之前。
完结。。。

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

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

相关文章

[C#]OpenCvSharp改变图像的对比度和亮度

目的 访问像素值mat.At<T>(y,x) 用0初始化矩阵Mat.Zeros 饱和操作SaturateCast.ToByte 亮度和对比度调整 g(x)αf(x)β 用α(>0)和β一般称作增益(gain)和偏置(bias)&#xff0c;分别控制对比度和亮度 把f(x)看成源图像像素&#xff0c;把g(x)看成输出图像像素…

Spring Boot集成Spring Retry快速入门Demo

1.Retry介绍 Spring Retry 提供了自动重新调用失败的操作的功能。这在错误可能是暂时的&#xff08;例如瞬时网络故障&#xff09;的情况下很有用。从2.2.0版本开始&#xff0c;重试功能已从Spring Batch中撤出&#xff0c;成为一个独立的新库&#xff1a;Spring Retry 使用场景…

蓝桥杯第十五届抱佛脚(十)贪心算法

蓝桥杯第十五届抱佛脚&#xff08;十&#xff09;贪心算法 贪心算法基本概念 贪心算法是一种在算法设计中常用的方法&#xff0c;它在每一步选择中都采取在当前状态下最好或最优&#xff08;即最有利&#xff09;的选择&#xff0c;从而希望导致结果是最好或最优的算法。 贪…

身份证实名认证接口的价格一般是多少呢?基于PHP身份核验接口

身份证实名认证接口分为身份证二要素、三要素、三要素人像核验接口&#xff0c;被广泛的应用于婚恋、交友、电商等等一系列行业领域&#xff0c;身份证实名认证需要实时数据&#xff0c;对于数据源来说也需要可靠&#xff0c;那么&#xff0c;身份证实名认证的价格是不是很贵呢…

小小算式(1 + 2) * (3 + 4)背后的大道理

目录 前缀表示法&#xff08;波兰表达式&#xff09; 中缀表达法 后缀表达法&#xff08;逆波兰表达式&#xff09; 三种表达法的相互转换 练习&#xff1a;逆波兰表达式求值 前缀表示法&#xff08;波兰表达式&#xff09; 波兰表示法&#xff08;英语&#xff1a;Polis…

Python学习,记录不熟悉知识点

目录 Set&#xff08;集合&#xff09; 集合内置方法完整列表 根据字符串的表达式计算结果 ​编辑 条件控制&#xff1a; if – elif – else match...case 循环语句&#xff1a; while循环 for循环 在同一行中有多个赋值操作&#xff08;先计算&#xff0c;再赋值&…

【Vue】Vue3中的OptionsAPI与CompositionAPI

文章目录 OptionsAPICompositionAPI对比总结 OptionsAPI 中文名:选项式API通过定义methods,computed,watch,data等属性方法&#xff0c;处理页面逻辑。以下是OptionsAPI代码结构 实例代码: <script lang"ts">// js或者tsimport { defineComponent } from vu…

javaScript手写专题——防抖/节流/闭包/Promise/深浅拷贝

目录 目录 一、 防抖/节流/闭包/定时器 编写一个组件&#xff0c;在input中输入文本&#xff0c;在给定的数据中查找相关的项目&#xff0c;并渲染搜索结果列表 1.新增InputSearch.vue组件 key的作用 2.新增 InputView.vue 3.添加路由 4.效果演示 follow up加上防抖怎么处理 1.…

「51媒体网」邀请媒体采访报道对企业宣传有何意义?

传媒如春雨&#xff0c;润物细无声的&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 邀请媒体采访报道对企业宣传具有多重意义&#xff1a; 提升品牌知名度和曝光度&#xff1a;媒体是信息传播的重要渠道&#xff0c;通过媒体的报道&#xff0c;企业及其活动、产品能够迅…

软考信息处理技术员2024年5月报名流程及注意事项

2024年5月软考信息处理技术员报名入口&#xff1a; 中国计算机技术职业资格网&#xff08;http://www.ruankao.org.cn/&#xff09; 2024年软考报名时间暂未公布&#xff0c;考试时间上半年为5月25日到28日&#xff0c;下半年考试时间为11月9日到12日。不想错过考试最新消息的…

k8s删除namespace失败一直处于Terminating状态

获取Terminating状态的namespace ~ kubectl get namespace NAME STATUS AGE bluehelix Active 146d broker Active 146d cattle-fleet-cluster…

Sketch是免费软件吗?这款软件支持导入!

Sketch 是一款针对网页、图标、插图等设计的矢量绘图软件。Sketch 的操作界面非常简单易懂&#xff0c;帮助全世界的设计师创作出许多不可思议的作品。但是同时&#xff0c;Sketch 也有一些痛点&#xff1a;使用 Sketch 需要安装 InVision、Abstract 、Zeplin 等插件&#xff0…

配置 施耐德 modbusTCP 分布式IO子站 PRA0100

模块官方介绍&#xff1a;https://www.schneider-electric.cn/zh/product/BMXPRA0100 1. 总体步骤 2. 软件组态&#xff1a;在 Unity Pro 软件中创建编辑 PRA 模块工程 2.1 新建项目 模块箱硬件型号如下 点击 Unity Pro 软件左上方【新建】按钮&#xff0c;选择正确的 DIO …

记一次C语言内存越界(内存越界 段错误 Segmentation fault )

1 背景 最近在用C重构原来用C写的SDK&#xff0c;发现一个内存越界问题&#xff0c;记录下来&#xff0c;以供后续参考。 2 问题 代码如下: #include <stdio.h> #include <stdlib.h>int array1[4] {1, 2, 3, 4}; int array2[4] {5, 6, 7, 8};int main(int arg…

Filter Listener Interceptor

文章目录 第一章 Filter1. 目标2. 内容讲解2.1 Filter的概念2.2 Filter的作用2.3 Filter的入门案例2.3.1 案例目标2.3.2 代码实现2.3.2.1 创建ServletDemo012.3.2.2 创建EncodingFilter 2.4 Filter的生命周期2.4.1 回顾Servlet生命周期2.4.1.1 Servlet的创建时机2.4.1.2 Servle…

git提交代码时报错,提不了

问题 今天在换了新电脑&#xff0c;提交代码时报错 ✖ eslint --fix found some errors. Please fix them and try committing again. ✖ 21 problems (20 errors, 1 warning) husky > pre-commit hook failed (add --no-verify to bypass) 解决 通过 --no-verify 解决&…

程序员如何搞副业

#程序员如何搞副业&#xff1f;# 在快速发展的IT行业中&#xff0c;程序员作为技术骨干&#xff0c;通常拥有扎实的编程能力和丰富的项目经验。然而&#xff0c;随着职业生涯的深入&#xff0c;许多程序员开始思考如何进一步提升自我价值&#xff0c;实现更多的经济收益。副业成…

RobotFramework测试框架(2)-测试用例

创建测试数据 测试数据语法 这里的测试数据就是指的测试用例。 测试文件组织 测试用例的组织层次结构如下&#xff1a; 在测试用例文件&#xff08; test case file &#xff09;中建立测试用例 一个测试文件自动的建成一个包含了这些测试用例的测试集&#xff08; test s…

python中for与while的区别是什么

Python中for循环和while循环本质上是没有区别的&#xff0c;但是在实际应用上&#xff0c;针对性不太一样。 for主要应用在遍历中&#xff0c;比如&#xff1a; example1&#xff1a; for i in range(10):print(i) 打印结果为&#xff1a; 0 1 2 3 4 5 6 7 8 9 注&#xff1a;…

RuoYi-Vue若依框架-在框架内用颜色选择器,页面显示色块

在用若依框架进行二次开发的时候写到自己的一个模块&#xff0c;其中涉及到颜色&#xff0c;我就想着是手动输入还是采用颜色选择器呢&#xff0c;考虑到后续涉及到另一个字段编码于时就采用了颜色选择器&#xff0c;选择完的颜色显示的是十六进制的颜色选择器&#xff0c;这时…