网上好多初学者 都想知道如何更好的用IAP,BOOTLOADER 功能

我给大家一个我自己的基于Xmodem的例子,

开发环境  KEIL 5.14 + STD标准库

芯片 STM32F103ZET6   外部晶振8MHz

用串口1通讯,通讯收发都用查询方式,没有用中断

另外用了systick 来做固定时间的延时程序

下面直接上代码

延时程序部分,

其实这个代码我也是从网上摘录的,不过希望大家好好理解一下

udelay.c

 #include "stm32f10x.h"

 static u8  fac_us=;//us延时倍乘数
static u16 fac_ms=;//ms延时倍乘数 //初始化延迟函数
//SYSTICK的时钟固定为HCLK时钟的1/8
//SYSCLK:系统时钟 void uDelay_SysTick_init(u8 SYSCLK)
{
SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟 HCLK/8 //b->1011
fac_us=SYSCLK/;
fac_ms=(u16)fac_us*;
} //延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对72M条件下,nms<=1864 void uDelay_SysTick_ms(u16 nms)
{
u32 temp; SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit) SysTick->VAL =0x00; //清空计数器
SysTick->CTRL=0x01 ; //开始倒数 do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(<<)));//等待时间到达 SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
} //延时nus
//nus为要延时的us数. void uDelay_SysTick_us(u32 nus)
{
u32 temp;
SysTick->LOAD=nus*fac_us; //时间加载 SysTick->VAL=0x00; //清空计数器
SysTick->CTRL=0x01 ; //开始倒数 do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(<<)));//等待时间到达 SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}

补一下 串口查询发送的 代码给你们

 void uUART_PutChar(USART_TypeDef* USARTx, uint8_t Data)
{
//while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){}
USARTx->SR;
USART_SendData(USARTx, Data);
while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET){}
}

