零基础国产GD32单片机编程入门(十三)单片机IAP(在应用编程)详解及实战源码

本文主要是介绍零基础国产GD32单片机编程入门(十三)单片机IAP(在应用编程)详解及实战源码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 一.概要
    • 二.GD32F103C8T6单片机IAP介绍
      • 1.GD32F103C8T6单片机IAP基本原理
      • 2.GD32F103C8T6单片机IAP基本流程
    • 三.配置一个BOOT工程
    • 四.配置一个APP工程
    • 五.工程源代码下载
    • 六.小结

一.概要

GD32单片机程序升级方法有很多种,主要有以下几种:

1.将编译生成的hex/bin文件使用ST-Link/J-Link工具直接下载进 Flash 即可,Keil中点击下载就能下载,下载后的代码会存放在Flash的起始地址0x08000000处。

2.ISP(In System Programing),这个是利用了GD32单片机自带的 Bootloader 升级程序。一般可通过USART串口对Flash重新编程,再通过电脑上的ISP下载软件导入程序。在用户参考手册中,可以看到下表,关于启动模式设置的,ISP就是BOOT1引脚为0,BOOT0引脚为1,单片机就进入ISP模式。
在这里插入图片描述
3. IAP(In Application Programing),即在应用编程,与之相对应的叫做ISP,两者的不同是ISP需要依靠烧写器在单片机复位离线的情况下编程,需要人工的干预,而IAP则是用户自己的程序在运行过程中对Flash 的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。

使用IAP技术能很好地降低现场工作量,实现IAP有两个很重要的前提
1.单片机程序能对自身的内部Flash 进行擦写。
2.单片机要有能够和外部进行通讯的方式,无论是网络还是别的方式,只要能传输数据就行。

二.GD32F103C8T6单片机IAP介绍

1.GD32F103C8T6单片机IAP基本原理

以GD32F103C8T6单片机为例,每次程序复位是从0x08000000的位置开始执行主程序,如果不做IAP则这64KB(0x10000)空间都可以用来存放应用程序,但为了实现IAP,需要有划出一部分空间存放BOOT程序,BOOT程序跟应用程序是两个独立的工程,BOOT程序主要功能是来接收外部通讯(串口,485等)协议传输的应用程序代码文件(bin文件),并调用FLASH写入函数把bin文件分成N个32Bit数据,写入到应用程序地址空间,就实现对应用程序的升级。
在这里插入图片描述

2.GD32F103C8T6单片机IAP基本流程

单片机先在BOOT工程的程序中跑,BOOT程序通过串口接收上位机发来的.bin文件(应用程序工程),检查后将.bin文件写入到Flash特定位置(0x08004000开始的地址),bin文件写完后,单片机就从BOOT程序的空间跳转到应用程序的空间运行。
在这里插入图片描述

三.配置一个BOOT工程

本实验配置一个包含跳转的程序工程,包含FLASH写入以及Y-Modem协议。

添加代码
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

主要代码如下:

