[源創] 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 \r\n");
122     printf("--> Press the [d] key in 60 seconds . \r\n");
123     printf("--> After 60 seconds running the user program . \r\n");
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. \r\n");
135         printf("--> The maximum of BIN file size is xxxKB \r\n");
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 \r\n");
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 .\r\n");
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 \r\n");
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(" \r\n");
290         printf("--> ******************************************************* \r\n");
291         printf("--> Programmer : Cao henglin  \r\n"); 
292         printf("--> TEL : 15050225228 (wechat)  \r\n"); 
293         printf("--> Q Q : 88410664  \r\n"); 
294         printf("--> E-MAIL : [email protected]  \r\n");  
295         printf("--> ******************************************************* \r\n");   
296         
297         uXMODEM_Process();
298         
299         printf("--> Run ! \r\n");
300         
301         //下面執行 跳轉到USER APP 中執行
302         //程式碼我不寫了,你們自己補一下,哈哈哈!!!
303         //對了一定要處理中斷向量表啊,別忘記!!!
304     }
305     
306     
307 }

 

以上就是實現  XModem的 全部程式碼了

跳轉程式碼  我沒有寫,你們自己動動小手自己解決一下吧

這個Xmodem 主體程式碼,我參照了 AVR專家 馬老師的例子,感謝馬老師的分享!

———————————-

以下我是用的超級終端,WIN7以後電腦自身不帶超級終端了,可以把超級終端拷貝過來使用

我就是在WIN10下用的,儘管圖標顯示有問題,已經很熟悉了,我不介意,哈哈哈

 

 以上要注意,傳輸的文件只能是.bin 文件的格式 二進位的,keil 如何生成 .bin文件

還要我講一遍么?

算了 還是說一下吧,誰叫我這麼好呢

fromelf.exe  –bin –output .\Objects\MDKT3.bin .\Objects\MDKT3.axf

 

 

直接看圖吧,別告訴我不懂啊

 

 

 看看  就是這麼的酷   非常好,已經下載到 我們指定的用戶程式區那邊了

 

用JLINK 把下載後的單片機 程式都讀上來,檢查一下我們下載的程式,有沒有放在0x0800A000這個用戶區

 

 

檢查沒有問題

非常好

 

 

檢查末尾也沒有問題

非常成功!