STM32F103通过Ymodem协议更新程序带MD5校验
一、先来几张靓图
二、Xshell软件设置
三、程序更新流程
waitStartVerInfo, //等待起始校验消息,确定协议
getProgInfoPack, //或去信息包
progFileDeal, //程序处理
downloadAndSaveProg, //下载并保存程序
verifyDownloadProg, //校验下载下来的程序
carryProgToMcu, //搬运程序进入MCU
verifyMcuProg, //校验搬运进入MCU的程序
recordProgInfo, //记录程序信息
jumpToAppProg, //跳转到应用程序
四、主要源码
#include "main.h"void $Sub$$main(void)
{ u8 res=0; FATFS fs;//逻辑磁盘工作区. extern int main(void);extern int $Super$$main(void);delay_init(); //延时函数初始化 uart_init(115200);rs485_init(115200);rs485_timer_init(2000,71);key_init(); //IO初始化W25QXX_Init(); //初始化W25Q128sys_data_read();res=f_mount(&fs,"0:",1); //挂载FLASH. if(res==0X0D)//FLASH磁盘,FAT文件系统错误,重新格式化FLASH{printf("Flash Disk Formatting...\r\n"); //格式化FLASHres=f_mkfs("0:",1,4096);//格式化FLASH,1,盘符;1,不需要引导区,8个扇区为1个簇if(res==0){f_setlabel((const TCHAR *)"0:PROG"); //设置Flash磁盘的名字为:ALIENTEKprintf("Flash Disk Format Finish\r\n"); //格式化完成}elseprintf("Flash Disk Format Error \r\n"); //格式化失败} $Super$$main();}int main(void)
{ bool isJumpToApp=true;YmodemSohPackage *ymodemSohPack = (YmodemSohPackage *)&rs485RecData.recDataBuf;//SOH包结构YmodemStxPackage *ymodemStxPack = (YmodemStxPackage *)&rs485RecData.recDataBuf;//STX包结构ProgUpdateProcessE progUpdateProcess=waitStartVerInfo; //程序更新流程CommitAgree commitProtoco=noAgree; //通信协议u16 rs485RecCntVal=0; //485接收到的数据u8 versionStrBuf[10]; //旧版本u8 sizeStrBuf[10]; //程序大小u8 md5StrBuf[34]; //MD5值u32 programTotalSize; //程序大小u8 failCnt=0; //失败计数char buf[200]; //临时缓冲器FRESULT fileRes=FR_OK; //文件操作结果static FIL file; //文件bool isAck=true; //是否应答ACKu8 packNumCnt;u32 br; //程序移动指针u32 updatingProgSize;//程序读取字节u32 progWriteAddr; //写MCU程序地址u8 readProgBuf[2048];//读取存储BUFif(get_update_key())//检测是否强制更新程序{MSG_OUT("开始更新程序");isJumpToApp=false;}while(1){if(isJumpToApp)//跳转到Application程序{if (strcmp((char *)sysParaSave.oldVersion, (char *)sysParaSave.newVersion) == 0)//程序有效{//执行跳转MSG_OUT("程序无需更新,直接跳转");__disable_irq(); //关闭所有中断iap_load_app(SAVE_PROGRAM_ADDR);//执行FLASH APP代码 }else{isJumpToApp=false;}}else{switch(progUpdateProcess){case waitStartVerInfo: //等待起始校验消息,确定协议{rs485RecCntVal = wait_rec_data(1000);if(rs485RecCntVal!=0){ if(strstr(rs485RecData.recDataBuf,"ymodem")!=NULL)//查找协议{commitProtoco=ymodem;}if(strstr(rs485RecData.recDataBuf,COMMIT_PASSWORD)!=NULL)//验证密码{if(commitProtoco!=noAgree)//通信协议和密码都合适{MSG_OUT("包头提取成功");progUpdateProcess=getProgInfoPack;//执行获去信息包}}}}break;case getProgInfoPack: //获去信息包{switch(commitProtoco){case ymodem:{ymodem_answer_c();rs485RecCntVal = wait_rec_data(1000);if(rs485RecCntVal!=0) //接收到了数据{//校验数据是否合适if(ymodemSohPack->packHead==ymodem_soh&&\ymodemSohPack->ymodemPackNum==(u8)(~ymodemSohPack->ymodemPackNumNegation)&&\ymodem_crc16_cal(ymodemSohPack->ymodemData, sizeof(ymodemSohPack->ymodemData))\==(ymodemSohPack->ymodemCrcH*256+ymodemSohPack->ymodemCrcL)){memset(versionStrBuf,0x00,sizeof(versionStrBuf));memset(sizeStrBuf,0x00,sizeof(sizeStrBuf));memset(md5StrBuf,0x00,sizeof(md5StrBuf));programTotalSize=0; //获取字符串if(copy_between_characters((char *)&ymodemSohPack->ymodemData,(char *)&versionStrBuf,"$","@")&&\copy_between_characters((char *)&ymodemSohPack->ymodemData,(char *)&sizeStrBuf,"@","&")&&\copy_between_characters((char *)&ymodemSohPack->ymodemData,(char *)&md5StrBuf,"&","#"))//获取版本{if(strcmp((char *)&versionStrBuf,(char *)sysParaSave.oldVersion)==0)//版本一样{MSG_OUT("运行程序与当前更新程序为同一个文件");failCnt=0;ymodem_cancel_transport();//停止ymodem传输progUpdateProcess=jumpToAppProg;//直接跳转运行 }else{programTotalSize = atol((char *)sizeStrBuf);MSG_OUT("文件信息获取成功");failCnt=0;progUpdateProcess=progFileDeal;//文件处理}}else{failCnt++;if(failCnt>=5){failCnt=0;MSG_OUT("文件信息获取失败");ymodem_cancel_transport();//停止ymodem传输while(1);} }}else{ failCnt++;if(failCnt>=5){failCnt=0;MSG_OUT("文件信息数据校验失败");ymodem_cancel_transport();//停止ymodem传输while(1);}}} else{failCnt++;if(failCnt>=5){failCnt=0;MSG_OUT("文件信息数据获取失败");ymodem_cancel_transport();//停止ymodem传输while(1);}}}break;} }break;case progFileDeal: //程序处理{//删除旧文件memset(buf,0x00,sizeof(buf));sprintf(buf,"%s%s%s%s",PROG_PATH,"/",sysParaSave.oldVersion,".bin");fileRes = f_unlink(buf);if(fileRes!=FR_OK&&fileRes!=FR_NO_PATH){MSG_OUT("旧文件删除失败");ymodem_cancel_transport();//停止ymodem传输while(1); }//新建根目录fileRes=f_mkdir(PROG_PATH); //新建程序根目录if(fileRes!=FR_OK&&fileRes!=FR_EXIST) //文件打开失败{MSG_OUT("程序根目录新建失败");ymodem_cancel_transport();//停止ymodem传输while(1);} //新建文件并打开memset(buf,0x00,sizeof(buf));sprintf(buf,"%s%s%s%s",PROG_PATH,"/",versionStrBuf,".bin"); fileRes=f_open(&file,buf,FA_CREATE_NEW|FA_WRITE); //新建文件并打开if(fileRes!=FR_OK){MSG_OUT("打开新文件失败");ymodem_cancel_transport();//停止ymodem传输while(1); }progUpdateProcess=downloadAndSaveProg;//开始下载程序isAck=true;packNumCnt=1; //从1开始计数failCnt=0;br=0;}break;case downloadAndSaveProg: //下载并保存程序{switch(commitProtoco){case ymodem:{ if(isAck)//应答ACKymodem_answer_ack();elseymodem_answer_nak();rs485RecCntVal = wait_rec_data(1000);if(rs485RecCntVal<5)//有可能是结束信号{if(ymodemStxPack->packHead==YMODEM_EOT)//结束信号{ymodem_answer_nak();rs485RecCntVal = wait_rec_data(1000);ymodem_answer_ack();ymodem_answer_c();delay_ms(200);packNumCnt=0;//结束包号是0isAck=true;}}else if(ymodemStxPack->packHead==ymodem_soh)//128字节包{if(ymodemSohPack->ymodemPackNum==(u8)(~ymodemSohPack->ymodemPackNumNegation)&&\ymodem_crc16_cal(ymodemSohPack->ymodemData, sizeof(ymodemSohPack->ymodemData))\==(ymodemSohPack->ymodemCrcH*256+ymodemSohPack->ymodemCrcL)&&ymodemSohPack->ymodemPackNum==packNumCnt){if(ymodemSohPack->ymodemPackNum!=0x00)//不是结束包{//读取成功了fileRes=f_write (&file, ymodemSohPack->ymodemData,sizeof(ymodemSohPack->ymodemData), &br); //写入文件if(fileRes==FR_OK){ MSG_OUT("写入成功");packNumCnt++;isAck=true; //应答、发送下一包failCnt=0;}else{isAck=false;//非应答、重新发送此包 failCnt++;if(failCnt>=5){failCnt=0;MSG_OUT("文件写入失败");ymodem_cancel_transport();//停止ymodem传输while(1);} } }else//是结束包{MSG_OUT("成功收到应答包");f_close (&file);//关闭文件progUpdateProcess = verifyDownloadProg;}}else{isAck=false;//非应答、重新发送此包failCnt++;if(failCnt>=5){failCnt=0;MSG_OUT("文件写入失败");ymodem_cancel_transport();//停止ymodem传输while(1);} } }else//1024 STX包{if(ymodemStxPack->ymodemPackNum==(u8)(~ymodemStxPack->ymodemPackNumNegation)&&\ymodem_crc16_cal(ymodemStxPack->ymodemData, sizeof(ymodemStxPack->ymodemData))\==(ymodemStxPack->ymodemCrcH*256+ymodemStxPack->ymodemCrcL)&&\ymodemStxPack->ymodemPackNum==packNumCnt){//读取成功了fileRes=f_write (&file, ymodemStxPack->ymodemData,sizeof(ymodemStxPack->ymodemData), &br); //写入文件if(fileRes==FR_OK){ MSG_OUT("写入成功");packNumCnt++;isAck=true; //应答、发送下一包failCnt=0;}else{isAck=false;//非应答、重新发送此包failCnt++;if(failCnt>=5){failCnt=0;MSG_OUT("文件写入失败");ymodem_cancel_transport();//停止ymodem传输while(1);}}}else{isAck=false;//非应答、重新发送此包failCnt++;if(failCnt>=5){failCnt=0;MSG_OUT("文件写入失败");ymodem_cancel_transport();//停止ymodem传输while(1);} } }}break;} }break;case verifyDownloadProg: //校验下载下来的程序{ fileRes=f_open(&file,buf,FA_READ); //打开新文件if(fileRes!=FR_OK){MSG_OUT("校验文件打开失败");while(1); } MSG_OUT("校验文件打开成功");if(file.fsize<programTotalSize){MSG_OUT("文件尺寸校验失败");f_close(&file);while(1); }MSG_OUT("文件尺寸校验成功");progUpdateProcess=carryProgToMcu;}break;case carryProgToMcu: //搬运程序进入MCU{MSG_OUT("开始更新程序");updatingProgSize=programTotalSize;//程序读取字节progWriteAddr=SAVE_PROGRAM_ADDR; //程序写入MCU地址__disable_irq(); //关闭所有中断while(1)//开始读取{memset(buf,0x00,sizeof(buf));sprintf(buf,"程序已更新: %d/%d",(programTotalSize-updatingProgSize),programTotalSize);MSG_OUT(buf);if(updatingProgSize==0) //程序复制完成{MSG_OUT("程序更新完成");progUpdateProcess=verifyMcuProg;//执行校验程序f_close (&file);break;} if(updatingProgSize<2048){if(f_read (&file, &readProgBuf,updatingProgSize, &br)==FR_OK) //读取文件{iap_write_appbin(progWriteAddr,readProgBuf,updatingProgSize); //更新FLASH代码 updatingProgSize=0;}else{MSG_OUT("程序文件读取失败!");f_close (&file);while(1);}}else{if(f_read (&file, &readProgBuf,2048, &br)==FR_OK) //读取文件{iap_write_appbin(progWriteAddr,readProgBuf,2048); //更新FLASH代码 updatingProgSize-=2048;progWriteAddr+=2048;}else{MSG_OUT("程序文件读取失败!");f_close (&file);while(1);}}} __enable_irq(); //关闭所有中断}break;case verifyMcuProg: //校验搬运进入MCU的程序{MSG_OUT("开始MD5校验程序");memset(buf,0x00,sizeof(buf));get_bin_md5(SAVE_PROGRAM_ADDR,programTotalSize,buf); //MD5校验程序文件if(strcmp((char *)md5StrBuf,buf)!=0){MSG_OUT("程序MD5校验失败");while(1);} MSG_OUT("MD5校验程序成功");progUpdateProcess=recordProgInfo;//记录程序信息}break;case recordProgInfo: //记录程序信息{MSG_OUT("开始记录数据");memset(sysParaSave.oldVersion,0x00,sizeof(sysParaSave.oldVersion));memset(sysParaSave.newVersion,0x00,sizeof(sysParaSave.newVersion));memset(sysParaSave.md5Val,0x00,sizeof(sysParaSave.md5Val)); memcpy(sysParaSave.oldVersion,versionStrBuf,sizeof(versionStrBuf)); //程序版本memcpy(sysParaSave.newVersion,versionStrBuf,sizeof(versionStrBuf)); //程序版本memcpy(sysParaSave.md5Val,md5StrBuf,sizeof(md5StrBuf)); //MD5sysParaSave.programSize = programTotalSize; //程序大小if(sys_data_save()!=true){MSG_OUT("数据保存失败");while(1);}MSG_OUT("数据保存成功");progUpdateProcess=jumpToAppProg;//执行跳转程序}break;case jumpToAppProg: //跳转到应用程序 {MSG_OUT("执行跳转");__disable_irq(); //关闭所有中断iap_load_app(SAVE_PROGRAM_ADDR);//执行FLASH APP代码 }break; }}}
}
五、主要说明
1、我用的是RS485协议,可以更改为SPI、IIC、串口、等。
2、程序自己已经在项目中使用,下面工程下载下来后可以直接使用,软件设置参考上面。
3、需要技术支持的可以在我的主页添加我的QQ、
4、项目中用到了FAFTS文件系统、MD5校验算法、在线IAP等知识。
5、项目中使用的存储介质是SPIFLASH(W25Q64),可以改为其他容量的。
六、文件名格式
文件名格式为:$V002@21540&9eff132d92eb0b32ddbe3654d567568d#
解释:$版本号@字节数&MD5校验值#
MD5计算地址:http://www.metools.info/other/o21.html
七、需要完整工程的点击购买
完整工程
STM32F103通过Ymodem协议更新程序带MD5校验相关推荐
- oracle包校验和失败怎么回事,lol更新包md5校验失败怎么回事_更新lol提示更新包MD5校验失败如何处理-win7之家...
lol英雄联盟是很多用户都喜欢的一款网络游戏,有时候有新版本的时候很多用户会对其进行更新,可是有不少用户在更新lol的时候,却遇到更新包md5校验失败,请稍后重试的提示,导致无法更新,这要怎么办呢,为 ...
- STM32F103代码远程升级(三)基于YModem协议串口升级程序的实现
文章目录 一.YModem协议简介 二.YModem的数据格式 1.起始帧的数据格式 2.数据帧的数据格式 3.结束帧的数据格式 4.文件传输过程 三.基于Ymodem协议串口升级程序的实现过程 1. ...
- STM32F103 通过SD卡IAP升级程序,带MD5校验,(带源码)可在实际项目中使用
一.将APP程序从SD卡搬运到MCU中 首先从sd卡通过FAFTS文件操作系统打开程序文件,然后记录下复制开始地址和程序文件大小 fileOperionResult = f_open(&upd ...
- 野火串口助手协议发送文件通讯协议——XMODEM协议——YMODEM协议
野火串口助手协议发送文件通讯协议 修订历史 日期 版本 更新内容 2020/6/22 0.0.1 首次发布 XMODEM协议 上位机是现实了XModem-CRC16和XModem-1K; XModem ...
- STM32的升级--ICP/ISP/IAP以及Ymodem协议分析
资料下载 Ymodem协议传输过程分析 ICP/ISP/IAP 区别 ICP(In-Circuit Programing): 通过J-Link/SWD等下载器烧写程序,上位机需要借助其他硬件的参与才能 ...
- 红帽子redhat linux 9.0官方下载地址,附MD5校验码
红帽子redhat linux 9.0官方下载地址如下: https://archive.download.redhat.com/pub/redhat/linux/9/en/iso/i386/shri ...
- ymodem android,【安卓相关】蓝牙基于Ymodem协议发送bin文件,对硬件设备进行升级。...
最近做的一个安卓项目是使用蓝牙基于Ymodem协议传输bin文件,实现对硬件设备进行升级. 做的过程中遇到了不少困难,用我这半吊子的语文水平,记录一下吧 怎么办,平时对各种文件传输协议真的是知之甚少啊 ...
- STM32 Ymodem 协议及代码解析
点击左上角的"关注",定期更新 STM32 最新资讯,总有你想要的信息! STM32 Ymodem 协议及代码解析 文章导图: 1. Ymodem 协议传输效果 1.1 发送端软件 ...
- Ymodem协议学习笔记
介绍 Xmodem.Ymodem和Zmodem协议是最常用的三种通信协议. Xmodem协议是最早的,支持传输128字节信息块. Ymodem是Xmodem的改进版协议,具有传输快速稳定的 ...
最新文章
- linux curl编译 arm交叉编译
- 论文浅尝 | 直译优于翻译?混合语言的知识库问答方法研究
- idea 亮度 调整_工业设计 | 2019优秀产品设计——IDEA金奖作品
- APP安全防护基本方法(混淆/签名验证/反调试)
- crc可以检出奇数个错误_计算机网络学习笔记 3.3 差错控制
- 一套价值800元的爱代挂源码完整版
- 六维空间:优秀的教育网IPV6免费资源共享平台!
- matlab 有限元法,基于Matlab语言的有限元法及其应用
- CCC与Android交互的注意点
- 教程篇(7.0) 10. FortiGate安全 反病毒 ❀ Fortinet 网络安全专家 NSE 4
- 网页通用的测试用例(出处:: 51Testing-- lxp1119216)
- 使用串口连接Arduino与树莓派开发板
- 半同步半异步模式 -------一个架构模式,清晰的结构,高效并发的I/O
- 跟想这台计算机usb无法识别,跟这台计算机连接的前一个usb设备工作不正常,windows 无法识别它。 这是怎么回事急!!...
- 麒麟处理器是基于arm的吗_直接采用ARM的CPU和GPU,那么麒麟芯片算自研吗?
- 20:关于x++和++x的用法
- 你做的数据运营,90%都是无用功
- 全网最硬核 JVM TLAB 分析(单篇版不包含额外加菜)
- 认识电子计算机ppt幼儿园,大班科学优质课教案《认识电子计算器》含PPT课件
- php 无法加载activex,IE怎么无法加载 Activex 控件?