• [源创] 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这个用户区

    检查没有问题

    非常好

    检查末尾也没有问题

    非常成功!

  • 相关阅读:
    TCP四种定时器--学习笔记
    Python魔术师--self
    python的socket里 gethostbyname 与 gethostbyname_ex 的区别
    用python查看URL编码的中文
    基于linux 的2048
    用灵活的指针访问类私有变量
    ie8无法拉伸背景图
    图片的onerror 事件解析
    stream.js
    Promise
  • 原文地址:https://www.cnblogs.com/caohenry999/p/13026681.html
Copyright © 2020-2023  润新知