2026/4/18 10:33:41
网站建设
项目流程
企业网站运营,学网站开发好不好,广州优化排名推广,网站后台密码存在哪单片机产品开发时可以使用JLink、DAPLink等烧录器进行固件下载和调试#xff0c;当产品开发完成量产后如果需要升级固件一般都会通过串口、CAN等配合Bootloader进行升级#xff0c;除了在单片机端实现一个Bootloader外还需要实现一个按照既定通讯协议发送固件的程序#xff…单片机产品开发时可以使用JLink、DAPLink等烧录器进行固件下载和调试当产品开发完成量产后如果需要升级固件一般都会通过串口、CAN等配合Bootloader进行升级除了在单片机端实现一个Bootloader外还需要实现一个按照既定通讯协议发送固件的程序如果使用的单片机支持USB则有更方便的升级方式接下来实现一个虚拟成U盘拖拽固件升级的Bootloader这里用到的是一个将USB引出的STM32F103C8T6的核心板打开STM32CubeMX新建一个STM32F103的工程配置USB定义Bootloder大小实现APP跳转方法如果不勾选USB MicroLIB需要再定义大一点复制#define BOOT_SIZE 0x4000#define APP_ADDR (FLASH_BASE BOOT_SIZE)typedef void (*pFunction)(void);void BL_StartAPP(void){pFunction start_application;uint32_t app_address;__disable_irq();app_address *(__IO uint32_t*) (APP_ADDR 4);start_application (pFunction) app_address;__set_MSP(*(__IO uint32_t*) app_address);start_application();}Bootloder大小可以完成Bootloader后再调整可以通过编译出的Hex文件计算例如下面这个关于Hex文件的格式可以在网上搜索最后的地址是0x3FE0最后一条的数据长度是0C所以Bootloder大小为0x3FEC定义为0x4000就够了使用PB9来控制是否进入Bootloader当PB9为高电平时跳转到APP在GPIO初始化后添加复制if(LL_GPIO_IsInputPinSet(KEY_GPIO_Port,KEY_Pin)){LL_mDelay(100);if(LL_GPIO_IsInputPinSet(KEY_GPIO_Port,KEY_Pin)){LL_GPIO_SetOutputPin(LED_GPIO_Port,LED_Pin);BL_StartAPP();}}LL_GPIO_ResetOutputPin(LED_GPIO_Port,LED_Pin);if(LL_GPIO_IsInputPinSet(KEY_GPIO_Port,KEY_Pin)){LL_mDelay(100);if(LL_GPIO_IsInputPinSet(KEY_GPIO_Port,KEY_Pin)){LL_GPIO_SetOutputPin(LED_GPIO_Port,LED_Pin);BL_StartAPP();}}接下来需要虚拟一个文件系统这里如果对文件系统不熟悉也没关系可以使用分区工具DiskGenius分出一个最小容量的分区没有空闲分区的可以在虚拟机里操作格式化后顺便放进一个提示文件选中这个分区记录下这两个数值打开扇区编辑全选然后另存为一个文件用winhex打开刚才保存的文件找到这几个不为0的数据段使用winhex的复制为C源码的选项将数据粘贴到代码中其中DBR中有一大段是启动代码可以忽略FAT1和FAT2的数据一样复制#define BL_FAT_CLUSTER_SIZE 0x200 //簇大小#define BL_FAT_INDEX_START_ADDR 0x11000 //目录起始地址#define BL_FAT_INDEX_BIN_START_ADDR 0x11080 //写入的BIN文件起始地址#define BL_FAT_DATA_START_ADDR 0x15000 //数据起始地址//以下是一个8M的FAT16分区的数据结构//DBR 0x00-0x1FF 以55 AA结尾引导程序代码部分省略const uint8_t BL_FAT_dbr[70] {0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x08, 0x00,0x02, 0x00, 0x02, 0x00, 0x40, 0xF8, 0x40, 0x00, 0x3F, 0x00, 0xFF, 0x00, 0x00, 0x08, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x23, 0x48, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20,0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x41, 0x54, 0x31, 0x36, 0x20, 0x20, 0x20, 0x59, 0x55,0x59, 0x59, 0x31, 0x39, 0x38, 0x39};//FAT1 0x1000 FAT2 0x9000const uint8_t BL_FAT_fat1_fat2[4]{0xF8,0xFF,0xFF,0xFF};//根目录 0x11000const uint8_t BL_FAT_root_dir[128] {0x53, 0x54, 0x4D, 0x33, 0x32, 0x42, 0x4F, 0x4F, 0x54, 0x20, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x95, 0xCC, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x42, 0x68, 0x00, 0x65, 0x00, 0x72, 0x00, 0x65, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x64, 0xFF, 0xFF,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,0x01, 0x70, 0x00, 0x75, 0x00, 0x74, 0x00, 0x20, 0x00, 0x62, 0x00, 0x0F, 0x00, 0x64, 0x69, 0x00,0x6E, 0x00, 0x20, 0x00, 0x66, 0x00, 0x69, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x65, 0x00, 0x20, 0x00,0x50, 0x55, 0x54, 0x42, 0x49, 0x4E, 0x7E, 0x31, 0x20, 0x20, 0x20, 0x20, 0x00, 0xB3, 0x93, 0x95,0xCC, 0x5A, 0xCC, 0x5A, 0x00, 0x00, 0x94, 0x95, 0xCC, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};接下来实现USB读取方法将这些数据发送给电脑复制void BL_FAT_ReadBlocks512(uint32_t block_addr,uint8_t *data,uint16_t block_len){uint32_t data_index block_addr * 512;uint32_t data_len block_len * 512;memset(data,0,data_len);if(data_index 0)//DBR{memcpy(data,BL_FAT_dbr,70);data[510] 0x55;data[511] 0xAA;}else if(data_index 0x1000 || data_index 0x9000) //FAT1 FAT2{memcpy(data,BL_FAT_fat1_fat2,4);}else if(data_index 0x11000)//根目录{memcpy(data,BL_FAT_root_dir,128);}}void BL_FAT_ReadBlocks512(uint32_t block_addr,uint8_t *data,uint16_t block_len){uint32_t data_index block_addr * 512;uint32_t data_len block_len * 512;memset(data,0,data_len);if(data_index 0)//DBR{memcpy(data,BL_FAT_dbr,70);data[510] 0x55;data[511] 0xAA;}else if(data_index 0x1000 || data_index 0x9000) //FAT1 FAT2{memcpy(data,BL_FAT_fat1_fat2,4);}else if(data_index 0x11000)//根目录{memcpy(data,BL_FAT_root_dir,128);}}在usbd_storage_if.c中的STORAGE_Read_FS调用这个方法编译烧录后拉低PB9通过USB连接电脑和核心板电脑上会出现这个盘符打开也能看到提示文件接下来实现通过U盘接收固件数据原本想用固定地址接收的但是有些系统接入U盘后会写入一些系统文件这样就占用了原本的地址虽然并没有成功写入但是可能是系统缓存的原因继续添加文件的话文件数据的起始地址就变了在0x11000这个地址存储着U盘中文件的索引数据格式如图向U盘添加文件后会在后面顺序添加这个文件的索引对于长文件名的文件最后也会追加一个短文件名的索引因此只需要判断最后一个文件索引的扩展名是不是BIN就行了。虚拟数据已经占用了前4个索引因此从第5个索引开始查找找到最后一个索引判断文件是否为BIN格式如果是BIN格式获取到数据的簇偏移号和大小成功获取到簇偏移号后就能计算出数据的写入地址然后等待USB写入数据并将固件的数据写入内部FLASH复制void BL_FAT_WriteBlocks512(uint32_t block_addr,uint8_t *data,uint16_t block_len){uint32_t data_index block_addr * 512;uint32_t data_len block_len * 512;uint16_t sum 0;if(data_index BL_FAT_INDEX_START_ADDR)return;if(find_bin_data_addr 0) //还未找到固件起始地址寻找最后一个不为0的文件索引{if(data_index BL_FAT_DATA_START_ADDR){if(data_index BL_FAT_INDEX_BIN_START_ADDR){data_index 0x80;data 0x80;data_len - 0x80;find_bin_data_addr 0;current_fat_file_addr BL_FAT_INDEX_BIN_START_ADDR;current_bin_data_addr 0;current_bin_data_size 0;current_flash_addr APP_ADDR;}if(data_index current_fat_file_addr 31)return;while(data_len 0){sum 0;for(uint8_t i 0;i32;i){sum data[i];}if(sum 0){if(current_bin_data_addr ! 0 current_bin_data_size ! 0){find_bin_data_addr 1;}break;}else{current_fat_file_addr data_index;if(data[11] 0x20 data[8] B data[9] I data[10] N (data[26] 1 || data[27] 0)){current_bin_data_addr BL_FAT_DATA_START_ADDR (data[26](data[27]8)-2)*BL_FAT_CLUSTER_SIZE; //减2才是真正的簇号current_bin_data_size data[28] (data[29]8) (data[30]16) (data[31]24);if(current_bin_data_size BOOT_SIZE (*(uint16_t*)(FLASHSIZE_BASE))*1024) //固件过大{current_bin_data_size 0;led_delay 200;}}}data_index 32;data 32;data_len - 32;}}}else{if(data_index current_bin_data_addr)return;if(data_len current_bin_data_size){BL_FlashApp(data,current_bin_data_size);//写入FLASH的方法省略网上例程很多current_bin_data_size 0;}else{BL_FlashApp(data,data_len);current_bin_data_size - data_len;}if(current_bin_data_size 0){find_bin_data_addr 0;led_delay 1000;}}}至此Bootloader部分就完成了接下来实现APP部分新建一个工程在工程设置中修改起始地址和长度在C/C标签添加USER_VECT_TAB_ADDRESS到末尾升级使用的是BIN文件在User选项卡中添加fromelf --bin -o .\L\L.bin #L就能在编译后生成bin文件了打开system_stm32f1xx.c修改偏移量之后就能像平常一样进行编程了编译出的bin文件就可以拖动到Bootloader的U盘中实现升级了效果如下在此基础上还可以增加文件校验加密传输防止降级等功能有兴趣的可以自行尝试---------------------作者yuyy1989链接https://bbs.21ic.com/icview-3461600-1-1.html来源21ic.com此文章已获得原创/原创奖标签著作权归21ic所有任何人未经允许禁止转载。