当前位置: 首页 > news >正文

STM32 CubeMX (uart_IAP串口)简单示例

STM32 CubeMX


STM32 CubeMX (串口IAP)

  • STM32 CubeMX
    • IAP有什么用?
    • 整体思路
  • 一、STM32 CubeMX 设置
    • 时钟树
    • UART使能
    • UART初始化设置
  • 二、代码部分
    • 文件移植![在这里插入图片描述](https://img-blog.csdnimg.cn/0c4841d8328b4169a8833f15fe3d670c.png)
    • 实验效果
    • APP程序返回IAP程序


IAP有什么用?

Iap,全名为in applacation programming,即在应用编程,与之相对应的叫做isp,in system programming,在系统编程,两者的不同是isp需要依靠烧写器在单片机复位离线的情况下编程,需要人工的干预,而iap则是用户自己的程序在运行过程中对User Flash 的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。在工程应用中经常会出现我们的产品被安装在某个特定的机械结构中,更新程序的时候拆机很不方便,使用iap技术能很好地降低工作量.

整体思路

实现iap有两个很重要的前提,首先,单片机程序能对自身的内部flash进行擦写,第二,单片机要有能够和外部进行通讯的方式,无论是网络还是别的方式,只要能传输数据就行

要做iap首先我们要知道stm32的启动流程,流程如下

  1. 单片机从0x80000000位置启动,并将该地址当成系统栈顶地址
  2. 运行到中断向量表中,默认的中断向量表为0x80000004,该位置存放复位中断
  3. 跳转到复位中断处理函数当中,进行系统初始化,然后运行main函数

两种实现方式:

  1. 将IAP和APP程序放在一个程序中,会增加代码的耦合性和难度;
  2. 要将单片机flash分为两部份 IAP程序 APP程序 ;IAP是烧录工具烧录的(如 JTAG 或 ISP 烧入),App是通过串口传递bin文件(也可以是其他方式:如蓝牙,网卡,CAN等等)然后芯片自己烧录的

一定要划分清楚IAP程序和APP程序的flash地址,不要重合了
#1.IAP程序设置,程序地址
在这里插入图片描述
#2.APP程序设置,程序地址
在这里插入图片描述
生成bin文件

fromelf.exe --bin -o "$L@L.bin" "#L

在这里插入图片描述

一、STM32 CubeMX 设置

时钟树

在这里插入图片描述

UART使能

在这里插入图片描述

UART初始化设置

在这里插入图片描述

二、代码部分

移植正点原子的两部分代码,IAP和Fashl,也可以移植官方的代码,有能实现的Dome都可以

文件移植在这里插入图片描述

在这里插入图片描述

移植至CubeMX生成的文件夹
在这里插入图片描述
添加文件和路径
在这里插入图片描述

修改IAP.C

#define FLASH_APP1_ADDR		0x8005000  	//第一个应用程序起始地址(存放在FLASH)
iapfun jump2app;
u16 iapbuf[512];//**缓存区大小,因为stm32f103c8t6的flash一页是1K的,所以要改小为512**

添加函数


//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(u32 addr) 
{MSR MSP, r0 			//set Main Stack valueBX r14
}

修改"stmflash.h"

//用户根据自己的需要设置
#define STM32_FLASH_SIZE 	64	 		//所选STM32的FLASH容量大小(单位为K)
#define STM32_FLASH_WREN 	1              	//使能FLASH写入(0,不是能;1,使能)
#define FLASH_WAITETIME  	50000          	//FLASH等待超时时间//FLASH起始地址
#define STM32_FLASH_BASE 0x08000000 		//STM32 FLASH的起始地址

修改UART

#include "usart.h"
#include "stdio.h"
int fputc(int ch, FILE *f) {HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);return ch;
}/* USER CODE BEGIN 0 */
#define USART_REC_LEN  			15*1024 //定义最大接收字节数 55K
#define EN_USART1_RX 			1		//使能(1)/禁止(0)串口1接收
#define RXBUFFERSIZE   1 					//缓存大小	  	
uint8_t USART_RX_BUF[USART_REC_LEN] __attribute__ ( ( at ( 0X20001000 ) ) ); //接收缓冲,最大USART_REC_LEN个字节,起始地址为0X20001000.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
uint16_t USART_RX_STA = 0;       	//接收状态标记
uint16_t USART_RX_CNT = 0;			//接收的字节数
/* USER CODE END 0 */
u8 aRxBuffer[RXBUFFERSIZE];//HAL库使用的串口接收缓冲UART_HandleTypeDef 	huart1;/* USART1 init function *///初始化IO 串口1 
//bound:波特率
void uart_init(u32 bound)
{	//UART 初始化设置huart1.Instance=USART1;					    //USART1huart1.Init.BaudRate=bound;				    //波特率huart1.Init.WordLength=UART_WORDLENGTH_8B;   //字长为8位数据格式huart1.Init.StopBits=UART_STOPBITS_1;	    //一个停止位huart1.Init.Parity=UART_PARITY_NONE;		    //无奇偶校验位huart1.Init.HwFlowCtl=UART_HWCONTROL_NONE;   //无硬件流控huart1.Init.Mode=UART_MODE_TX_RX;		    //收发模式HAL_UART_Init(&huart1);					    //HAL_UART_Init()会使能UART1HAL_UART_Receive_IT(&huart1, (u8 *)aRxBuffer, RXBUFFERSIZE);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量}//UART底层初始化,时钟使能,引脚配置,中断配置
//此函数会被HAL_UART_Init()调用
//huart:串口句柄void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{//GPIO端口设置GPIO_InitTypeDef GPIO_Initure;if(huart->Instance==USART1)//如果是串口1,进行串口1 MSP初始化{__HAL_RCC_GPIOA_CLK_ENABLE();			//使能GPIOA时钟__HAL_RCC_USART1_CLK_ENABLE();			//使能USART1时钟__HAL_RCC_AFIO_CLK_ENABLE();GPIO_Initure.Pin=GPIO_PIN_9;			//PA9GPIO_Initure.Mode=GPIO_MODE_AF_PP;		//复用推挽输出GPIO_Initure.Pull=GPIO_PULLUP;			//上拉GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;//高速HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA9GPIO_Initure.Pin=GPIO_PIN_10;			//PA10GPIO_Initure.Mode=GPIO_MODE_AF_INPUT;	//模式要设置为复用输入模式!	HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA10#if EN_USART1_RXHAL_NVIC_EnableIRQ(USART1_IRQn);				//使能USART1中断通道HAL_NVIC_SetPriority(USART1_IRQn,3,3);			//抢占优先级3,子优先级3
#endif	}
}
extern u8 flag_1;//串口1中断服务程序
void USART1_IRQHandler(void)                	
{ u8 Res;if((__HAL_UART_GET_FLAG(&	huart1,UART_FLAG_RXNE)!=RESET))  //接收中断(接收到的数据必须是0x0d 0x0a结尾){Res=USART1->DR; if(USART_RX_CNT<USART_REC_LEN){USART_RX_BUF[USART_RX_CNT]=Res;USART_RX_CNT++;			 									     }}flag_1=1;HAL_UART_IRQHandler(&	huart1);	
} 

