STM32+Python用XMODEM协议升级固件之STM32固件开发

本文章针对有嵌入式编程基础的技术人员,Python制作上位机软件工具需要会使用Pycharm工具。文章不再具体描述嵌入式开发的基础和Python的基础语法等问题,有些语法会在文章中间说明,其中Python制作的软件升级工具成功升级STM32F103CT6和STC8H8K64U的固件,着重讲解Python+PYQT5+STM32F103C8T6使用XMODEM协议升级固件的开发过程。

目录

一: XMODEM的STM32F103C8初始化代码。

XMODEM的原理就不多说了,各个博主都有分享,本代码通过Windows系统自带的超级终端测试,本人使用Python编写的代码也测试过,都能正常使用。很多人可能有疑问,为何Windows超级终端可以使用,为何还要自己写个工具呢?原因如下:

1: Windows系统超级终端不能自由的发数据,例如发单个字节或者多少个字节。

2: Windows系统超级终端使用不友好,对于非专业技术人员,有难度,更别说让客户使用了。

3: 一般嵌入式产品做好后,后续需要维护升级,可以通过发命令方式进入Boot。根据个人喜好,也可以在代码中添加自己的调试命令,Windows超级终端对这方面不大友好,而通过的串口工具,例如SSCOM又不具备下载升级功能。

1.1:代码整体框架

     ​​​  

Main.C代码如下:

#include "main.h"

void SystemClock_Config(void);

int main(void)
{
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_AFIO);
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);

  NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

  LL_GPIO_AF_DisableRemap_SWJ();

  SystemClock_Config();

  InitLedGPIO();                              // 初始化LED的GPIO
  CheckAPPFirmware();                 // 检测是否有固件

  Delay1us(30000);                         // 延时
  
  InitUsart1();                                  // 初始化串口1
  InitTimer3();                                 // 初始化定时器3
  
  InitXModem();                            // 初始化XMODEM的参数
  while (1)
     {
         LEDTask();                         // LED任务
        XModemTask();                  // XMODEM任务
     } 
}

1.2: SystemClock_Config()代码

这部分代码由STM32生成,简单配置时钟频率即可

void SystemClock_Config(void)
{
  LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);
  while(LL_FLASH_GetLatency()!= LL_FLASH_LATENCY_2)
  {
  }
  LL_RCC_HSI_SetCalibTrimming(16);
  LL_RCC_HSI_Enable();

   /* Wait till HSI is ready */
  while(LL_RCC_HSI_IsReady() != 1)
  {

  }
  LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI_DIV_2, LL_RCC_PLL_MUL_16);
  LL_RCC_PLL_Enable();

   /* Wait till PLL is ready */
  while(LL_RCC_PLL_IsReady() != 1)
  {

  }
  LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
  LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
  LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
  LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);

   /* Wait till System clock is ready */
  while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
  {

  }
  LL_Init1msTick(64000000);                        // 配置Tick时钟频率为64MHz
  LL_SetSystemCoreClock(64000000);        // 配置系统主时钟为64MHz
}

1.3:InitLedGPIO() 代码

void InitLedGPIO(void)
{
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};  
    /* GPIO Ports Clock Enable */
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC);
    LL_GPIO_ResetOutputPin(LED_GPIO_Port, LED_Pin);
    GPIO_InitStruct.Pin = LED_Pin;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;    // 此模式可选其它
    LL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);
  
    LedOff();                //关闭LED灯,进入boot后,会快速闪烁

}

1.4: CheckAPPFirmware()代码

检查是否需要更新固件。

void    CheckAPPFirmware(void)
{
    u16    APPData;

    APPData = Flash_ReadData16Bit( FLASH_APP_CHECK_ADDRESS );    

    if((APPData == APP_NEED_TO_UPDATE_DATA) || (APPData == 0xFFFF) )        //检查到Flash升级标识,表示需要升级
        {            
            return;    
        }

    BootloaderJumpToApp();       
}

1.5: InitUsart1()串口1初始化代码

void InitUsart1(void)
{

      LL_USART_InitTypeDef USART_InitStruct = {0};

      LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

      LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
      LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
      
      GPIO_InitStruct.Pin = LL_GPIO_PIN_9;
      GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
      GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
      GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
      LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

      GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
      GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING;
      LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

      /* USART1 interrupt Init */
      NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
      NVIC_EnableIRQ(USART1_IRQn);

      USART_InitStruct.BaudRate = BAUDRATE;
      USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
      USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
      USART_InitStruct.Parity = LL_USART_PARITY_NONE;
      USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
      USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
      USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
      LL_USART_Init(USART1, &USART_InitStruct);
      LL_USART_ConfigAsyncMode(USART1);
     
      LL_USART_DisableIT_TC( USART1);          
      LL_USART_DisableIT_TXE(USART1);          
      LL_USART_EnableIT_RXNE(USART1);   
      LL_USART_Enable(USART1);      
}

1.6: InitTimer3()代码   

// 在Xmodem中,不使用定时器3中断,这里仅示例定时器的配置,1ms定时器中断

void InitTimer3(void)
{

  LL_TIM_InitTypeDef TIM_InitStruct = {0};

  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);

  NVIC_SetPriority(TIM3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(TIM3_IRQn);

  TIM_InitStruct.Prescaler = 6400-1;                            //100us
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
  TIM_InitStruct.Autoreload = 10;                                //计数器重装载值,10*100us,产生1ms定时中断
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
  LL_TIM_Init(TIM3, &TIM_InitStruct);
  LL_TIM_EnableARRPreload(TIM3);
  LL_TIM_SetClockSource(TIM3, LL_TIM_CLOCKSOURCE_INTERNAL);
  LL_TIM_SetTriggerOutput(TIM3, LL_TIM_TRGO_RESET);
  LL_TIM_DisableMasterSlaveMode(TIM3);

  LL_TIM_EnableIT_UPDATE(TIM3);
  LL_TIM_EnableCounter(TIM3);

  LL_SYSTICK_EnableIT();
  
  SystemTime = 0;                //此变量做系统时钟实,在Tick时钟对此变量+1操作

}

1.7: InitXModem()代码

void     InitXModem(void)
{
    InitXModemParameter();    
    Flash_ErasePages(FLASH_APP_START_ADDRESS, STM32_FLASH_PAGES-          BOOT_LOADER_PAGE_SIZE);
}

void     InitXModemParameter(void)
{
    XModemStructure.XModemReceiveDataPackTimeStart = DISABLE;
    XModemStructure.XModemReceiveDataPackSuccess = ERROR;    
    
    XModemStructure.XModemDataErrorTimes = 0;    
    XModemStructure.XModemReceiveDataPackTime = 0;    

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hhccxw

你的肯定是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值