一、硬件配置方案
// CAN初始化关键代码(CubeMX生成优化版)voidMX_CAN1_Init(void){CAN_FilterTypeDef sFilterConfig={0};// 使能CAN和GPIO时钟__HAL_RCC_CAN1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();// 配置CAN引脚(PA11-RX, PA12-TX)GPIO_InitTypeDef GPIO_InitStruct={0};GPIO_InitStruct.Pin=GPIO_PIN_11|GPIO_PIN_12;GPIO_InitStruct.Mode=GPIO_MODE_AF_PP;GPIO_InitStruct.Pull=GPIO_PULLUP;GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Alternate=GPIO_AF9_CAN1;HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);// CAN基本配置hcan1.Instance=CAN1;hcan1.Init.Prescaler=9;// 72MHz/9=8MHz → 500kbpshcan1.Init.SyncJumpWidth=CAN_SJW_1TQ;hcan1.Init.TimeSeg1=CAN_BS1_8TQ;hcan1.Init.TimeSeg2=CAN_BS2_3TQ;hcan1.Init.TimeTriggeredMode=DISABLE;hcan1.Init.AutoBusOff=ENABLE;hcan1.Init.AutoWakeUp=ENABLE;hcan1.Init.AutoRetransmission=ENABLE;hcan1.Init.ReceiveFifoLocked=DISABLE;hcan1.Init.TransmitFifoPriority=DISABLE;HAL_CAN_Init(&hcan1);// 过滤器配置(接收所有消息)sFilterConfig.FilterBank=0;sFilterConfig.FilterMode=CAN_FILTERMODE_IDMASK;sFilterConfig.FilterScale=CAN_FILTERSCALE_32BIT;sFilterConfig.FilterIdHigh=0x0000;sFilterConfig.FilterIdLow=0x0000;sFilterConfig.FilterMaskIdHigh=0x0000;sFilterConfig.FilterMaskIdLow=0x0000;HAL_CAN_ConfigFilter(&hcan1,&sFilterConfig);}二、CAN通信协议设计
1. 消息格式定义
typedefstruct{uint32_tmagic;// 魔数0xA5A5A5A5uint8_tcmd;// 命令码:0x01=擦除,0x02=写入,0x03=跳转uint16_taddr;// 目标地址uint16_tlen;// 数据长度uint8_tdata[256];// 数据负载uint16_tcrc;// CRC16校验}can_frame_t;2. 关键通信流程
sequenceDiagram participant Bootloader participant Host participant App Host->>Bootloader:发送擦除命令(0x01)Bootloader->>Flash:擦除APP区域(0x08008000-0x0801FFFF)Bootloader-->>Host:返回ACK(0x06)Host->>Bootloader:分块发送数据(0x02)Bootloader->>Flash:写入数据(每包≤256字节)Bootloader-->>Host:返回ACK(0x06)或NACK(0x15)Host->>Bootloader:发送跳转命令(0x03)Bootloader->>Bootloader:验证APP校验和 Bootloader->>App:设置VTOR寄存器 Bootloader->>App:跳转执行三、BootLoader工程实现
1. 启动流程优化
voidBootloader_Main(void){// 1. 禁用中断__disable_irq();// 2. 检查升级标志if(READ_REG(FLASH->OPTCR)&0x01){Jump_To_App(APP_ADDRESS);}// 3. 初始化CANMX_CAN1_Init();CAN_Filter_Config();// 4. 进入接收循环while(1){if(CAN_Message_Received()){Process_CAN_Frame();}}}2. 安全校验机制
// CRC16校验实现uint16_tCalculate_CRC(uint8_t*data,uint16_tlen){uint16_tcrc=0xFFFF;for(uint16_ti=0;i<len;i++){crc^=(uint16_t)data[i]<<8;for(uint8_tj=0;j<8;j++){crc=(crc&0x8000)?(crc<<1)^0x1021:crc<<1;}}returncrc;}// 安全校验流程if(Verify_CRC(frame.data,frame.len)!=frame.crc){Send_Error(0x15);// CRC错误return;}四、App工程适配
1. 中断向量表重定向
// 在system_stm32f1xx.c中修改#defineVECT_TAB_OFFSET0x8000// Bootloader占用前32KB// 在App启动文件中添加externuint32_t_estack_app;__attribute__((section(".isr_vector")))uint32_t*isr_vector[]={&_estack_app,(uint32_t*)APP_Reset_Handler,// 其他中断向量...};2. 双工程编译配置
#Bootloader Makefile片段BOOTLOADER_SRCS=startup_stm32f103xb.s can_driver.c flash_ops.c BOOTLOADER_OBJS=$(BOOTLOADER_SRCS:.c=.o)#App工程Makefile片段APP_SRCS=main.c app_logic.c APP_OBJS=$(APP_SRCS:.c=.o)五、上位机程序设计(Qt示例)
// CANBootloader.pro配置QT+=core gui serialbus// 通信线程实现voidCanWorker::run(){QCanBusDevice*device=QCanBus::instance()->createDevice("can0",this);if(!device)return;connect(device,&QCanBusDevice::framesReceived,[=](quint32 frameId){QCanBusFrame frame=device->receive();processFrame(frame);});}// 数据发送逻辑voidMainWindow::on_sendButton_clicked(){QByteArray data=ui->dataEdit->toPlainText().toUtf8();QCanBusFrameframe(0x18E00001);// 标准IDframe.setPayload(data);canDevice->transmit(frame);}参考代码 基于CAN总线的 STM32F103 的BootLoader,上位机+下位机程序www.youwenfan.com/contentcss/69866.html
六、量产注意事项
Flash保护策略
// 启用写保护FLASH_OB_WRP(ENABLE,0x000000FF);// 保护前1KB版本回滚机制
#defineMAX_RETRIES3if(flash_erase_failed>MAX_RETRIES){Jump_To_Backup_App();// 跳转到备份区}OTA升级流程
七、调试与验证
逻辑分析仪捕获
01030080000800000000000000000000// 擦除命令02030080000800000000000000000000// 写入命令03030080000800000000000000000000// 跳转命令错误处理测试
模拟总线断开:触发CAN错误中断,自动重启
数据篡改测试:修改接收数据后验证CRC失败
八、扩展功能建议
安全增强
// AES加密实现voidEncrypt_Data(uint8_t*data,uint16_tlen){AES_KEY enc_key;AES_set_encrypt_key(key,128,&enc_key);AES_cbc_encrypt(data,data,len,&enc_key,iv,AES_ENCRYPT);}多节点管理
// 节点地址分配表constuint8_tnode_table[32]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10};