main.c

int main(void)
{/* USER CODE BEGIN 1 */u16 oldcount = 0;				//老的串口接收数据值u16 applenth = 0;				//接收到的app代码长度u16 app_bin = 0;u16 app_enter = 0;HAL_Init();SystemClock_Config();MX_GPIO_Init();uart_init(115200);while ( 1 ){//	 首先判断app代码的首地址是否为0x0800 000,是则进入app,否的话进行引导区。if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.{iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码}//   判断app代码栈顶是否为0x2000 000,不是则进入升级模式,代码如下,其中 FLASH_APP1_ADDR=0x8005000;if ( ( ( ( * ( vu32* ) FLASH_APP1_ADDR ) & 0x2FFE0000 ) != 0x20000000 ) ){printf ( "/***** No APP! *****/ \r\n" );printf ( "stm32f103c8t6在线升级  \r\n" );printf ( "选择对应的app bin文件 \r\n" );printf ( "输入 A 发送bin文件 \r\n" );printf ( "输入 E 进入app \r\n" );while ( 1 ){printf ( "滴答!\r\n" );if( flag_1==1){flag_1=0;printf ( "holle wored!\r\n" );}if ( USART_RX_CNT ){if ( oldcount == USART_RX_CNT ) //新周期内,没有收到任何数据,认为本次数据接收完成.{applenth = USART_RX_CNT;oldcount = 0;USART_RX_CNT = 0;if ( applenth > 100 ){printf ( "用户程序接收完成!\r\n" );printf ( "代码长度:%dBytes\r\n", applenth );}}else oldcount = USART_RX_CNT;}HAL_Delay(1000);if ( USART_RX_BUF[0] == 'A' ){if ( applenth )printf ( "\r\n 请发送bin文件 \r\n" );app_bin = 1;applenth = 0;}else if ( app_bin ){if ( applenth ){printf ( "开始更新固件...\r\n" );printf ( "Copying APP2FLASH..." );//此处 0X20001000 地址为串口缓冲区开始接收数据地址if ( ( ( * ( vu32* ) ( 0X20001000 + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX. 串口是否接收到数据{iap_write_appbin ( FLASH_APP1_ADDR, USART_RX_BUF, applenth ); //更新FLASH代码 printf ( "Copy APP Successed!!" );printf ( "固件更新完成!\r\n" );applenth = 0;app_bin = 0;}}}if ( USART_RX_BUF[0] == 'E' ){if ( applenth )printf ( "\r\n 将要执行APP \r\n" );app_enter = 1;applenth = 0;} if ( app_enter ){printf ( "开始执行FLASH用户代码!!\r\n" );if ( ( ( * ( vu32* ) ( FLASH_APP1_ADDR + 4 ) ) & 0xFF000000 ) == 0x08000000 ) //判断是否为0X08XXXXXX.{iap_load_app ( FLASH_APP1_ADDR ); //执行FLASH APP代码}else {printf ( "非FLASH应用程序,无法执行!\r\n" );printf ( "Illegal FLASH APP!" );}}}}}/* USER CODE END 3 */
}

