[源创] STM32F103ZET6 基于XMODEM 通讯的 BOOTLOADER案列IAP

时间:2021-09-30 09:02:39

网上好多初学者 都想知道如何更好的用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下用的,尽管图标显示有问题,已经很熟悉了,我不介意,哈哈哈

[源创] STM32F103ZET6 基于XMODEM 通讯的 BOOTLOADER案列IAP

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

还要我讲一遍么?

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

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

[源创] STM32F103ZET6 基于XMODEM 通讯的 BOOTLOADER案列IAP

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

[源创] STM32F103ZET6 基于XMODEM 通讯的 BOOTLOADER案列IAP

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

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

[源创] STM32F103ZET6 基于XMODEM 通讯的 BOOTLOADER案列IAP

检查没有问题

非常好

[源创] STM32F103ZET6 基于XMODEM 通讯的 BOOTLOADER案列IAP

检查末尾也没有问题

非常成功!

[源创] 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&comma;StringBuffer和StringBuilder源码解析&lbrack;基于JDK6&rsqb;

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

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

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

  5. ArrayList 源码(基于Java1&period;8)

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

  6. wp8使用Beetle&period;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&period;修改IK分词器源码来基于mysql热更新词库

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

随机推荐

  1. (转)jQuery插件 -- Form表单插件jquery&period;form&period;js

    beforeSubmit: validate function validate(formData, jqForm, options) { //在这里对表单进行验证,如果不符合规则,将返回false来 ...

  2. JavaScript 一个等号 两个等号 三个等号的区别

    一个等号 =:表示赋值 : 两个等号 ==:先转换类型再比较 : 三个等号 ===:先判断类型,如果不是同一类型直接false.

  3. 【python自动化第六篇:面向对象】

    知识点概览: 面向对象的介绍 面向对象的特性(class,object)实例变量,类变量 面型对象编程的介绍 其他概念 一.面向对象介绍 编程范式:面向对象,面向过程,函数式编程 面向过程:通过一组指 ...

  4. UWP 显示图片到Image控件

    要想显示图片,前提是要有一个空间的啦 <Image x:Name="imageHidden"/> 然后一个响应选择图片得事件,注意使用asynchronous方法哦 F ...

  5. python之数据类型补充、集合、深浅copy

    一.内容回顾 代码块: 一个函数,一个模块,一个类,一个文件,交互模式下,每一行就是一个代码块. is == id id()查询对象的内存地址 == 比较的是两边的数值. is 比较的是两边的内存地址 ...

  6. Spring(三)实例化Bean以及注入对象

    使用xml实例化bean 在xml中实例化bean的三种方式 <bean id="springService" class="com.zhiyou100.crm.t ...

  7. Python中&lowbar;&lowbar;repr&lowbar;&lowbar;和&lowbar;&lowbar;str&lowbar;&lowbar;区别

    Python中__repr__和__str__区别 看下面的例子就明白了 class Test(object): def __init__(self, value='hello, world!'): ...

  8. AI的新增功能(定义图案)(描边渐变)(图像描摹)5&period;1

    1.定义图案:打开一个AI素材文件如图: 选择工具拖拽选择这个图案,选择“对象”“图案”“建立”完成图案的建立 此时会弹出图案选项对话框,改变拼贴类型,图案宽高,份数,不透明度,单击"完成“ ...

  9. selenium-各种定位方法

    selenium各种定位方法. https://www.red-gate.com/simple-talk/wp-content/uploads/imported/1269-Locators_table ...

  10. 【干货】使用EnCase来分析windows 7文件系统------认识元数据记录&dollar;MFT,数据恢复

    来源:Unit 6: Windows File Systems and Registry 6.1 Windows File Systems and Registry Windows NTFS File ...