//串口设置USART0 ,PB6,PB7脚,波特率115200,无校验,8位数据,1位停止位
void gd_eval_com_init(void)
{/* enable GPIO clock */rcu_periph_clock_enable(RCU_GPIOB);/* enable USART clock */rcu_periph_clock_enable(RCU_USART0);gpio_pin_remap_config(GPIO_USART0_REMAP, ENABLE);//PB6,PB7需要重映射gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_6);gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ,GPIO_PIN_7);/* USART configure */usart_deinit(USART0);usart_baudrate_set(USART0,115200);//波特率115200usart_word_length_set(USART0, USART_WL_8BIT);usart_stop_bit_set(USART0, USART_STB_1BIT);usart_parity_config(USART0, USART_PM_NONE);usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);usart_receive_config(USART0, USART_RECEIVE_ENABLE);usart_enable(USART0);
}
int main(void)
{rcu_ahb_clock_config(RCU_AHB_CKSYS_DIV1);//AHB主频是1分频systick_config();//系统主频108MHZ,采用外部晶振,由两个宏决定(__SYSTEM_CLOCK_108M_PLL_HXTAL与HXTAL_VALUE)rcu_periph_clock_enable(RCU_AF); //管脚复用时钟alternate function clock使能gd_eval_com_init();//串口初始化FLASH_If_Init();//FLASH解锁while(1){Main_Menu();//实现程序升级并跳转,Ymodem协议}return 0;
}/*** @brief  Receive a file using the ymodem protocol* @param  buf: Address of the first byte* @retval The size of the file*/
int32_t Ymodem_Receive (uint8_t *buf)
{uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], file_size[FILE_SIZE_LENGTH], *file_ptr, *buf_ptr;int32_t i, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0;uint32_t flashdestination, ramsource;/* Initialize flashdestination variable */flashdestination = APPLICATION_ADDRESS;for (session_done = 0, errors = 0, session_begin = 0; ;){for (packets_received = 0, file_done = 0, buf_ptr = buf; ;){switch (Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT)){case 0:errors = 0;switch (packet_length){/* Abort by sender */case - 1:Send_Byte(ACK);return 0;/* End of transmission */case 0:Send_Byte(ACK);file_done = 1;break;/* Normal packet */default:if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff)){Send_Byte(NAK);}else{if (packets_received == 0){/* Filename packet */if (packet_data[PACKET_HEADER] != 0){/* Filename packet has valid data */for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);){FileName[i++] = *file_ptr++;}FileName[i++] = '\0';for (i = 0, file_ptr ++; (*file_ptr != ' ') && (i < (FILE_SIZE_LENGTH - 1));){file_size[i++] = *file_ptr++;}file_size[i++] = '\0';Str2Int(file_size, &size);/* Test the size of the image to be sent *//* Image size is greater than Flash size */if (size > (USER_FLASH_SIZE + 1)){/* End session */Send_Byte(CA);Send_Byte(CA);return -1;}/* erase user application area */FLASH_If_Erase(APPLICATION_ADDRESS);Send_Byte(ACK);Send_Byte(CRC16);}/* Filename packet is empty, end session */else{Send_Byte(ACK);file_done = 1;session_done = 1;break;}}/* Data packet */else{memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);ramsource = (uint32_t)buf;/* Write received data in Flash */if (FLASH_If_Write(&flashdestination, (uint32_t*) ramsource, (uint16_t) packet_length/4)  == 0){Send_Byte(ACK);}else /* An error occurred while writing to Flash memory */{/* End session */Send_Byte(CA);Send_Byte(CA);return -2;}}packets_received ++;session_begin = 1;}}break;case 1:Send_Byte(CA);Send_Byte(CA);return -3;default:if (session_begin > 0){errors ++;}if (errors > MAX_ERRORS){Send_Byte(CA);Send_Byte(CA);return 0;}Send_Byte(CRC16);break;}if (file_done != 0){break;}}if (session_done != 0){break;}}return (int32_t)size;
}void SerialDownload(void)
{uint8_t Number[10] = {0};int32_t Size = 0;SerialPutString("Waiting for the file to be sent ... (press 'a' to abort)\n\r");Size = Ymodem_Receive(&tab_1024[0]);if (Size > 0){SerialPutString("\n\n\r Programming Completed Successfully!\n\r--------------------------------\r\n Name: ");SerialPutString(FileName);Int2Str(Number, Size);SerialPutString("\n\r Size: ");SerialPutString(Number);SerialPutString(" Bytes\r\n");SerialPutString("Jump To App\r\n");JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);Jump_To_Application = (pFunction) JumpAddress;/* Initialize user application's Stack Pointer */__set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);/* Jump to application */Jump_To_Application();}else if (Size == -1){SerialPutString("\n\n\rThe image size is higher than the allowed space memory!\n\r");}else if (Size == -2){SerialPutString("\n\n\rVerification failed!\n\r");}else if (Size == -3){SerialPutString("\r\n\nAborted by user.\n\r");}else{SerialPutString("\n\rFailed to receive the file!\n\r");}
}

四.配置一个APP工程

本实验配置一个LED闪烁的程序工程
添加代码

配置应用程序起始地址
在这里插入图片描述

生成.bin文件配置,配置完,编译的时候就会生成.bin文件
在这里插入图片描述