实验效果

请添加图片描述

APP程序返回IAP程序

执行下面代码可以重回函数

 			  SCB->VTOR = FLASH_BASE | 0x0000;HAL_NVIC_SystemReset();

相关文章:

STM32 CubeMX (uart_IAP串口)简单示例

STM32 CubeMX STM32 CubeMX &#xff08;串口IAP&#xff09; STM32 CubeMXIAP有什么用&#xff1f;整体思路 一、STM32 CubeMX 设置时钟树UART使能UART初始化设置 二、代码部分文件移植![在这里插入图片描述](https://img-blog.csdnimg.cn/0c4841d8328b4169a8833f15fe3d670c.p…...

Kafka:安装和配置

producer&#xff1a;发布消息的对象&#xff0c;称为消息产生者 &#xff08;Kafka topic producer&#xff09; topic&#xff1a;Kafka将消息分门别类&#xff0c;每一个消息称为一个主题&#xff08;topic&#xff09; consumer&#xff1a;订阅消息并处理发布消息的对象…...

786. 第k个数

文章目录 QuestionIdeasCode Question 给定一个长度为 n 的整数数列&#xff0c;以及一个整数 k &#xff0c;请用快速选择算法求出数列从小到大排序后的第 k 个数。 输入格式 第一行包含两个整数 n 和 k 。 第二行包含 n 个整数&#xff08;所有整数均在 1∼109 范围内&…...

用友-NC-Cloud远程代码执行漏洞[2023-HW]

用友-NC-Cloud远程代码执行漏洞[2023-HW] 一、漏洞介绍二、资产搜索三、漏洞复现PoC小龙POC检测脚本: 四、修复建议 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#…...

Transformer(二)(VIT,TNT)(基于视觉CV)

目录 1.视觉中的Attention 2.VIT框架&#xff08;图像分类&#xff0c;不需要decoder&#xff09; 2.1整体框架 2.2.CNN和Transformer遇到的问题 2.3.1CNN 2.3.2Transformer 2.3.3二者对比 2.4.公式理解 3TNT 参考文献 1.视觉中的Attention 对于人类而言看到一幅图可以立…...

Scratch 详解 之 线性→代数之——求两线段交点坐标

可能有人要问&#xff1a;求交点坐标有什么用呢&#xff1f;而且为啥要用线代来求&#xff1f;直线方程不行吗&#xff1f;&#xff1f;&#xff1f; 这个问题&#xff0c;我只能说&#xff0c;直线方程计算的次数过多了&#xff0c;而且动不动就要考虑线的方向&#xff0c;90的…...

Python-组合数据类型

今天要介绍的是Python的组合数据类型 整理不易&#xff0c;希望得到大家的支持&#xff0c;欢迎各位读者评论点赞收藏 感谢&#xff01; 目录 知识点知识导图1、组合数据类型的基本概念1.1 组合数据类型1.2 集合类型概述1.3 序列类型概述1.4 映射类型概述 2、列表类型2.1 列表的…...

vue3+vue-simple-uploader实现大文件上传

vue-simple-uploader本身是基于vue2实现,如果要使用vue3会报错。如何在vue3中使用,可参考我的另一篇文章:解决vue3中不能使用vue-simple-uploader__Jyann_的博客-CSDN博客 一.实现思路 使用vue-simple-uploader组件的uploader组件,设置自动上传为false,即可开启手动上传。…...

自适应变异麻雀搜索算法及其Matlab实现