以下就是今天的核心内容,大家注意看啊

 /* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "stdio.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/
#define CLI() __set_PRIMASK(1) //关闭总中断
#define SEI() __set_PRIMASK(0) //打开总中断
/* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/
extern void uUART_PutChar(USART_TypeDef* USARTx, uint8_t Data);
extern void uUSART_Init(void); extern void uDelay_SysTick_init(u8 SYSCLK);
extern void uDelay_SysTick_ms(u16 nms);
extern void uDelay_SysTick_us(u32 nus); #define def_FLASH_BASE (u32)(0x08000000)
#define def_FLASH_PAGESIZE (u32)(2048)
#define def_FLASH_PAGECUNT (u32)(256)
#define def_USERAPP_START (u32)(def_FLASH_BASE + (def_FLASH_PAGESIZE * 20))
#define def_USERAPP_BOTTOM (u32)(def_FLASH_BASE+def_FLASH_PAGESIZE * 256-def_FLASH_PAGESIZE*2) u32 gFlash_User_Address; //FLASH地址
u16 gFlash_128Bytes_Cnt=; //----------------------------------------------------------------------------- //定义Xmoden控制字符
#define XMODEM_NUL 0x00
#define XMODEM_SOH 0x01
#define XMODEM_STX 0x02
#define XMODEM_EOT 0x04
#define XMODEM_ACK 0x06
#define XMODEM_NAK 0x15
#define XMODEM_CAN 0x18
#define XMODEM_EOF 0x1A
#define XMODEM_WAIT_CHAR XMODEM_NAK #define dST_WAIT_START 0x00 //等待启动
#define dST_BLOCK_OK 0x01 //接收一个数据块成功
#define dST_BLOCK_FAIL 0x02 //接收一个数据块失败
#define dST_OK 0x03 //完成 //定义全局变量 struct str_XMODEM
{
unsigned char SOH; //起始字节
unsigned char BlockNo; //数据块编号
unsigned char nBlockNo; //数据块编号反码
unsigned char Xdata[]; //数据128字节
unsigned char CheckSum; //CheckSum校验数据
}strXMODEM; //XMODEM的接收数据结构 unsigned char gXM_BlockCount; //数据块累计(仅8位,无须考虑溢出)
unsigned char gXM_STATUS; //运行状态
//----------------------------------------------------------------------------- //接收指定字节数据(带超时控制)
// *ptr 数据缓冲区
// len 数据长度
// timeout 超时设定
// 返回值 已接收字节数目 unsigned char get_data(unsigned char *ptr,unsigned char len,u32 timeout)
{
unsigned count=;
do
{
if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET) //recive
{
*ptr++ = USART_ReceiveData(USART1);//如果接收到数据,读出 USART_ClearFlag(USART1, USART_FLAG_RXNE); count++; if (count>=len)
{
break; //够了?退出
}
continue;
} uDelay_SysTick_us();
timeout--;
}
while (timeout);
return count;
} unsigned char uCheckSum(unsigned char *ptr,unsigned char count)
{
unsigned char CheckSum=; while (count--)
{
CheckSum = CheckSum + *ptr++ ;
}
return CheckSum;
} void uXMODEM_Process()
{
unsigned char c;
u16 i;
unsigned char CheckSum;
uint16_t dataIndex;
uint16_t *pBuffer; //向PC机发送开始提示信息
printf("--> User program upgrade \r\n");
printf("--> Press the [d] key in 60 seconds . \r\n");
printf("--> After 60 seconds running the user program . \r\n"); //60秒种等待PC下发“d”,否则退出Bootloader程序 c=; get_data(&c,,**); //限时60秒,接收一个数据 if ((c=='d')||(c=='D'))
{
gXM_STATUS=dST_WAIT_START; //并且数据='d'或'D',进入XMODEM
printf("--> Please use the XMODEM protocol to transfer the BIN file. \r\n");
printf("--> The maximum of BIN file size is xxxKB \r\n");
}
else
{
gXM_STATUS=dST_OK; //退出Bootloader程序
} //进入XMODEM模式 gXM_BlockCount=0x01; gFlash_128Bytes_Cnt = ; gFlash_User_Address = def_USERAPP_START; while (gXM_STATUS!=dST_OK) //循环接收,直到全部发完
{
if (gXM_STATUS==dST_WAIT_START)
{
//XMODEM未启动
uUART_PutChar(USART1,XMODEM_WAIT_CHAR); //发送请求XMODEM_WAIT_CHAR
} i=get_data(&strXMODEM.SOH,,*); //限时1秒,接收133字节数据 if (i)
{
//分析数据包的第一个数据 SOH/EOT/CAN
switch (strXMODEM.SOH)
{
case XMODEM_SOH: //收到开始符SOH
if (i>=)
{
gXM_STATUS=dST_BLOCK_OK;
}
else
{ //如果数据不足,要求重发当前数据块
gXM_STATUS=dST_BLOCK_FAIL;
uUART_PutChar(USART1,XMODEM_NAK);
}
break; case XMODEM_EOT: //收到结束符EOT
uUART_PutChar(USART1,XMODEM_ACK); //通知PC机全部收到
gXM_STATUS=dST_OK; printf("--> User program upgrade finished \r\n");
break; case XMODEM_CAN: //收到取消符CAN
uUART_PutChar(USART1,XMODEM_ACK); //回应PC机
gXM_STATUS=dST_OK; printf("--> Warning: Cancel the upgrade, the user program may not complete .\r\n");
break; default: //起始字节错误
uUART_PutChar(USART1,XMODEM_NAK); //要求重发当前数据块
gXM_STATUS=dST_BLOCK_FAIL;
break;
}
} if (gXM_STATUS==dST_BLOCK_OK) //接收133字节OK,且起始字节正确
{
if (gXM_BlockCount != strXMODEM.BlockNo) //核对数据块编号正确
{
uUART_PutChar(USART1,XMODEM_NAK); //数据块编号错误,要求重发当前数据块
continue;
}
if (gXM_BlockCount !=(unsigned char)(~strXMODEM.nBlockNo))
{
uUART_PutChar(USART1,XMODEM_NAK); //数据块编号反码错误,要求重发当前数据块
continue;
} CheckSum=strXMODEM.CheckSum;
if (uCheckSum(&strXMODEM.Xdata[],)!=CheckSum)
{
uUART_PutChar(USART1,XMODEM_NAK); //CheckSum错误,要求重发当前数据块
continue;
}
//------------------------------------------------------------------------------------
//正确接收128个字节数据 if ((def_USERAPP_START <= gFlash_User_Address) &&(gFlash_User_Address <= def_USERAPP_BOTTOM))
{ FLASH_Unlock(); //解锁写保护 if((gFlash_128Bytes_Cnt==) && ((gFlash_128Bytes_Cnt %)==))
{
//擦除一整页
FLASH_ErasePage(gFlash_User_Address);//擦除这个扇区
} //写128字节
pBuffer =(u16 *) &strXMODEM.Xdata[]; for(dataIndex=;dataIndex<;dataIndex++)
{
FLASH_ProgramHalfWord(gFlash_User_Address+dataIndex*,pBuffer[dataIndex]);
} FLASH_Lock();//上锁写保护 gFlash_128Bytes_Cnt++;
gFlash_User_Address = def_USERAPP_START + *gFlash_128Bytes_Cnt; }
else
{
uUART_PutChar(USART1,XMODEM_CAN); //程序已满,取消传送
uUART_PutChar(USART1,XMODEM_CAN);
uUART_PutChar(USART1,XMODEM_CAN); gXM_STATUS=dST_OK; printf("--> The Flash Rom is full , Transfer stop \r\n"); break; } //------------------------------------------------------------------------------------ uUART_PutChar(USART1,XMODEM_ACK); //回应已正确收到一个数据块
gXM_BlockCount++; //数据块累计加1
}
} } //主程序
int main(void)
{ //考虑到BootLoader可能由应用程序中跳转过来,所以所用到的模块需要全面初始化
//这个BootLoader没有使用中断 uUSART_Init();
uDelay_SysTick_init();
CLI(); while()
{ printf(" \r\n");
printf("--> ******************************************************* \r\n");
printf("--> Programmer : Cao henglin \r\n");
printf("--> TEL : 15050225228 (wechat) \r\n");
printf("--> Q Q : 88410664 \r\n");
printf("--> E-MAIL : caohenglin@outlook.com \r\n");
printf("--> ******************************************************* \r\n"); uXMODEM_Process(); printf("--> Run ! \r\n"); //下面执行 跳转到USER APP 中执行
//代码我不写了,你们自己补一下,哈哈哈!!!
//对了一定要处理中断向量表啊,别忘记!!!
} }

以上就是实现  XModem的 全部代码了

跳转代码  我没有写,你们自己动动小手自己解决一下吧

这个Xmodem 主体代码,我参照了 AVR专家 马老师的例子,感谢马老师的分享!

----------------------------------

以下我是用的超级终端,WIN7以后电脑自身不带超级终端了,可以把超级终端拷贝过来使用

我就是在WIN10下用的,尽管图标显示有问题,已经很熟悉了,我不介意,哈哈哈

以上要注意,传输的文件只能是.bin 文件的格式 二进制的,keil 如何生成 .bin文件

还要我讲一遍么?

算了 还是说一下吧,谁叫我这么好呢

fromelf.exe  --bin --output .\Objects\MDKT3.bin .\Objects\MDKT3.axf

直接看图吧,别告诉我不懂啊

看看  就是这么的酷   非常好,已经下载到 我们指定的用户程序区那边了

用JLINK 把下载后的单片机 程序都读上来,检查一下我们下载的程序,有没有放在0x0800A000这个用户区

检查没有问题

非常好

检查末尾也没有问题

非常成功!

[源创] STM32F103ZET6 基于XMODEM 通讯的 BOOTLOADER案列IAP的更多相关文章

  1. 【深圳】OSC源创会第44期 开始报名

    时间:2016-03-19 14:00 地点: 深圳 南山区海德三道天利中央商务广场B座负一楼(意启创业) 费用:50元/人(现场交),女士.50积分的账号.开源软件作者.学生免费 (用于准备茶歇小食 ...

  2. AtomicInteger源码分析——基于CAS的乐观锁实现

    AtomicInteger源码分析——基于CAS的乐观锁实现 1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时 ...

  3. String,StringBuffer和StringBuilder源码解析[基于JDK6]

    最近指导几位新人,学习了一下String,StringBuffer和StringBuilder类,从反馈的结果来看,总体感觉学习的深度不够,没有读出东西.其实,JDK的源码是越读越有味的.下面总结一下 ...

  4. 项目源码--JAVA基于LBS地理位置信息应用的服务端

    技术要点: 1. LBS应用框架服务端实现 2. JAVA服务端技术 3. MYSQL数据库技术 4. 源码带详细的中文注释 ......   详细介绍: 1. LBS应用框架服务端实现 此套源码是基 ...

  5. ArrayList 源码(基于Java1.8)

    ArrayList 源码 ArrayList 基于数组实现,也就是类对变量 Object[]系列操作,封装为常用的add,remove,indexOf, contains本质是通过 size 计数器对 ...

  6. wp8使用Beetle.NetPackage实现基于TCP通讯的订单查询

    在新版本的Beetle.NetPackage中提供了对Protobuf和Controller的支持,所以在WP8下使用Beetle.NetPackage进行基于TCP的数据交互则一件非常简单事情.下面 ...

  7. 实操重写IK分词器源码,基于mysql热更新词库

    实操重写IK分词器源码,基于mysql热更新词库参考网址:https://blog.csdn.net/wuzhiwei549/article/details/80451302 问题一:按照这篇文章的介 ...

  8. 并发-AtomicInteger源码分析—基于CAS的乐观锁实现

    AtomicInteger源码分析—基于CAS的乐观锁实现 参考: http://www.importnew.com/22078.html https://www.cnblogs.com/mantu/ ...

  9. 32.修改IK分词器源码来基于mysql热更新词库

    主要知识点, 修改IK分词器源码来基于mysql热更新词库     一.IK增加新词的原因 在第32小节中学习到了直接在es的词库中增加词语,来扩充自已的词库,但是这样做有以下缺点: (1)每次添加完 ...

随机推荐

  1. 基于OpenCV的KNN算法实现手写数字识别

    基于OpenCV的KNN算法实现手写数字识别 一.数据预处理 # 导入所需模块 import cv2 import numpy as np import matplotlib.pyplot as pl ...

  2. Oracle触发器之替代触发器

    替代触发器 替代视图增删改操作.视图可以认为成逻辑上的一张表,类似于把一个sql语句的执行结果永久的像表存储到数据 库中,视图一般用来做查询. 创建视图的语法: create view 视图名称 as ...

  3. 谈谈Spring bean的生命周期(一)

    简介 本片文章主要讲Spring IOC容器中 bean 的生命周期 Spring bean 生命周期 Spring 中bean的声明周期 可以分为如下4个阶段: 实例化阶段--Instantiati ...

  4. 计算机网络——简单说说WebSocket协议

    一.前言   之前做了一个Web小项目,需要实现后端持续给前端推送消息的功能,当时最开始使用的是轮询实现,但是效率太低,对资源消耗也大.之后为了解决这个问题,上网查阅资料后,改用了WebSocket实 ...

  5. 帝国cms列表页内容简介字段smalltext去除里面html格式代码 设置方法

    帝国cms列表页内容简介字段smalltext去除里面html格式代码帝国cms列表页调用内容简介出现html代码怎么办 近来在用帝国cms的时候,发现一个问题,在列表页调用产品简介的时候出现了这种h ...

  6. 黑马程序员_毕向东_Java基础视频教程——位运算练习(随笔)

    位运算(练习) 最有效率的方式算出 2乘以 8等于几 2 << 3 = 2 * 2^3 = 2 * 8 = 16 对于两个整数变量的值进行互换(不需要第三方变量) class Test { ...

  7. 黑马程序员_毕向东_Java基础视频教程——switch语句练习(随笔)

    switch(练习) /* if和 switch 语句很像. 具体什么场景下使用什么语句呢? 如果判断的具体数值不多且符合byte.short.int.char.String类型,虽然两个语句都可以使 ...

  8. python之logging基础入门

    博客学习至:https://www.cnblogs.com/Nicholas0707/p/9021672.html#_label0 https://www.cnblogs.com/dream66/p/ ...

  9. 黑马vue学习的总结,vue笔记

    cls:清除终端输出 $refs $http $route 使用this.$emit('show')来调用父方法

  10. hadoop与spark的处理技巧(四)推荐引擎处理技巧

    经常一起购买的商品 scala> var file=sc.textFile("/user/ghj/togeterBought") file: org.apache.spark ...