一、先来几张靓图



二、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校验相关推荐

  1. oracle包校验和失败怎么回事,lol更新包md5校验失败怎么回事_更新lol提示更新包MD5校验失败如何处理-win7之家...

    lol英雄联盟是很多用户都喜欢的一款网络游戏,有时候有新版本的时候很多用户会对其进行更新,可是有不少用户在更新lol的时候,却遇到更新包md5校验失败,请稍后重试的提示,导致无法更新,这要怎么办呢,为 ...

  2. STM32F103代码远程升级(三)基于YModem协议串口升级程序的实现

    文章目录 一.YModem协议简介 二.YModem的数据格式 1.起始帧的数据格式 2.数据帧的数据格式 3.结束帧的数据格式 4.文件传输过程 三.基于Ymodem协议串口升级程序的实现过程 1. ...

  3. STM32F103 通过SD卡IAP升级程序,带MD5校验,(带源码)可在实际项目中使用

    一.将APP程序从SD卡搬运到MCU中 首先从sd卡通过FAFTS文件操作系统打开程序文件,然后记录下复制开始地址和程序文件大小 fileOperionResult = f_open(&upd ...

  4. 野火串口助手协议发送文件通讯协议——XMODEM协议——YMODEM协议

    野火串口助手协议发送文件通讯协议 修订历史 日期 版本 更新内容 2020/6/22 0.0.1 首次发布 XMODEM协议 上位机是现实了XModem-CRC16和XModem-1K; XModem ...

  5. STM32的升级--ICP/ISP/IAP以及Ymodem协议分析

    资料下载 Ymodem协议传输过程分析 ICP/ISP/IAP 区别 ICP(In-Circuit Programing): 通过J-Link/SWD等下载器烧写程序,上位机需要借助其他硬件的参与才能 ...

  6. 红帽子redhat linux 9.0官方下载地址,附MD5校验码

    红帽子redhat linux 9.0官方下载地址如下: https://archive.download.redhat.com/pub/redhat/linux/9/en/iso/i386/shri ...

  7. ymodem android,【安卓相关】蓝牙基于Ymodem协议发送bin文件,对硬件设备进行升级。...

    最近做的一个安卓项目是使用蓝牙基于Ymodem协议传输bin文件,实现对硬件设备进行升级. 做的过程中遇到了不少困难,用我这半吊子的语文水平,记录一下吧 怎么办,平时对各种文件传输协议真的是知之甚少啊 ...

  8. STM32 Ymodem 协议及代码解析

    点击左上角的"关注",定期更新 STM32 最新资讯,总有你想要的信息! STM32 Ymodem 协议及代码解析 文章导图: 1. Ymodem 协议传输效果 1.1 发送端软件 ...

  9. Ymodem协议学习笔记

    介绍   Xmodem.Ymodem和Zmodem协议是最常用的三种通信协议.   Xmodem协议是最早的,支持传输128字节信息块.   Ymodem是Xmodem的改进版协议,具有传输快速稳定的 ...

最新文章

  1. linux curl编译 arm交叉编译
  2. 论文浅尝 | 直译优于翻译?混合语言的知识库问答方法研究
  3. idea 亮度 调整_工业设计 | 2019优秀产品设计——IDEA金奖作品
  4. APP安全防护基本方法(混淆/签名验证/反调试)
  5. crc可以检出奇数个错误_计算机网络学习笔记 3.3 差错控制
  6. 一套价值800元的爱代挂源码完整版
  7. 六维空间:优秀的教育网IPV6免费资源共享平台!
  8. matlab 有限元法,基于Matlab语言的有限元法及其应用
  9. CCC与Android交互的注意点
  10. 教程篇(7.0) 10. FortiGate安全 反病毒 ❀ Fortinet 网络安全专家 NSE 4
  11. 网页通用的测试用例(出处:: 51Testing-- lxp1119216)
  12. 使用串口连接Arduino与树莓派开发板
  13. 半同步半异步模式 -------一个架构模式,清晰的结构,高效并发的I/O
  14. 跟想这台计算机usb无法识别,跟这台计算机连接的前一个usb设备工作不正常,windows 无法识别它。 这是怎么回事急!!...
  15. 麒麟处理器是基于arm的吗_直接采用ARM的CPU和GPU,那么麒麟芯片算自研吗?
  16. 20:关于x++和++x的用法
  17. 你做的数据运营,90%都是无用功
  18. 全网最硬核 JVM TLAB 分析(单篇版不包含额外加菜)
  19. 认识电子计算机ppt幼儿园,大班科学优质课教案《认识电子计算器》含PPT课件
  20. php 无法加载activex,IE怎么无法加载 Activex 控件?

热门文章

  1. go圣经笔记——程序结构
  2. 猎豹2018秋招编程题2
  3. 量产动效视频原来如此简单
  4. Vscode格式化 代码
  5. 电机学-交流绕组-基本要求
  6. python383安装教程_安装pip
  7. sudoku数独软件
  8. 【学习笔记】softmax回归与mnist编程
  9. 随机产生唯一的app_key和app_secret
  10. 基于VUE2.0的高仿饿了么分析与总结