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

网上好多初学者 都想知道如何更好的用IAP,BOOTLOADER 功能

我给大家一个我自己的基于Xmodem的例子,

开发环境  KEIL 5.14 + STD标准库

芯片 STM32F103ZET6   外部晶振8MHz

用串口1通讯,通讯收发都用查询方式,没有用中断

另外用了systick 来做固定时间的延时程序

下面直接上代码

延时程序部分,

其实这个代码我也是从网上摘录的,不过希望大家好好理解一下

udelay.c

 1 #include "stm32f10x.h"
 2 
 3 static u8  fac_us=0;//us延时倍乘数
 4 static u16 fac_ms=0;//ms延时倍乘数
 5 
 6 
 7 //初始化延迟函数
 8 //SYSTICK的时钟固定为HCLK时钟的1/8
 9 //SYSCLK:系统时钟
10 
11 void uDelay_SysTick_init(u8 SYSCLK)
12 {
13     SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟  HCLK/8 //b->1011
14     fac_us=SYSCLK/8;            
15     fac_ms=(u16)fac_us*1000;
16 }    
17 
18 
19 //延时nms
20 //注意nms的范围
21 //SysTick->LOAD为24位寄存器,所以,最大延时为:
22 //nms<=0xffffff*8*1000/SYSCLK
23 //SYSCLK单位为Hz,nms单位为ms
24 //对72M条件下,nms<=1864 
25 
26 
27 void uDelay_SysTick_ms(u16 nms)
28 {                     
29     u32 temp;
30     
31     SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit)
32     
33     SysTick->VAL =0x00;           //清空计数器
34     SysTick->CTRL=0x01 ;          //开始倒数  
35     
36     do
37     {
38         temp=SysTick->CTRL;
39     }
40     while(temp&0x01&&!(temp&(1<<16)));//等待时间到达
41     
42     SysTick->CTRL=0x00;       //关闭计数器
43     SysTick->VAL =0X00;       //清空计数器              
44 }
45 
46 //延时nus
47 //nus为要延时的us数.    
48 
49 void uDelay_SysTick_us(u32 nus)
50 {        
51     u32 temp;             
52     SysTick->LOAD=nus*fac_us; //时间加载    
53     
54     SysTick->VAL=0x00;        //清空计数器
55     SysTick->CTRL=0x01 ;      //开始倒数 
56     
57     do
58     {
59         temp=SysTick->CTRL;
60     }
61     while(temp&0x01&&!(temp&(1<<16)));//等待时间到达   
62     
63     SysTick->CTRL=0x00;       //关闭计数器
64     SysTick->VAL =0X00;       //清空计数器     
65 }

补一下 串口查询发送的 代码给你们 

1 void uUART_PutChar(USART_TypeDef* USARTx, uint8_t Data)
2 {
3     //while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){}
4     USARTx->SR;
5     USART_SendData(USARTx, Data);
6     while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET){}
7 }

以下就是今天的核心内容,大家注意看啊

  1 /* Includes ------------------------------------------------------------------*/
  2 #include "stm32f10x.h"
  3 #include "stdio.h"
  4 
  5 /* Private typedef -----------------------------------------------------------*/
  6 
  7 /* Private define ------------------------------------------------------------*/
  8 #define CLI() __set_PRIMASK(1) //关闭总中断
  9 #define SEI() __set_PRIMASK(0) //打开总中断
 10 /* Private macro -------------------------------------------------------------*/
 11 
 12 /* Private variables ---------------------------------------------------------*/
 13 
 14 /* Private function prototypes -----------------------------------------------*/
 15 
 16 /* Private functions ---------------------------------------------------------*/
 17 extern void uUART_PutChar(USART_TypeDef* USARTx, uint8_t Data);
 18 extern void uUSART_Init(void);
 19 
 20 extern void uDelay_SysTick_init(u8 SYSCLK);
 21 extern void uDelay_SysTick_ms(u16 nms);
 22 extern void uDelay_SysTick_us(u32 nus);
 23 
 24 #define def_FLASH_BASE     (u32)(0x08000000) 
 25 #define def_FLASH_PAGESIZE (u32)(2048) 
 26 #define def_FLASH_PAGECUNT (u32)(256) 
 27 #define def_USERAPP_START  (u32)(def_FLASH_BASE + (def_FLASH_PAGESIZE * 20))
 28 #define def_USERAPP_BOTTOM (u32)(def_FLASH_BASE+def_FLASH_PAGESIZE * 256-def_FLASH_PAGESIZE*2)
 29 
 30 u32  gFlash_User_Address;        //FLASH地址
 31 u16  gFlash_128Bytes_Cnt=0;
 32 
 33 //-----------------------------------------------------------------------------
 34 
 35 //定义Xmoden控制字符
 36 #define XMODEM_NUL           0x00
 37 #define XMODEM_SOH           0x01
 38 #define XMODEM_STX           0x02
 39 #define XMODEM_EOT           0x04
 40 #define XMODEM_ACK           0x06
 41 #define XMODEM_NAK           0x15
 42 #define XMODEM_CAN           0x18
 43 #define XMODEM_EOF           0x1A
 44 #define XMODEM_WAIT_CHAR     XMODEM_NAK
 45 
 46 
 47 #define dST_WAIT_START       0x00    //等待启动
 48 #define dST_BLOCK_OK         0x01    //接收一个数据块成功
 49 #define dST_BLOCK_FAIL       0x02    //接收一个数据块失败
 50 #define dST_OK               0x03    //完成
 51 
 52 //定义全局变量
 53 
 54 struct str_XMODEM
 55 {
 56     unsigned char SOH;               //起始字节
 57     unsigned char BlockNo;           //数据块编号
 58     unsigned char nBlockNo;          //数据块编号反码
 59     unsigned char Xdata[128];        //数据128字节
 60     unsigned char CheckSum;          //CheckSum校验数据
 61 }strXMODEM;                           //XMODEM的接收数据结构
 62 
 63 unsigned char  gXM_BlockCount;          //数据块累计(仅8位,无须考虑溢出)
 64 unsigned char  gXM_STATUS;              //运行状态
 65 //-----------------------------------------------------------------------------
 66 
 67 //接收指定字节数据(带超时控制)
 68 //    *ptr        数据缓冲区
 69 //    len            数据长度
 70 //    timeout        超时设定
 71 //  返回值        已接收字节数目
 72 
 73 unsigned char get_data(unsigned char *ptr,unsigned char len,u32 timeout)
 74 {
 75     unsigned count=0;
 76     do
 77     {
 78         if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET) //recive
 79         {
 80             *ptr++ = USART_ReceiveData(USART1);//如果接收到数据,读出
 81                        
 82             USART_ClearFlag(USART1, USART_FLAG_RXNE); 
 83             
 84             count++;
 85             
 86             if (count>=len)
 87             {
 88                 break;               //够了?退出
 89             }
 90          continue;   
 91         }
 92         
 93         uDelay_SysTick_us(10);
 94         timeout--;
 95     }
 96     while (timeout);
 97     return count;
 98 }
 99 
