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();

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

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

相关文章

2023/8/16总结

这几天完成了私信的功能点&#xff0c;用websocket做的。 这是大概的界面&#xff0c;参考的是微信 用户可以搜索好友&#xff1a; 如果不存在是下面这样&#xff0c;存在就会在左边的聊天里面显示有这个人选项 发送消息 接下来需要把推荐算法给做了

文件IO编程 1 2

头文件包含路径 linux 操作系统分为两大空间&#xff1a;用户空间和内核空间 这样划分&#xff0c;是为了保护内核的核心组件&#xff0c;不被轻易访问和修改 系统调用&#xff1a;安全的访问内核空间 其核心是&#xff1a;函数API&#xff08;API&#xff1a;用户编程接口&…

K8S系列文章之 Docker安装使用Kafka

通过Docker拉取镜像的方式进行安装 照例先去DockerHub找一下镜像源&#xff0c;看下官方提供的基本操作&#xff08;大部分时候官方教程比网上的要清晰一些&#xff0c;并且大部分教程可能也是翻译的官方的操作步骤&#xff0c;所以直接看官方的就行&#xff09; 老实说Kafka…

【Vue3】Vue3 UI 框架 | Element Plus —— 创建并优化表单

安装 # NPM $ npm install element-plus --save // 或者&#xff08;下载慢切换国内镜像&#xff09; $ npm install element-plus -S// 可以选择性安装 less npm install less less-loader -D // 可以选择性配置 自动联想src目录Element Plus 的引入和注入 main.ts import…

总结 TCP 协议的相关特性

TCP协议段格式: 如图, 端口号: 是其中一个重要的部分,知道端口号才能确认数据交给哪个应用程序(端口号属于传输层的概念). 4位首部长度:4bit表示的范围是0->15,在此处,单位是"4字节",因此,将这里的数值 * 4&#xff0c;才是真正的报头长度,即TCP 报头最大长度,60…

Cenos7 搭建Minio最新版集群部署服务器(一)

------> 道 | 法 | 术 | 器 | 势 <------ 多台服务器间免密登录|免密拷贝 Cenos7 搭建Minio集群部署服务器(一) Cenos7 搭建Minio集群Nginx统一访问入口|反向动态代理(二) Spring Boot 与Minio整合实现文件上传与下载(三) CentOS7的journalctl日志查看方法 …

已知四个坐标点,怎样求出四边形的四个内角

1&#xff0c;理论 最简单的方式利用向量进行求解 如图可得&#xff1a; cosθa*b/&#xff08;|a|*|b|&#xff09; 已知三点坐标&#xff0c;很容易可以得到两向量之积a*b&#xff0c;以及每个的模值 2&#xff0c;四个角度求解过程 首先&#xff0c;我们定义了四个坐标点…

在数字游民天堂,Polkadot Hubs 探索建设更紧密的全球社区

分布式办公是 Web3 行业的协作常态&#xff0c;当数字游民们享受着线上远程工作的自由和便捷时&#xff0c;也在怀念着一种面对面与他人交流与共创的经历。共享空间随之兴起&#xff0c;为许多初创项目公司提供开放舒适的环境&#xff0c;却难以在不同的人群之间搭起一张巨大的…

完美解决Github提交PR后报错:File is not gofumpt-ed (gofumpt)

问题阐述 最近在Github上提交PR后&#xff0c;遇到了这么一个问题&#xff1a;golangci-lint运行失败&#xff0c;具体原因是File is not gofumpt-ed (gofumpt)。 名词解释 golangci-lint&#xff1a; golangci-lint 是Go语言社区中常用的代码质量检查工具&#xff0c;它可以…

[自学记录06|*百人计划]Gamma矫正与线性工作流

一、前言 Gamma矫正其实也属于我前面落下的一块内容&#xff0c;打算把它补上&#xff0c;其它的没补是因为我之前写的GAMES101笔记里已经涵盖了&#xff0c;而Gamma矫正在101里面确实没提到&#xff0c;于是打算把它补上&#xff0c;这块内容并不难&#xff0c;但是想通透的理…

我的创作纪念日(256天)