中断向量表偏移配置
在这里插入图片描述
主要代码如下:

#include "gd32f10x.h"
#include "gd32f10x_libopt.h"
#include "systick.h"int main(void)
{rcu_ahb_clock_config(RCU_AHB_CKSYS_DIV1);//AHB主频是1分频nvic_vector_table_set(NVIC_VECTTAB_FLASH, 0x4000);//中断向量地址偏移0x4000systick_config();//系统主频108MHZ,采用外部晶振,由两个宏决定(__SYSTEM_CLOCK_108M_PLL_HXTAL与HXTAL_VALUE)rcu_periph_clock_enable(RCU_AF); //管脚复用时钟alternate function clock使能delay_1ms(1000);//等待1秒gpio_pin_remap_config(GPIO_SWJ_NONJTRST_REMAP, ENABLE);//PB4管脚默认是NJTRST,要当GPIO,需要重映射rcu_periph_clock_enable(RCU_GPIOB);//GPIOB时钟使能gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);//PB4配置成输出while(1){delay_1ms(1000);//等待1秒gpio_bit_set(GPIOB, GPIO_PIN_4);//输出高电平delay_1ms(1000);//等待1秒gpio_bit_reset(GPIOB, GPIO_PIN_4);//输出低电平}
}

实验效果:
BOOT程序:主要实现YMODEM协议以及内部FLASH编程,程序烧录完之后,由APP程序生成的APP.Bin文件烧录到APP程序的FLASH地址空间,再实现程序跳转。

1.Keil5打开BOOT工程,编译,并烧录BOOT程序。
2. Keil5打开APP程序,编译,生成APP.bin文件,文件在工程Objects目录下。
3. 打开Xshell6软件,配置好串口参数,115200波特率,无校验,COM口号是根据电脑自动识别,再点连接。会提示连接成功
在这里插入图片描述
在这里插入图片描述

4.板子重新上电,提示输入1,就在屏幕上输入1,会有C符号提示
在这里插入图片描述

5.选择YMODEM传输,选择APP.Bin文件
在这里插入图片描述

6.选择文件传输后,进度条会有进度,而且最终屏幕显示Jum To App,说明IAP升级成功
在这里插入图片描述

五.工程源代码下载

通过网盘分享的文件:14.IAP实验.zip
链接: https://pan.baidu.com/s/1WxJfDd0OxS_6HjPBc_W6Mg 提取码: 8g3k

如果链接失效,可以联系博主给最新链接
程序下载下来之后解压就行

六.小结

在单片机应用中,在线升级功能是必不可少的,它可以让我们在不破坏硬件的情况下对程序进行升级和修正,提高了开发效率。

这篇关于零基础国产GD32单片机编程入门(十三)单片机IAP(在应用编程)详解及实战源码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1136834

相关文章

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

详解C#如何提取PDF文档中的图片

《详解C#如何提取PDF文档中的图片》提取图片可以将这些图像资源进行单独保存,方便后续在不同的项目中使用,下面我们就来看看如何使用C#通过代码从PDF文档中提取图片吧... 当 PDF 文件中包含有价值的图片,如艺术画作、设计素材、报告图表等,提取图片可以将这些图像资源进行单独保存,方便后续在不同的项目中使

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

C#数据结构之字符串(string)详解

《C#数据结构之字符串(string)详解》:本文主要介绍C#数据结构之字符串(string),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录转义字符序列字符串的创建字符串的声明null字符串与空字符串重复单字符字符串的构造字符串的属性和常用方法属性常用方法总结摘

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

Pandas使用SQLite3实战

《Pandas使用SQLite3实战》本文主要介绍了Pandas使用SQLite3实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1 环境准备2 从 SQLite3VlfrWQzgt 读取数据到 DataFrame基础用法:读

Java中StopWatch的使用示例详解

《Java中StopWatch的使用示例详解》stopWatch是org.springframework.util包下的一个工具类,使用它可直观的输出代码执行耗时,以及执行时间百分比,这篇文章主要介绍... 目录stopWatch 是org.springframework.util 包下的一个工具类,使用它