[源创] 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 : caohenglin@outlook.com \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这个用户区
检查没有问题
非常好
检查末尾也没有问题
非常成功!