100 unsigned char uCheckSum(unsigned char *ptr,unsigned char count)
101 {
102     unsigned char CheckSum=0;
103 
104     while (count--)
105     {
106         CheckSum = CheckSum + *ptr++ ;
107     }
108     return CheckSum;
109 }
110 
111 
112 void uXMODEM_Process()
113 {
114     unsigned char c;
115     u16 i;
116     unsigned char CheckSum;
117     uint16_t dataIndex;  
118     uint16_t *pBuffer;
119     
120     //向PC机发送开始提示信息
121     printf("--> User program upgrade 
");
122     printf("--> Press the [d] key in 60 seconds . 
");
123     printf("--> After 60 seconds running the user program . 
");
124     
125     //60秒种等待PC下发“d”,否则退出Bootloader程序
126     
127     c=0;
128     
129     get_data(&c,1,100*1000*60);         //限时60秒,接收一个数据
130     
131     if ((c=='d')||(c=='D'))
132     {
133         gXM_STATUS=dST_WAIT_START;        //并且数据='d'或'D',进入XMODEM
134         printf("--> Please use the XMODEM protocol to transfer the BIN file. 
");
135         printf("--> The maximum of BIN file size is xxxKB 
");
136     }
137     else
138     {
139         gXM_STATUS=dST_OK;            //退出Bootloader程序
140     }
141 
142     //进入XMODEM模式
143 
144     gXM_BlockCount=0x01;
145     
146     gFlash_128Bytes_Cnt = 0;    
147 
148     gFlash_User_Address = def_USERAPP_START;
149     
150     while (gXM_STATUS!=dST_OK)                             //循环接收,直到全部发完
151     {
152         if (gXM_STATUS==dST_WAIT_START)
153         {
154             //XMODEM未启动
155             uUART_PutChar(USART1,XMODEM_WAIT_CHAR);     //发送请求XMODEM_WAIT_CHAR
156         }
157         
158         i=get_data(&strXMODEM.SOH,132,100*1000);            //限时1秒,接收133字节数据
159         
160         if (i)
161         {
162             //分析数据包的第一个数据 SOH/EOT/CAN
163             switch (strXMODEM.SOH)
164             {
165                 case XMODEM_SOH:                        //收到开始符SOH
166                     if (i>=132)
167                     {
168                         gXM_STATUS=dST_BLOCK_OK;
169                     }
170                     else
171                     {   //如果数据不足,要求重发当前数据块
172                         gXM_STATUS=dST_BLOCK_FAIL;
173                         uUART_PutChar(USART1,XMODEM_NAK);
174                     }
175                     break;
176                     
177                 case XMODEM_EOT:                        //收到结束符EOT
178                     uUART_PutChar(USART1,XMODEM_ACK);   //通知PC机全部收到
179                     gXM_STATUS=dST_OK;
180 
181                     printf("--> User program upgrade finished 
");
182                     break;
183                 
184                 case XMODEM_CAN:                        //收到取消符CAN
185                     uUART_PutChar(USART1,XMODEM_ACK);   //回应PC机
186                     gXM_STATUS=dST_OK;
187 
188                     printf("--> Warning: Cancel the upgrade, the user program may not complete .
");
189                     break;
190                 
191                 default:        //起始字节错误
192                     uUART_PutChar(USART1,XMODEM_NAK);   //要求重发当前数据块
193                     gXM_STATUS=dST_BLOCK_FAIL;
194                     break;
195             }
196         }
197 
198 
199 
200         if (gXM_STATUS==dST_BLOCK_OK)                      //接收133字节OK,且起始字节正确
201         {
202             if (gXM_BlockCount != strXMODEM.BlockNo)       //核对数据块编号正确
203             {
204                 uUART_PutChar(USART1,XMODEM_NAK);       //数据块编号错误,要求重发当前数据块
205                 continue;
206             }
207             if (gXM_BlockCount !=(unsigned char)(~strXMODEM.nBlockNo))
208             {
209                 uUART_PutChar(USART1,XMODEM_NAK);       //数据块编号反码错误,要求重发当前数据块
210                 continue;
211             }
212 
213             CheckSum=strXMODEM.CheckSum;
214             if (uCheckSum(&strXMODEM.Xdata[0],128)!=CheckSum)
215             {
216                 uUART_PutChar(USART1,XMODEM_NAK);       //CheckSum错误,要求重发当前数据块
217                 continue;
218             }
219             //------------------------------------------------------------------------------------
220             //正确接收128个字节数据
221              
222             if ((def_USERAPP_START <= gFlash_User_Address) &&(gFlash_User_Address <= def_USERAPP_BOTTOM))
223             {      
224 
225                 FLASH_Unlock();         //解锁写保护
226                 
227                 if((gFlash_128Bytes_Cnt==0) && ((gFlash_128Bytes_Cnt %16)==0))
228                 {
229                     //擦除一整页
230                     FLASH_ErasePage(gFlash_User_Address);//擦除这个扇区
231                 }
232 
233                 //写128字节
234                 pBuffer =(u16 *) &strXMODEM.Xdata[0];
235                 
236                  for(dataIndex=0;dataIndex<64;dataIndex++)
237                 {
238                     FLASH_ProgramHalfWord(gFlash_User_Address+dataIndex*2,pBuffer[dataIndex]);
239                 }                   
240 
241                 
242                 FLASH_Lock();//上锁写保护  
243                 
244                 gFlash_128Bytes_Cnt++;
245                 gFlash_User_Address = def_USERAPP_START + 128*gFlash_128Bytes_Cnt;
246                       
247                 
248             }
249             else
250             {
251                 uUART_PutChar(USART1,XMODEM_CAN);       //程序已满,取消传送
252                 uUART_PutChar(USART1,XMODEM_CAN);
253                 uUART_PutChar(USART1,XMODEM_CAN);
254                 
255                 gXM_STATUS=dST_OK;
256                 
257                 printf("--> The Flash Rom is full , Transfer stop 
");
258                 
259                 break;
260                 
261             }
262             
263             //------------------------------------------------------------------------------------
264          
265             uUART_PutChar(USART1,XMODEM_ACK);           //回应已正确收到一个数据块
266             gXM_BlockCount++;         //数据块累计加1
267         }
268     }
269 
270 }
271 
272 
273 
274 //主程序
275 int main(void)
276 {
277     
278     //考虑到BootLoader可能由应用程序中跳转过来,所以所用到的模块需要全面初始化
279     //这个BootLoader没有使用中断   
280    
281     uUSART_Init();
282     uDelay_SysTick_init(72);    
283     CLI();
284     
285     while(1)
286     {    
287 
288         
289         printf(" 
");
290         printf("--> ******************************************************* 
");
291         printf("--> Programmer : Cao henglin  
"); 
292         printf("--> TEL : 15050225228 (wechat)  
"); 
293         printf("--> Q Q : 88410664  
"); 
294         printf("--> E-MAIL : caohenglin@outlook.com  
");  
295         printf("--> ******************************************************* 
");   
296         
297         uXMODEM_Process();
298         
299         printf("--> Run ! 
");
300         
301         //下面执行 跳转到USER APP 中执行
302         //代码我不写了,你们自己补一下,哈哈哈!!!
303         //对了一定要处理中断向量表啊,别忘记!!!
304     }
305     
306     
307 }

以上就是实现  XModem的 全部代码了

跳转代码  我没有写,你们自己动动小手自己解决一下吧

这个Xmodem 主体代码,我参照了 AVR专家 马老师的例子,感谢马老师的分享!

----------------------------------

以下我是用的超级终端,WIN7以后电脑自身不带超级终端了,可以把超级终端拷贝过来使用

我就是在WIN10下用的,尽管图标显示有问题,已经很熟悉了,我不介意,哈哈哈

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

还要我讲一遍么?

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

fromelf.exe  --bin --output .ObjectsMDKT3.bin .ObjectsMDKT3.axf

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

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

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

检查没有问题

非常好

检查末尾也没有问题

非常成功!

原文地址:https://www.cnblogs.com/caohenry999/p/13026681.html