前言 结缘 我与csdn的结缘&#xff0c;之前在创作纪念日&#xff08;128天&#xff09;便已提到&#xff0c;今在此便不再多言 收获 很惭愧&#xff0c;自六月底至八月中旬&#xff0c;因为忙于找工作&#xff0c;奔赴面试求职之际&#xff0c;写博客没有像之前那么勤&#x…

qt QPalette的原理与使用

QPalette类用于控制控件的风格&#xff0c;即任意一个地方的绘制方式。每个控件或者说qwidget对象内部都有一个QPalette对象。 在paintEvent(QPaintEvent *event)函数中&#xff0c;其实就是调用该控件的QPalette内容来进行绘制的了。 例如&#xff1a; QStyleOptionTab opt…

《论文阅读12》RandLA-Net: Efficient Semantic Segmentation of Large-Scale Point Clouds

一、论文 研究领域&#xff1a;全监督3D语义分割&#xff08;室内&#xff0c;室外RGB&#xff0c;kitti&#xff09;论文&#xff1a;RandLA-Net: Efficient Semantic Segmentation of Large-Scale Point Clouds CVPR 2020 牛津大学、中山大学、国防科技大学 论文链接论文gi…

Kafka-eagle监控平台

Kafka-Eagle简介 在开发工作中&#xff0c;当业务不复杂时&#xff0c;可以使用Kafka命令来进行一些集群的管理工作。但如果业务变得复杂&#xff0c;例如&#xff1a;需要增加group、topic分区&#xff0c;此时&#xff0c;再使用命令行就感觉很不方便&#xff0c;此时&#x…

Vim学习(二)—— 编译C程序

打开终端&#xff0c;这里以MobaXterm为例&#xff0c; 邮件创建新的空文件并命名&#xff0c; 然后cd到对应路径下&#xff0c;用 vim hello.cvim打开创建的文件&#xff0c;进入编辑模式&#xff0c;编辑完程序后按Esc退出编辑模式&#xff0c;输入 :wq保存并退出&#xf…

linux安装wkhtmltopdf(清晰明了)

概述 在公司项目中使用到 wkhtmltopdf 转换PDF&#xff0c;由于 wkhtmltox-0.12.5 版本 echarts 图形虚线样式&#xff0c;需要升级 wkhtmltox-0.12.6 版本来解决。 官网地址 wkhtmltopdf &#xff1a;https://wkhtmltopdf.org/ windows 安装 下载流程及安装流程 进入官…

《系统架构设计师教程》重点章节思维导图

内容来自《系统架构设计师教程》&#xff0c;筛选系统架构设计师考试中分值重点分布的章节&#xff0c;根据章节的内容整理出相关思维导图。 重点章节 第2章&#xff1a;计算机系统知识第5章&#xff1a;软件工程基础知识第7章&#xff1a;系统架构设计基础知识第8章&#xff1…

Kotlin反射访问androidx.collection.LruCache类私有变量

Kotlin反射访问androidx.collection.LruCache类私有变量 androidx.collection.LruCache类中定义了一个名为map的LinkedHashMap&#xff0c;map存储了所有LruCache的数据&#xff0c;有时候需要遍历访问该LinkedHashMap&#xff0c;取出里面的值&#xff0c;但是LruCache代码实…

GPU Dissolve(GPU 消散)学习GPU Instancing

一&#xff1a;摘要 通过制作一个模型GPU消散效果来学习GPU Instancing 也就是实例化。 目标效果是杨超大佬文章《GPU shatter》里面的消散效果如图&#xff1a; Tags&#xff1a;模型顶点分裂(Mesh Vertex Splitting)&#xff0c; 实例化绘制(GPU Instancing Drawing)&#x…

开源可商业运营的ChatGpt网页源码v1.2.2

&#x1f916; 主要功能 后台管理系统,可对用户,Token,商品,卡密等进行管理 精心设计的 UI&#xff0c;响应式设计 极快的首屏加载速度&#xff08;~100kb&#xff09; 支持Midjourney绘画和DALLE模型绘画,GPT4等应用 海量的内置 prompt 列表&#xff0c;来自中文和英文 一键导…