[源創] 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這個用戶區
檢查沒有問題
非常好
檢查末尾也沒有問題
非常成功!