一、先来几张靓图
二、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(); //初始化W25Q128
- sys_data_read();
-
- res=f_mount(&fs,"0:",1); //挂载FLASH.
- if(res==0X0D)//FLASH磁盘,FAT文件系统错误,重新格式化FLASH
- {
- printf("Flash Disk Formatting...\r\n"); //格式化FLASH
- res=f_mkfs("0:",1,4096);//格式化FLASH,1,盘符;1,不需要引导区,8个扇区为1个簇
- if(res==0)
- {
- f_setlabel((const TCHAR *)"0:PROG"); //设置Flash磁盘的名字为:ALIENTEK
- printf("Flash Disk Format Finish\r\n"); //格式化完成
- }
- else
- printf("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; //是否应答ACK
- u8 packNumCnt;
- u32 br; //程序移动指针
- u32 updatingProgSize;//程序读取字节
- u32 progWriteAddr; //写MCU程序地址
- u8 readProgBuf[2048];//读取存储BUF
-
- if(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)//应答ACK
- ymodem_answer_ack();
- else
- ymodem_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;//结束包号是0
- isAck=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)); //MD5
-
- sysParaSave.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),可以改为其他容量的。
|