麻雀搜索算法( sparrow search algorithm&#xff0c;SSA) 是2020 年新提出的一种元启发式算法[1]&#xff0c;它是受麻雀种群的觅食和反捕食行为启发&#xff0c;将搜索群体分为发现者、加入者和侦察者 3 部分&#xff0c;其相互分工寻找最优值&#xff0c;通过 19 个标准测试…...

ETL技术入门之ETLCloud初认识

首先ETL是什么&#xff1f; ETL代表“Extract, Transform, Load”&#xff0c;是一种用于数据集成和转换的过程。它在数据管理和分析中扮演着重要的角色。下面我们将分解每个步骤&#xff1a; Extract&#xff08;抽取&#xff09;&#xff1a; 这一步骤涉及从多个不同的数据源…...

uniapp项目如何运行在微信小程序模拟器上

在HbuilderX中的小程序写完后自己一定要保存&#xff0c;否则会出不来效果 那么怎么让uniapp项目运行在微信小程序开发工具中呢 1 在hbuilderx中点击运行到小程序模拟器 2 然后在项目目录中会生成一个文件夹 在微信小程序开发软件中的工具>安全设置>打开端口 或者在微…...

数据挖掘全流程解析

数据挖掘全流程解析 数据指标选择 在这一阶段&#xff0c;使用直方图和柱状图的方式对数据进行分析&#xff0c;观察什么数据属性对于因变量会产生更加明显的结果。 如何绘制直方图和条形统计图 数据清洗 观察数据是否存在数据缺失或者离群点的情况。 数据异常的两种情况…...

详细介绍如何对音乐信息进行检索和音频节拍跟踪

在本文中,我们将了解节拍的概念,以及我们在尝试跟踪节拍时面临的挑战。然后我们将介绍解决问题的方法以及业界最先进的解决方案。 介绍 音乐就在我们身边。每当我们听到任何与我们的心灵和思想相关的音乐时,我们就会迷失其中。我们下意识地随着听到的节拍而敲击。您一定已…...

Java课题笔记~ HTTP协议(请求和响应)

Servlet最主要的作用就是处理客户端请求&#xff0c;并向客户端做出响应。为此&#xff0c;针对Servlet的每次请求&#xff0c;Web服务器在调用service()方法之前&#xff0c;都会创建两个对象 分别是HttpServletRequest和HttpServletResponse。 其中HttpServletRequest用于封…...

在x86下运行的Ubuntu系统上部署QEMU用于模拟RISC-V硬件环境

1.配置工作环境 sudo apt install gcc bison flex libncurses-dev ninja-build \pkg-config build-essential zlib1g-dev pkg-config libglib2.0-dev \binutils-dev libboost-all-dev autoconf libtool libssl-dev \libpixman-1-dev python-capstone virtualenv software-prop…...

网络爬虫选择代理IP的标准

Hey&#xff0c;小伙伴们&#xff01;作为一家http代理产品供应商&#xff0c;我知道网络爬虫在选择代理IP时可能会遇到些问题&#xff0c;毕竟市面上有很多选择。别担心&#xff01;今天我要给大家分享一些实用的建议&#xff0c;帮助你们选择适合网络爬虫的代理IP。一起来看看…...

RxJava 复刻简版之三,map 多次中转数据

案例代码&#xff1a;https://gitee.com/bobidali/lite-rx-java/commit/292e9227a5491f7ec6a07f395292ef8e6ff69290 RxJava 的调用第一步是封装了观察者接受了数据的处理&#xff0c;进一步就是使用 map 将数据操作传递给上下游 1、类似Observer.create 创建一个简单的观察者…...

06 Word2Vec模型(第一个专门做词向量的模型,CBOW和Skip-gram)

博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https://github.com/nickchen121/Pre-training-language-model 配套博客链接:https://www.cnblogs.com/nickchen121/p/15105048.html 神经网络语言模型(NNL…...

Axure RP9小白安装教程

第一步&#xff1a; 打开&#xff1a;Axure中文学习网 第二步&#xff1a; 鼠标移动软件下载&#xff0c;点击Axure RP 9下载既可 第三步&#xff1a; 注意&#xff1a;Axure RP 9 MAC正式版为苹果版本&#xff0c;Axure RP 9 WIN正式版为Windows版本 中文汉化包&#xff…...

腾讯云CVM服务器2核2g1m带宽支持多少人访问?

腾讯云2核2g1m的服务器支持多少人同时访问&#xff1f;2核2g1m云服务器短板是在1M公网带宽上&#xff0c;腾讯云服务器网以网站应用为例&#xff0c;当大规模用户同时访问网站时&#xff0c;很大概率会卡在公网带宽上&#xff0c;所以压根就谈不上2核2G的CPU内存计算性能是否够…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

Ubuntu系统多网卡多相机IP设置方法

目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机&#xff0c;交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息&#xff0c;系统版本&#xff1a;Ubuntu22.04.5 LTS&#xff1b;内核版本…...