本文章针对有嵌入式编程基础的技术人员,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;

最低0.47元/天 解锁文章
4311





