/*************************************************** *注意要想二次升级必须要在用户APP中将 UPDATA_FLAG[0]='0'并保存在flash中! }1 |3 b! b% f# D *设置完成后将单片机重启,重启完成将升级包通过串口发送给单片机即可升级完成' k$ I, }& K8 R *同时注意用户APP中需要在程序的开头添加SCB->VTOR = FLASH_BASE | 0x10000;语句! `, u4 c( D* c1 k d% V1 m *本实验程序为考虑后期利用8266升级所以设置波特率为 1152000 X5 X9 Z! k5 o4 p: O p5 o- o *注意本程序代码的升级包限定最小20个字节才为升级包否则为控制命令 ****************************************************/ //主函数部分 #include "led.h"" ~: R( _0 N) w$ `& M #include "delay.h" #include "sys.h" #include "usart.h") x0 L( D' d% w' @ #include "stmflash.h" #include "iap.h" #include "time.h"% s6 J, z, F; A3 v u16 UPDATA_FLAG[1]; int main(void) { " m/ n- b0 ?. ?" d6 T9 I u16 oldcount=0; //老的串口接收数据值 u16 applenth=0; //接收到的app代码长度% U2 ~ F& |! X; `7 Z9 r, T static u8 START_UPDATA=0; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(256000); //串口初始化为256000& a& u( [6 l, F7 Z) z( @ delay_init(); //延时初始化 1 e0 |" F! [. z LED_Init();1 @1 a) `" }& D( j: Q TIM2_Init(9,7199); //升级延时定时器0 w' c1 D% h5 d2 o; A1 J: ~6 J3 Z( g STMFLASH_Read(0X08071000,(u16*)UPDATA_FLAG,1); //读取更新标志 如果此标志位为:'1'代表程序已经更新了 如果为 '0'代表程序在执行IAP等待接收升级包 if(UPDATA_FLAG[0]=='0')3 r7 H/ w2 i, V8 Y! ]( e {0 M4 z& J! Z- F2 ^9 G //等待发送更新包,说明程序从用户程序进行了重启 //提示发送更新包 printf("Please send update package....\r\n"); } else if(UPDATA_FLAG[0]=='1')6 u. N$ ^3 B4 V$ w3 A7 G { printf("Loading...\r\n"); } while(1)$ b% P5 L. G( }2 x { LED1=!LED1; //LED闪烁指示/ Y6 z3 O0 q9 S9 Y2 d& M delay_ms(100); p+ A% r; f3 d( r: Z, K0 v: k if(USART_RX_CNT) {# W! V& G% p+ v0 L+ J) l9 {) {4 ` if(oldcount==USART_RX_CNT)//新周期内,没有收到任何数据,认为本次数据接收完成. { applenth=USART_RX_CNT;- m# ~' f2 C3 R% ]% @ oldcount=0; USART_RX_CNT=0; if(applenth>20) //此处强行规定发过来的升级包必须大于20个字节否则不予升级 {+ `: I: Y4 o! I" H2 { printf("USER CODE RXC\r\n"); //提示升级包接收完成 printf("CODE SIZE:%dBytes\r\n",applenth);, @7 R! r% D3 C0 l( Y1 K5 c START_UPDATA=1; //此标志为1时可以进入升级 UP_DATA_Time_3000ms=0;4 ~" @9 T- B& b }5 n: U8 n) O- W* Y }else oldcount=USART_RX_CNT; }1 I# l, g7 T$ C0 b1 s0 F if(START_UPDATA==1&&UP_DATA_Time_3000ms>=3000) { UP_DATA_Time_3000ms=0; START_UPDATA=2; }; A4 C# \. g$ b2 g' B/ s7 C& @ if(START_UPDATA==2)" Y/ t- t" I; i. r2 y0 r4 c { if(applenth)( }3 Q% i0 |/ e. ]" m { printf("Start updating...\r\n"); if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX. { 6 D1 Y, E7 \0 y& b- a* U. a! W$ T UPDATA_FLAG[0]='1'; STMFLASH_Write(0X08071000,(u16*)UPDATA_FLAG,1); //允许更新标志 STMFLASH_Read(0X08071000,(u16*)UPDATA_FLAG,1); //读取更新标志4 g/ U# N" L8 `! c iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth);//更新FLASH代码 5 z8 L' ?, X8 F6 S. v1 n! u printf("Updated firmware\r\n"); 2 I) A6 S( u/ l/ S+ ^8 D% v printf("Resart \r\n"); delay_ms(100); //延时一小会儿等待上一帧数据发送完成 //软件重启CPU5 _$ |2 T5 N/ g+ u8 d# g( h __disable_fault_irq(); NVIC_SystemReset(); }4 P( N% _) }8 g" T: Q else { printf("Illegal Code!\r\n"); @$ w ?$ }% z4 N. j } }# L9 R8 \% N! M+ A# t# e# u START_UPDATA=0; }2 ~! k( [/ o) T- q /**********************************************************************4 ^* V# }3 y; V$ ]0 f *有升级包进行升级 *此处的标志位需要在用户APP中进行清零后才可进行下一次的更新否则每次上电都会直接跳转到用户APP执行 ***********************************************************************/ ! ]1 b& o7 `; q1 `! w6 ^ if(UPDATA_FLAG[0]=='1') {& k- u( h* m3 r% Y; w- S) |) v6 { if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX. 此处测试一下是否会多次跳入 { $ ~! g# \. q5 u( R6 ]2 r iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码 } }( Y: ~3 [) G6 X( b } * ]. o: r% _+ Q _' v9 r P }. W/ [, T' m' h5 `7 g% V //API部分 #include "sys.h" #include "delay.h"* f' Y" }/ O, u8 O2 I #include "usart.h" #include "stmflash.h" #include "iap.h" iapfun jump2app; u16 iapbuf[1024]; //appxaddr:应用程序的起始地址 //appbuf:应用程序CODE.' Q+ ~6 i2 n- X H5 i# _1 x& T) \% K; u //appsize:应用程序大小(字节). void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize) { u16 t; u16 i=0; u16 temp;1 Z% Y/ b; F. M; B1 C/ S8 B3 B- A u32 fwaddr=appxaddr;//当前写入的地址 u8 *dfu=appbuf;5 k0 b+ S! b: c2 h, c5 S( q, P for(t=0;t<appsize;t+=2) { 7 h: B. ^9 Q' v) j temp=(u16)dfu[1]<<8;* r( A/ o* e6 n! o temp+=(u16)dfu[0]; dfu+=2;//偏移2个字节, R* [( q0 @0 E4 ] iapbuf[i++]=temp; i$ b- u$ E: t1 j5 w6 z' O if(i==1024) {% Y; O" _7 f9 P, Y6 J2 u8 U4 A5 ?/ N i=0;7 l# P6 F" C9 _5 O* t STMFLASH_Write(fwaddr,iapbuf,1024); fwaddr+=2048;//偏移2048 16=2*8.所以要乘以2.# j' B0 s8 L/ q* D2 B8 D% @4 K. | } } if(i)STMFLASH_Write(fwaddr,iapbuf,i);//将最后的一些内容字节写进去. ) V2 W) |+ t' M/ w, P+ S4 E6 E% n } //跳转到应用程序段+ X1 O3 ?! R) }! q+ d/ R' ? //appxaddr:用户代码起始地址. void iap_load_app(u32 appxaddr) {" Q* a. Q! w# O0 _6 z2 b2 O; C if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法. { jump2app=(iapfun)*(vu32*)(appxaddr+4); //用户代码区第二个字为程序开始地址(复位地址) 6 B L3 V7 o3 A; E( s" f8 c6 x MSR_MSP(*(vu32*)appxaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址) jump2app(); //跳转到APP.) Q5 K& E' A0 o8 g" f+ E* i }1 M# k3 T, s ~; B0 d } - M/ }' M$ H! o' C |
é å¥ä¸ä½æº.rar
下载897.98 KB, 下载次数: 1119
æ¬å°å级åè¿ç¨å级ä¸ä½æº
3 ^0 _; a5 f) T- N. U4 b' k
问下楼主,wifi模块是用esp8266吗?
谢谢楼主的分享$ H; O. w' S. s% K8 n& o* V0 r5 u+ j4 b