ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32F103VET6智能小车源代码从工程打开到烧录调试的完整指南

STM32F103VET6智能小车源代码从工程打开到烧录调试的完整指南 简介基于STM32F103VET6的智能小车完整源代码工程面向嵌入式初学者、电子竞赛选手及希望快速搭建小车平台的开发者覆盖从芯片初始化到电机控制、传感器融合与通信协议处理等关键环节。压缩包共21.32MB内含2000个文件主体为C/H语言源码365个C、111个H并辅以汇编文件、Keil工程文件uvprojx、链接脚本及大量HTML/JS/PNG等说明与图表素材方便对照技术原理阅读。该资源已有1169人学习下载多用于智能车竞赛、课程设计及STM32入门实践。代码按功能模块划分电机驱动、超声波测距、蓝牙控制等部分层次清晰同时包含HAL库底层驱动和中断服务逻辑适合在真实硬件上移植、调试也可作为学习ARM Cortex-M3中断、PWM调速与嵌入式系统架构设计的参考。1. 为什么 STM32F103VET6 是智能小车源代码的常见主控选择以及拿到 zip 后第一步该看什么你在搜索引擎里输入“基于STM32的智能小车源代码”下载最多的压缩包后缀是 zip解压后十有八九能看到STM32F103VET6这个芯片型号。这颗芯片不是性能最强的也不是最便宜的但它有一个优势512KB Flash 和 64KB SRAM 刚好覆盖了 MCU 小车项目的全部需求从 PWM 调速到编码器测速从循迹传感器到蓝牙遥控都能塞进一片芯片里不用像 C8T6 那样为 Flash 空间砍功能。很多毕业设计、电子竞赛和工程训练项目的源代码都选它作为主控导致这类 zip 在网上形成了一个固定品类。但拿到 zip 后直接双击工程文件编译的人往往会在十分钟内遇到三个问题Keil 提示找不到芯片型号、Flash 下载算法不匹配、烧录时 ST-Link 连接不稳定。这些问题的原因不在代码而在你没把 zip 当软件包看待。压缩包里的.uvprojx、.ioc、USER/、HARDWARE/这些目录结构决定了你该用哪个 IDE、哪个库函数版本以及哪些外设引脚配置。这篇文章就顺着“工程打开 → 外设驱动 → 烧录调试 → 改造复用”这条线把 STM32F103VET6 智能小车源代码从 zip 变成真的能跑的小车。适合刚入门的学子也适合手上有一堆下载代码但没人讲解的竞赛队友。2. 智能小车源代码的项目骨架从解压 zip 到 Keil/STM32CubeIDE 打开工程2.1 解压 zip 后识别工程类型Keil MDK 的 .uvprojx 与 CubeIDE 的 .ioc下载下来的 zip 解压后先别急着找main.c。打开根目录看一眼有没有.uvprojx、.ioc、.cproject这三种文件这决定了后续所有操作路线。如果是 Keil MDK 工程根目录或MDK-ARM子目录下能看到项目名.uvprojx双击就能打开。如果是 STM32CubeIDE 工程根目录有.project和.cproject同时还有一个.ioc文件那是 CubeMX 的图形化引脚配置文件。第三种情况最考验人zip 里只有USER、HARDWARE、SYSTEM这类源码文件夹没有任何工程文件这是作者故意省去了 IDE 配置让使用者自己建工程。# 在 Linux 或 Git Bash 里执行快速定位工程文件类型 cd ~/smart_car_src find . -maxdepth 3 \( -name *.uvprojx -o -name *.ioc -o -name *.cproject \) -print这个命令只做一件事把三种工程文件的路径列出来。如果输出只有.ioc和.cproject就用 STM32CubeIDE 导入如果只有.uvprojx就用 Keil 打开如果一条输出都没有那你得手工建工程。很多人在这里犯的错误是明明手上有.ioc却想用 Keil 直接打开结果 Keil 提示文件格式不受支持于是怀疑压缩包有问题。其实.ioc是 CubeMX 的项目配置Keil 根本读不了。2.2 用 Keil MDK 打开 STM32F103VET6 工程前要装的芯片支持包如果确定是 Keil 工程用 MDK5 打开.uvprojx时最常弹出的错误是Device: STM32F103VET6 not found。这个提示不是因为你的 MDK 版本太老而是缺芯片支持包。Keil MDK 5.x 的器件库不再内置全部由Pack Installer管理。打开Tools - Pack Installer在Packs页签里展开STMicroelectronics找到STM32F1 Series Device Support并安装如果安装失败可以去 Keil 官网下载离线包手动安装。装完之后重启 Keil在Options for Target - Device左侧树形菜单里应该能定位到STMicroelectronics - STM32F1 Series - STM32F103VE。选型必须精确到VE不能顺手选成ZE或C8。STM32F103VET6是 LQFP100 封装Flash 512KB而C8T6只有 64KB Flash、LQFP48 封装外设地址和中断向量表虽然大部分兼容但某些源码里用到了FSMC或SDIO等 C8T6 没有的外设编译时会报undefined symbol。芯片包安装好之后还要在Utilities - Settings - Flash Download里确认下载算法是STM32F10x High-density Flash 512K。很多从网上下的智能小车源代码作者用的是 C8T6 的 128K 算法直接烧录会卡在Erase Failed。2.3 配置魔术棒选项卡芯片型号、Flash 下载算法与调试器Keil 里按AltF7打开Options for Target这套配置是所有 STM32F103VET6 智能小车源码通用的。Device页检查芯片是不是STM32F103VETarget页检查外部晶振Xtal填的是 8.0MHz 还是 25MHz。这个值很关键因为HSE_VALUE宏定义要和实际板子焊接的晶振一致如果源码里写的是 8MHz而你板子上是 12MHz 晶振系统时钟会变成 84MHz 而不是 72MHz串口波特率误差会直接导致乱码PWM 频率也会整体偏高。Debug页选择ST-Link Debugger然后点Settings确认Connect模式是Normal或under ResetFlash Download里勾选Reset and Run。工程文件类型打开工具必须检查项常见坑.uvprojx.uvoptxKeil MDKDevice 选择 STM32F103VEFlash 算法 High-density 512K沿用 C8T6 的 128K 算法导致擦除失败.ioc.cprojectSTM32CubeIDE检查 CubeMX 生成的 HAL 库版本导入后外设时钟树被覆盖只有源码文件夹手动建 Keil/CubeIDE 工程启动文件startup_stm32f103xe.s漏加HARDWARE头文件路径这张表覆盖了从 zip 到可编译工程的三条主要路径。我一般遇到没有工程文件的源码时会先建一个空工程把下载算法和芯片型号配置好然后把源码里的USER、HARDWARE、SYSTEM目录复制进工程挨个添加.c文件。这个过程比较机械但能让你对整个项目的文件依赖关系有清晰认识后面调试外设时不容易抓瞎。3. 智能小车关键外设驱动PWM 电机控制、GPIO 循迹与串口调试3.1 电机控制用定时器 PWM 输出控制 L298N 或 TB6612智能小车源代码里最核心的驱动是电机控制常见方案用 L298N 模块左右两个电机分别由一路 PWM 调速和两个方向引脚控制。STM32F103VET6 的TIM2和TIM3都是通用定时器输出 PWM 足够。选定时器时要避开已经被系统占用的TIM1因为TIM1属于高级定时器多了一堆刹车输入和互补输出逻辑配置复杂度高对直流电机调速没有实际意义。常见的引脚分配是TIM2_CH1接左电机 ENATIM2_CH2接右电机 ENB方向引脚用两个普通 GPIO。void PWM_Init(void) { // 使能 TIM2 和 GPIOA/GPIOB 时钟注意 APB1 和 APB2 不要写反 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitTypeDef gpio; gpio.GPIO_Pin GPIO_Pin_0 | GPIO_Pin_1; // PA0 PA1 作为 PWM 输出 gpio.GPIO_Mode GPIO_Mode_AF_PP; // 复用推挽 gpio.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, gpio); gpio.GPIO_Pin GPIO_Pin_3 | GPIO_Pin_4; // PB3 PB4 方向控制 gpio.GPIO_Mode GPIO_Mode_Out_PP; GPIO_Init(GPIOB, gpio); // 72MHz / (711) 1MHz重载值 999PWM 频率 1kHz TIM_TimeBaseInitTypeDef tim; TIM_TimeBaseStructInit(tim); tim.TIM_Prescaler 72 - 1; tim.TIM_Period 999; TIM_TimeBaseInit(TIM2, tim); TIM_OCInitTypeDef oc; TIM_OCStructInit(oc); oc.TIM_OCMode TIM_OCMode_PWM1; oc.TIM_OutputState TIM_OutputState_Enable; oc.TIM_Pulse 0; TIM_OC1Init(TIM2, oc); // 通道1 左电机 TIM_OC2Init(TIM2, oc); // 通道2 右电机 TIM_Cmd(TIM2, ENABLE); } void Motor_SetSpeed(uint8_t left, uint8_t right) { TIM_SetCompare1(TIM2, left); TIM_SetCompare2(TIM2, right); }上面这段代码用的是标准外设库很多从正点原子、野火模板衍生出来的智能小车源代码都是这种风格。TIM_Prescaler71和TIM_Period999决定了系统时钟分频后 PWM 频率是 1kHz对应周期 1ms。L298N 对这种低频 PWM 响应没问题但电机高速换向时声音会有点大。如果换用 TB6612FNG 模块建议把 PWM 频率提到 10kHz 以上减小电感啸叫做法是将TIM_Period改为 99同时把Motor_SetSpeed的参数范围从 0-999 改成 0-99。方向引脚的逻辑组合参考驱动板手册L298N 的 IN11、IN20 正转反过来反转两个都是 1 是刹车两个都是 0 是惰行。3.2 循迹模块GPIO 输入读取与状态判断逻辑循迹小车一般使用 2 到 5 路 TCRT5000 红外反射传感器。每路传感器输出一个数字电平STM32 端配置为浮空输入或上拉输入。代码里最常见的是直接在主循环里逐个读取 GPIO再用若干if判断传感器状态组合。这种写法在只有一路传感器时没问题但五路循迹时组合有 32 种每加一种情况就多一层if代码越来越烂。更好的做法是给 5 路传感器的二进制组合建一张查找表表里直接存左右电机的修正值。#define BASE_SPEED 500 uint8_t Track_Scan(void) { uint8_t value 0; value | GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_0) 0; value | GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1) 1; value | GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_2) 2; value | GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_3) 3; value | GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_4) 4; return value; } void Track_Control(void) { static const int8_t left_tbl[32] { 0, 0, -20, -30, 0, 0, 0, -40, 20, 0, 0, 0, 0, 0, 0, -40, 0, 0, 0, 0, 30, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0 }; static const int8_t right_tbl[32] { 0, 0, 20, 30, 0, 0, 0, 40, -20, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, -30, 0, 0, 0, -40, 0, 0, 0, 0, 0, 0, 0 }; uint8_t s Track_Scan(); Motor_SetSpeed(BASE_SPEED left_tbl[s], BASE_SPEED right_tbl[s]); }Track_Scan把 PC0-PC4 的电平拼成一个 5 位整数低 5 位最大值就是 31所以两张查找表大小都是 32。索引 4二进制 00100表示只有中间传感器压线查表结果是左右不修正直行。索引 300011表示左侧两个传感器偏出左轮减 20、右轮不动小车左修正。这种查表法相比连续if的优势是逻辑清晰、执行时间固定后续增加传感器数量只需要改表长度和Track_Scan的位拼接方式。注意 TCRT5000 模块输出极性不一定一致有些模块检测到黑线输出低电平有些输出高电平源码里如果对传感器数值取反要对应调整GPIO_ReadInputDataBit之后处理。3.3 测速编码器定时器输入捕获模式速度闭环小车会在轮轴上装霍尔编码器两路输出信号相位差 90 度。STM32 的定时器有硬件编码器接口只要把 A 相、B 相接在同一个定时器的 CH1 和 CH2初始化时配置TIM_EncoderInterfaceConfig硬件就会自己完成相位判断和倍频计数。STM32F103VET6的TIM4通道 1、2 映射在 PB6、PB7一部分源码用的是这个组合但也有用到TIM1或TIM2的在自己改板子时务必对照数据手册查引脚复用表。void Encoder_Init(void) { GPIO_InitTypeDef gpio; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); gpio.GPIO_Pin GPIO_Pin_6 | GPIO_Pin_7; gpio.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOB, gpio); TIM_TimeBaseInitTypeDef tim; TIM_TimeBaseStructInit(tim); tim.TIM_Prescaler 0; tim.TIM_Period 0xFFFF; TIM_TimeBaseInit(TIM4, tim); TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); TIM_SetCounter(TIM4, 0); TIM_Cmd(TIM4, ENABLE); } int16_t Encoder_GetCount(void) { return (int16_t)TIM_GetCounter(TIM4); }TIM_EncoderMode_TI12模式下计数器会在 A 相和 B 相的上升沿都计数所以实际分辨率是编码器线数的 4 倍。每隔固定时间读取一次计数器值与上次相减就是这段时间的脉冲增量。这里有个坑TIM_Period设为 0xFFFF计数值到了 65535 再增会溢出到负数所以读取函数返回类型必须是int16_t否则负数会被当成很大的正数PID 正反馈直接飞车。编码器线数也要和电机型号对应网上源码经常写 13 线或 11 线但你买的减速电机可能是其他规格改错这个值会让速度环比例系数失效。3.4 串口调试printf 重定向与波特率校验小车跑起来之后第一件事是确认主控在运行最常用的手段是串口打印。智能小车源码里串口几乎固定使用USART1引脚 PA9/PA10波特率 115200 或 9600。如果源码里已经调用了printf但串口助手没有输出先看 Keil 工程有没有勾选Use MicroLIB不勾选的话fputc重定向不会生效。#include stdio.h int fputc(int ch, FILE* f) { while (!(USART1-SR USART_SR_TXE)); USART1-DR ch; return ch; }这段代码把printf的输出引导到USART1。注意USART_SR_TXE是发送数据寄存器空标志只有该位为 1 时才允许写入USART1-DR有些源码写的是USART_FLAG_TC那是发送完成标志两者差别是 TC 等字节完全发完才返回低速串口下会明显拖慢printf。波特率校验很简单先在main开头打印一行HELLO\r\n如果收到的字符串整体错位但 ASCII 码能看出规律基本是波特率设置不一致如果收到一堆0x00或0xFF优先检查系统时钟和晶振配置。外设定时器/引脚参数示例说明左电机 PWMTIM2_CH1 / PA01kHz占空比 0-999接 L298N ENA右电机 PWMTIM2_CH2 / PA11kHz占空比 0-999接 L298N ENB左方向PB3PB4推挽输出IN1/IN2 组合5 路循迹PC0-PC4上拉输入TCRT5000 数字输出编码器TIM4_CH1/CH2 / PB6/PB716 位计数4 倍频计数调试串口USART1 / PA9/PA101152008N1printf 输出上述引脚分配不是行业标准但是网上大多数 STM32F103VET6 智能小车源码的默认接线。拿到 zip 后先把引脚映射画出来再对照自己的驱动板比逐行读源码更高效。4. 烧录与调试 stm32 智能小车固件过程中最常见的坑No STM32 Target Found 与 Flash 校验失败4.1 调试器连接失败Error: No STM32 target found!把代码编译通过之后插上 ST-LinkKeil 点下载最可能跳出来的是Error: Flash Download failed - Cortex-M3或者在 STM32CubeProgrammer 里看到Error: No STM32 target found! If your product embeds Debug Authentication...。F103VET6 没有调试认证单元后半句可以忽略问题大概率出在连接线上。先检查 ST-Link 和板子的 SWD 三根线SWDIO 对应 PA13SWCLK 对应 PA14GND 必须连通。这看起来简单但实际中很多人把 SWDIO 和 SWCLK 接反因为排针丝印不清晰。第二种情况是目标板上的程序把 PA13/PA14 重映射成了普通 GPIO导致调试端口被占用。解决办法是让 ST-Link 在复位期间强行连接Debug - Settings - Connect改为under Reset同时把 ST-Link 的 NRST 线接到板子上。如果手里没有 NRST 飞线可以按住板子复位键点击下载在提示连接的一瞬间松开这种方式成功率不稳定但对老式 ST-Link 有时能奏效。在Options for Target - Debug - Settings里看到 IDCODE 显示0x1BA01477时说明连接已建立。4.2 Boot0 跳线、供电与复位电容烧录成功但拔掉调试器后小车不运行第一个怀疑对象就是 BOOT0。STM32F103VET6 的 BOOT0 如果拉高上电从系统存储器启动而不是用户 Flash程序根本没执行。网上很多源码配的接线图BOOT0 的跳线帽位置拍得不清楚照图接成 3.3V 的人不在少数。用万用表测量 BOOT0 引脚电压运行模式下应该接近 0V。BOOT1 一般悬浮但在某些板子上 BOOT1 被上拉到高这时 BOOT0 低电平依然从 Flash 启动问题不大。供电是另一个隐形杀手。L298N 电机驱动板内部有 5V 稳压器如果 STM32 最小系统板的 5V 直接从 L298N 输出取电机启动瞬间电流可以到 1A 以上稳压器输出电压瞬间跌落主控掉电复位。表现是程序运行一会儿突然从头开始或者烧录时 ST-Link 频繁掉线。稳妥做法是电机驱动供电用独立电池STM32 用 USB 5V 或另一路稳压模块两块板子之间只连接信号线。复位电容大小被忽视的频率也很高F103VET6 的 NRST 去耦电容一般用 104100nF如果被换成了 10uF复位时间会拉长某些调试器在高速连接时就会超时。4.3 用 ST-Link Utility 和串口打印验证固件是否运行烧录成功的提示不能完全相信最好用 STM32 ST-LINK Utility 的Read功能读回 Flash检查 0x08000000 起始地址是否包含0x20000000开头的栈顶值和0x0800XXXX的复位向量。如果读回来全是0xFF说明擦除成功了但写入失败Keil 的烧录日志里会有隐藏的校验错误。通过验证后再拔掉 ST-Link单独给板子上电看串口有没有输出。如果串口没有输出一种情况是程序跑飞另一种是时钟配置错了此时用示波器量 PA9 引脚应该有明显的电平翻转。错误现象直接原因验证手段解决办法No STM32 target foundSWD 两根线接反万用表量 PA13/PA14 与排针连通性交换 SWDIO/SWCLKFlash 下载失败下载算法与 Flash 密度不符查看 Keil Log 中的算法名称添加 High-density 512K 算法烧录成功但不上电运行BOOT0 为高电平量 BOOT0 电压跳线帽接到 GND程序运行中重启电机拉低逻辑电源示波器看 5V 跌落电机和逻辑分开供电4.4 下载算法和烧录地址不匹配时怎么办有些智能小车源代码带 bootloader烧录地址不是0x08000000而是0x0800C000Keil 工程里对应的IROM1也会被改成0x0800C000。如果没注意直接烧录要么 Keil 提示写入地址越界要么烧完了程序跑不起来。遇到这种工程最简单的方法是把IROM1改回0x08000000Size设为0x80000然后重新编译全量烧录。这样会失去原来的串口升级或 IAP 功能但至少能先让小车动起来。如果必须保留 bootloader 的分区可以在 app 的main函数前面调用NVIC_SetVectorTable(0x08000000, 0xC000)把中断向量表偏移到 app 起始地址否则任何中断都会跳转到 bootloader 的向量表程序一开中断就死机。5. 把下载的源代码改造成自己的智能小车参数调整、避障扩展与源代码版本管理5.1 通过宏定义调整 PWM 频率、电机死区与转向灵敏度下载的源码里速度和转向参数通常散落在各个地方。直接改main里的数字调几轮下来自己都记不住哪个值对应哪个行为。我会先把左右电机占空比上限、转向修正值、循迹传感器阈值统一收敛到一个config.h头文件里。比如定义BASE_SPEED、TURN_OFFSET、DEAD_ZONE_MIN然后在代码里引用这些宏。这样回到家想调只需要打开一个文件。电机死区的处理是很多人忽略的细节。L298N 驱动直流减速电机时占空比低于某个阈值电机根本转不起来PWM 值从 0 加到 80 完全没反应超过 100 突然窜出去。解决办法是设定一个最小输出值在电机启动时直接跳到最小转动力矩以上。#define PWM_MAX 999 #define PWM_MIN 120 void Motor_SetSpeed(int left, int right) { if (left PWM_MAX) left PWM_MAX; if (left -PWM_MAX) left -PWM_MAX; if (right PWM_MAX) right PWM_MAX; if (right -PWM_MAX) right -PWM_MAX; if (left 0 left PWM_MIN) left PWM_MIN; if (left 0 left -PWM_MIN) left -PWM_MIN; if (right 0 right PWM_MIN) right PWM_MIN; if (right 0 right -PWM_MIN) right -PWM_MIN; TIM_SetCompare1(TIM2, left 0 ? left : -left); TIM_SetCompare2(TIM2, right 0 ? right : -right); GPIO_WriteBit(GPIOB, GPIO_Pin_3, left 0 ? 1 : 0); GPIO_WriteBit(GPIOB, GPIO_Pin_4, left 0 ? 1 : 0); }这段代码把PWM_MIN作为死区补偿负值代表反转方向引脚电平也相应翻转。注意取绝对值时不要用abs因为abs对-2147483648这类边界值处理会有问题这里的占空比范围只是 0-999直接用三目运算符更安全。TIM_Period如果从 999 改成 99PWM_MAX和PWM_MIN也要对应缩放否则占空比超过重载值输出行为会变成常开或常关。5.2 外扩超声波避障模块注意中断优先级和 GPIO 映射循迹小车要加避障最常见的外设是 HC-SR04 超声波模块。TRIG 引脚发送一个 10us 高电平触发测距ECHO 引脚返回一个宽度代表距离的脉冲。测量 ECHO 高电平时间可以用定时器输入捕获也可以直接循环读取 GPIO。听起来软件延时简单但 72MHz 下每条指令约 14ns超声波最远测距 4m对应 ECHO 高电平 23ms用循环等待会把 CPU 占死期间中断抖动会干扰编码器测速。所以建议 ECHO 接在定时器通道上用硬件输入捕获。typedef enum {RUN_FORWARD, RUN_LEFT, RUN_RIGHT, RUN_BACK} CarState_t; CarState_t g_state RUN_FORWARD; void Car_Update(void) { uint32_t dist Ultrasonic_GetDistance(); // 单位 cm switch (g_state) { case RUN_FORWARD: if (dist 30) { Motor_SetSpeed(-BASE_SPEED, BASE_SPEED); g_state RUN_LEFT; } else { Motor_SetSpeed(BASE_SPEED, BASE_SPEED); } break; case RUN_LEFT: delay_ms(200); g_state RUN_FORWARD; break; default: g_state RUN_FORWARD; break; } }状态机是避障逻辑里最适合小车的结构。RUN_FORWARD直行中如果前方距离小于 30cm左轮反转、右轮正转让车身右转状态切到RUN_LEFT等 200ms 后切回直行。注意Ultrasonic_GetDistance内部必须有超时保护比如连续等待 50ms 没等到 ECHO 下降沿就返回一个超大值否则模块前方没障碍物时ECHO 一直高电平程序卡死在等待函数里表现和死机一样。另外 HC-SR04 的 ECHO 输出是 5V 电平F103VET6 的 GPIO 容忍 5V可以直接连但部分模块在低电压时输出波形不规整串一个 1k 电阻再并联 10k 电阻到地能明显减少误触发。5.3 用 Git 管理从 zip 得到的源代码避免改坏后回退不了从 zip 解压出来的源代码第一件事就是初始化 Git 仓库把原始状态提交一个版本。这样后面无论怎么改都能回到最初能编译的版本。cd ~/smart_car_src git init git add . git commit -m import original stm32f103vet6 smart car source from zip git tag v0.1-original提交之后每调整一个参数或新增一个功能模块就单独提交一次。比如把 PWM 频率从 1kHz 改成 10kHz提交信息写清楚原因。当避障逻辑把循迹算法改出问题时git diff一眼就能看到改动范围。对于 Keil 工程建议把MDK-ARM/Objects/、MDK-ARM/Listings/和*.uvguix.*加入.gitignore这些是编译中间文件每次构建都会变化放进版本控制只会制造噪音。针对那些感觉烧录后没运行但连接正常的情况最后留个检查方法用 STM32CubeProgrammer 连接芯片读Option Bytes里的读保护级别。如果显示Level 1芯片 Flash 内容受保护Keil 的下载行为会异常。这是很多源码发布者交付前用 ST-Link Utility 勾了写保护导致的。用 CubeProgrammer 的Full chip erase解除读保护再重新烧录问题通常就消失了。这个技巧不算高深但 5 年经验以上的工程师也经常栽在它上面。本文还有配套的精品资源点击获取
返回列表