1. 这个STM32开源项目到底在分享什么
先说说我为什么想聊这个话题。前段时间我在整理自己硬盘里积压的嵌入式项目时,翻出来一个两年前做的STM32小项目,当时顺手把代码、原理图和仿真文件都打包扔在了开源仓库里。本来没当回事,结果陆续有几个人留言说照着做成功了,还有人问能不能把设计思路讲细一点。这让我意识到,一个完整的STM32开源项目,光扔三个文件上去是远远不够的,真正有价值的是把“为什么这么设计”讲清楚。
所谓“代码 + 原理图 + 仿真”三件套,本质上是一个嵌入式项目从设计到验证的完整闭环。代码解决的是“逻辑怎么跑”,原理图解决的是“电流怎么流”,仿真解决的是“在没打板之前怎么确认前两者没打架”。这三样东西缺一个,项目就不算完整——只有代码没有原理图,别人不知道怎么接线;只有原理图没有代码,板子焊好了也跑不起来;没有仿真,你就得靠反复打板来试错,时间和金钱成本直接翻倍。
这个内容适合谁看?如果你正在做基于STM32的毕业设计,或者想从51单片机进阶到STM32,又或者你手头有个小项目想开源出去但不知道怎么整理,那这篇内容应该能帮到你。我会用一个具体的STM32F103C8T6最小系统项目作为例子,把从需求分析到仿真验证的全流程拆开讲,包括我踩过的坑和后来总结出来的经验。不需要你有多深的嵌入式基础,只要会用Keil、能看懂基本的电路符号就行。
2. 项目整体设计与方案选型思路
2.1 为什么选STM32F103C8T6作为核心
选型这件事,很多人上来就看性能参数,我觉得应该反过来——先看你要做什么,再看什么芯片刚好够用还留点余量。我见过太多人做个小项目直接上STM32H7,结果BOM成本翻了好几倍,焊接难度也上去了,最后功能其实F103就能跑。
STM32F103C8T6这颗芯片在开源社区里被称为“最小系统板之王”,不是没有道理的。72MHz的Cortex-M3内核,64KB Flash,20KB SRAM,加上丰富的外设(2个SPI、2个I2C、3个USART、2个ADC、多个定时器),对于大多数中小规模的控制和采集任务来说完全够用。关键是它的资料生态极其丰富,你遇到任何问题,搜索一下基本都能找到答案。价格方面,国产替代和原厂散新片都很便宜,打样几块板子试错也不心疼。
我对比过几个常见选项:STM32F030系列便宜但外设少,做稍微复杂一点的东西就要外扩;STM32F407性能强但价格和功耗都上去了,对于不需要浮点运算和以太网的项目来说有点浪费。F103C8T6刚好卡在“够用且便宜”这个甜点位上。
2.2 代码、原理图、仿真三者的协同关系
很多人做项目是线性的:先画原理图,再写代码,最后仿真。但我的经验是,这三者应该并行推进,互相验证。原理图画完一个模块,就写对应的驱动代码,然后在仿真环境里跑一下看看逻辑对不对。这样一旦发现问题,修改成本最低。
具体来说,原理图决定了引脚分配和外设连接方式,代码里的GPIO初始化、外设配置必须和原理图严格对应。仿真则是把编译好的固件加载到虚拟的STM32模型中运行,观察引脚电平变化、串口输出、定时器计数等是否符合预期。如果仿真通过但实物不工作,大概率是硬件焊接或电源问题;如果仿真就不通过,那肯定是代码逻辑或配置有误。
注意:仿真不能完全替代实物测试。仿真环境里的时序是理想化的,实际电路中存在的信号抖动、电源纹波、电磁干扰等问题,仿真不一定能反映出来。所以仿真通过只是第一步,实物验证不能省。
2.3 开源项目文件结构的组织方式
一个让人愿意下载的开源项目,文件结构必须清晰。我见过太多仓库把所有文件堆在根目录下,找个原理图要翻半天。我的习惯是按功能分目录:
ProjectName/ ├── Hardware/ │ ├── Schematic/ │ │ ├── MainBoard.SchDoc │ │ └── PowerSupply.SchDoc │ ├── PCB/ │ │ └── MainBoard.PcbDoc │ └── BOM/ │ └── BOM_MainBoard.xlsx ├── Firmware/ │ ├── Core/ │ │ ├── Inc/ │ │ └── Src/ │ ├── Drivers/ │ │ ├── STM32F1xx_HAL_Driver/ │ │ └── CMSIS/ │ ├── MDK-ARM/ │ │ └── Project.uvprojx │ └── README.md ├── Simulation/ │ ├── Proteus/ │ │ └── Project.pdsprj │ └── Wokwi/ │ └── diagram.json ├── Docs/ │ ├── DesignNotes.md │ └── PinMapping.md └── README.md这样别人拿到项目,先看根目录的README了解概况,需要硬件资料进Hardware,需要代码进Firmware,想先仿真验证就进Simulation。每个子目录里再放一个简短的说明文件,告诉别人这个目录里有什么、怎么用。
3. 核心细节解析与实操要点
3.1 原理图设计中的关键模块拆解
以STM32F103C8T6最小系统为例,原理图可以拆成几个核心模块:电源模块、晶振模块、复位模块、启动模式配置、调试接口、外设接口。
电源模块是整个系统的基础。F103的工作电压是2.0V到3.6V,典型值3.3V。如果输入是5V(比如从USB取电),就需要一颗LDO降压到3.3V。我常用的是AMS1117-3.3,便宜好用,但要注意它的压差和散热。输入5V输出3.3V时,压差1.7V,如果负载电流200mA,那LDO上消耗的功率就是0.34W,SOT-223封装勉强能扛住,但最好在输出端加个10uF以上的钽电容或电解电容来稳定电压。
晶振模块方面,F103通常用8MHz的外部高速晶振(HSE)作为PLL输入,经过9倍频后得到72MHz的系统时钟。晶振两端各接一个20pF左右的负载电容,具体值要根据晶振规格书来定。我实测过,如果负载电容不匹配,晶振起振时间会变长,甚至偶尔起振失败。另外,晶振走线要尽量短,远离电源线和高频信号线,否则容易引入噪声。
复位模块用一个10k电阻上拉到3.3V,再加一个100nF电容到地,构成上电复位电路。如果需要手动复位,并联一个轻触开关。启动模式配置通过BOOT0和BOOT1引脚的电平来决定从Flash启动、从系统存储器启动还是从SRAM启动。正常运行时BOOT0接10k下拉到地,BOOT1任意。
调试接口我强烈建议引出SWD接口,只需要SWDIO、SWCLK、GND、3.3V四根线,比JTAG省空间。用ST-Link Utility或者Keil自带的调试器都能直接下载和调试。
3.2 代码架构的分层设计
代码这块,我见过很多初学者把所有逻辑都塞在main.c里,几百行堆在一起,改一个功能要翻半天。我的做法是分层:硬件抽象层(HAL)、驱动层、应用层。
硬件抽象层直接用ST官方的HAL库或者LL库。HAL库的好处是移植方便,换芯片型号时改动小;LL库更接近寄存器,效率高但移植性差一些。对于开源项目,我倾向于用HAL库,因为别人拿到代码后更容易理解和修改。
驱动层是针对具体外设的封装。比如你要驱动一个DHT11温湿度传感器,就写一个dht11.c和dht11.h,里面包含初始化、读数据、校验等函数。这样应用层只需要调用DHT11_ReadData()就能拿到温湿度值,不需要关心底层的时序细节。
应用层就是主逻辑。比如一个环境监测项目,应用层可能是:初始化所有外设 -> 进入主循环 -> 每隔2秒读一次温湿度 -> 通过串口打印 -> 如果温度超过阈值就点亮LED报警。
/* 应用层主循环示例 */ while (1) { if (HAL_GetTick() - lastReadTime >= 2000) { lastReadTime = HAL_GetTick(); if (DHT11_ReadData(&temp, &humi) == DHT11_OK) { printf("Temp: %d.%d C, Humi: %d.%d %%\r\n", temp / 10, temp % 10, humi / 10, humi % 10); if (temp > TEMP_THRESHOLD) { HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); } else { HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); } } } }这种分层的好处是,如果你想换一个温湿度传感器(比如SHT30),只需要重写驱动层,应用层几乎不用动。
3.3 仿真环境的搭建与配置
仿真工具的选择上,Proteus是经典方案,支持STM32F103系列,可以加载Keil编译出来的hex文件,观察引脚电平和外设行为。Wokwi是近几年兴起的在线仿真平台,不需要安装软件,浏览器里就能跑,适合快速验证逻辑,但对STM32的支持不如Proteus全面。
以Proteus为例,搭建仿真的步骤是:新建工程 -> 放置STM32F103C8T6元件 -> 添加必要的外围元件(晶振、电阻、电容、LED、串口终端等)-> 双击STM32元件加载hex文件 -> 设置晶振频率为8MHz -> 运行仿真。
这里有个坑:Proteus里的STM32模型默认是从外部加载hex文件,但如果你在Keil里没有正确设置输出hex,仿真就跑不起来。在Keil的Options for Target -> Output里勾选“Create HEX File”,编译后会在Objects目录下生成hex文件。
另一个坑是时钟配置。Proteus里的STM32模型对时钟树的模拟和实物有差异,如果你在代码里配置了PLL倍频到72MHz,但Proteus里没有正确设置外部晶振频率,仿真可能会跑飞或者时序完全不对。我的经验是,在Proteus里把外部晶振频率设置成和代码里HSE_VALUE一致的值,通常是8000000。
提示:仿真通过不代表实物一定通过,但仿真不通过实物一定不通过。所以仿真是一个低成本的前置验证手段,能帮你排除大部分逻辑错误。
4. 实操过程与核心环节实现
4.1 从零搭建Keil工程并配置时钟
新建Keil工程时,第一步是选芯片型号。在Device里找到STM32F103C8,确认Flash和SRAM大小。然后勾选CMSIS的CORE和Device Startup,以及Device的StdPeriph Drivers或者HAL Drivers。我一般用HAL库,所以勾选HAL下的GPIO、RCC、UART、TIM等需要的外设。
时钟配置是很多新手容易出错的地方。F103的时钟树是这样的:HSE(8MHz)-> PLL输入 -> PLL倍频(x9)-> 系统时钟72MHz -> AHB分频(/1)-> HCLK 72MHz -> APB1分频(/2)-> PCLK1 36MHz -> APB2分频(/1)-> PCLK2 72MHz。注意APB1的最大频率是36MHz,所以如果HCLK是72MHz,APB1必须至少2分频。
在SystemClock_Config()函数里,用HAL_RCC_OscConfig()配置HSE和PLL,用HAL_RCC_ClockConfig()配置AHB、APB1、APB2的分频系数。配置完后可以用HAL_RCC_GetSysClockFreq()读一下实际系统时钟,确认是72000000。
void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } }注意FLASH_LATENCY_2这个参数。当系统时钟超过48MHz时,Flash需要插入等待周期,72MHz对应2个等待周期。如果这个设错了,程序可能跑飞或者读取Flash数据出错。
4.2 GPIO与外设初始化的标准流程
GPIO初始化遵循一个固定套路:使能时钟 -> 配置结构体 -> 调用HAL_GPIO_Init()。以点亮一个LED为例,假设LED接在PA5,低电平点亮:
__HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);串口初始化稍微复杂一点,需要配置波特率、数据位、停止位、校验位、模式等。以USART1为例,PA9是TX,PA10是RX:
__HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); UART_HandleTypeDef huart1; huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(&huart1);这里有个细节:PA9配置成复用推挽输出(AF_PP),PA10配置成浮空输入或上拉输入。如果两个都配成AF_PP,接收可能会出问题。HAL库的HAL_UART_MspInit()回调函数里会自动处理这些,但如果你手动初始化,就要注意这个区别。
4.3 仿真验证的完整操作记录
我在Proteus里验证这个最小系统时,操作顺序是这样的:
第一步,在Proteus里放置STM32F103C8T6、8MHz晶振、两个20pF电容、复位电路(10k电阻+100nF电容)、LED和限流电阻(220欧姆)、虚拟串口终端。
第二步,双击STM32元件,在Program File里选择Keil编译生成的hex文件,Crystal Frequency填8MHz。
第三步,检查电源和地是否连接正确。Proteus里的STM32模型有隐藏的电源引脚,默认是连接的,但如果你用了自定义的电源符号,要确认VDD和VSS都接上了。
第四步,点击运行。如果LED按照代码逻辑闪烁,串口终端有输出,说明基本功能正常。
我遇到过一个问题:仿真运行时串口终端没有输出。排查后发现是Proteus里的虚拟串口终端波特率设置和代码里不一致。代码里是115200,终端默认是9600,改成一致后就正常了。这个坑很典型,实物调试时如果串口助手波特率设错,也会出现乱码或没输出。
另一个问题是仿真速度。Proteus仿真STM32时,如果代码里有延时函数(比如HAL_Delay),仿真时间会按实际时间走,一个2秒的延时就要等2秒。如果主循环里延时很多,仿真会非常慢。我的做法是在仿真时把延时改短,或者用定时器中断来替代阻塞式延时。
5. 常见问题与排查技巧实录
5.1 代码编译通过但仿真跑不起来
这种情况通常有几个原因。一是hex文件没有正确生成或加载。检查Keil的Output设置里是否勾选了Create HEX File,以及Proteus里加载的hex路径是否正确。二是时钟配置问题。如果代码里配置了HSE,但Proteus里的晶振没有起振,系统会卡在HAL_RCC_OscConfig()里等待HSE就绪,直到超时。可以在Proteus里观察晶振引脚是否有波形,或者临时把时钟源改成HSI来排除。
三是栈溢出。F103C8T6的SRAM只有20KB,如果定义了大数组或者递归调用太深,栈可能会溢出。在Keil的Options for Target -> Target里可以设置栈大小,默认是0x400(1KB)。如果程序复杂,可以适当加大,但要注意不要超过SRAM总量。
5.2 实物板子不工作的排查顺序
实物调试和仿真不同,变量更多。我的排查顺序是:电源 -> 时钟 -> 复位 -> 下载 -> 外设。
先量电源。用万用表测VDD引脚对VSS的电压,应该是3.3V左右。如果偏差超过5%,检查LDO输入输出电容是否焊接良好。然后量晶振引脚,用示波器看是否有8MHz正弦波。如果没有,检查晶振和负载电容是否焊接正确,或者换一个晶振试试。
复位引脚在正常运行时应该是高电平。如果一直是低电平,检查复位电路的上拉电阻和电容。下载失败的话,检查SWD接口的SWDIO和SWCLK是否接反,以及BOOT0是否被拉高导致芯片进入了系统存储器启动模式。
外设不工作时,先确认GPIO配置是否正确。比如LED不亮,量一下对应引脚的电平是否在变化。如果电平在变但LED不亮,可能是限流电阻太大或LED极性接反。
5.3 常见问题速查表
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 仿真中LED不闪烁 | hex文件未加载或时钟配置错误 | 检查Program File路径和晶振频率设置 |
| 串口无输出 | 波特率不匹配或TX/RX接反 | 确认两端波特率一致,交换TX/RX试试 |
| 实物无法下载 | SWD接线错误或BOOT0拉高 | 检查SWDIO/SWCLK,确认BOOT0为低 |
| 程序跑飞 | Flash等待周期设置错误 | 72MHz时FLASH_LATENCY应设为2 |
| 晶振不起振 | 负载电容不匹配或晶振损坏 | 更换负载电容,用示波器观察波形 |
| ADC读数跳动大 | 参考电压不稳或输入阻抗过高 | 加滤波电容,降低输入阻抗 |
| 定时器不准 | 时钟源配置错误 | 确认APB1/APB2分频系数和定时器时钟 |
| 中断不触发 | NVIC未使能或优先级配置错误 | 检查HAL_NVIC_EnableIRQ()和优先级分组 |
5.4 几个容易被忽略的实操心得
第一个心得:在原理图里给每个电源引脚都加一个100nF的去耦电容,尽量靠近引脚放置。我早期做板子时觉得麻烦,只加了一两个,结果ADC采样总是有噪声,后来每个电源引脚都加上去耦电容后问题就消失了。这个电容的作用是滤除高频噪声,为芯片提供稳定的局部电源。
第二个心得:SWD接口的SWCLK和SWDIO线上最好各串一个22欧姆的电阻,可以抑制信号反射,提高下载稳定性。尤其是下载线比较长的时候,这个电阻很有用。
第三个心得:在代码里加一个简单的串口打印功能,把关键变量的值输出出来。实物调试时,你没法像仿真那样随时暂停看变量,串口打印是最直接的观测手段。我通常会在初始化完成后打印一行“System Init OK”,在主循环里定期打印传感器数据,这样一眼就能看出程序跑到哪一步了。
第四个心得:开源项目里一定要写清楚引脚映射表。我见过太多项目代码里直接写GPIO_PIN_5,但原理图上没标PA5对应什么功能,别人拿到后要对着代码和原理图来回翻。在Docs目录下放一个PinMapping.md,用表格列出每个引脚的功能、外设、备注,能省掉别人很多时间。
| 引脚 | 功能 | 外设 | 备注 |
|---|---|---|---|
| PA5 | LED | GPIO输出 | 低电平点亮 |
| PA9 | USART1_TX | USART1 | 115200-8-N-1 |
| PA10 | USART1_RX | USART1 | 115200-8-N-1 |
| PA13 | SWDIO | SWD | 调试数据 |
| PA14 | SWCLK | SWD | 调试时钟 |
| PB0 | DHT11_DATA | GPIO | 单总线,需上拉 |
| PC13 | KEY | GPIO输入 | 按下为低 |
这个表格看起来简单,但实际用起来非常方便。别人拿到你的项目,第一件事就是看这个表,然后对照自己的板子接线。
6. 开源项目整理的几个实用建议
6.1 README怎么写才有人看
README是别人了解你项目的第一入口。我见过很多README就一句话“STM32项目,代码在src里”,这种基本没人愿意看。一个好的README应该包含:项目简介(一句话说清楚做什么)、功能列表、硬件需求(芯片型号、外设清单)、软件需求(Keil版本、库版本)、编译和烧录步骤、目录结构说明、引脚映射表、常见问题。
项目简介不要写“基于STM32的智能XXX系统”这种空话,要具体。比如“用STM32F103C8T6读取DHT11温湿度,通过串口输出,温度超阈值时点亮LED”,这样别人一眼就知道这个项目适不适合自己。
编译步骤要写到傻瓜级别。比如“用Keil 5.36打开Firmware/MDK-ARM/Project.uvprojx,点击Build,确认0 Error 0 Warning,然后用ST-Link连接SWD接口,点击Download”。不要假设别人知道怎么操作。
6.2 代码注释的度怎么把握
注释太少别人看不懂,注释太多显得啰嗦。我的原则是:函数头写清楚功能、参数、返回值;关键逻辑行写清楚为什么这么做;显而易见的代码不写注释。
比如一个延时函数:
/** * @brief 微秒级延时函数 * @param us: 延时时长,单位微秒 * @note 基于SysTick实现,最大延时受SysTick重装载值限制 */ void delay_us(uint32_t us) { uint32_t temp; SysTick->LOAD = 9 * us; /* 72MHz下,9个时钟周期约1us */ SysTick->VAL = 0x00; SysTick->CTRL = 0x01; do { temp = SysTick->CTRL; } while ((temp & 0x01) && !(temp & (1 << 16))); SysTick->CTRL = 0x00; SysTick->VAL = 0x00; }这个注释就恰到好处:函数头说明了功能和参数,关键行说明了9这个系数的来源,循环部分说明了等待逻辑。
6.3 版本管理和更新日志
开源项目不是扔上去就不管了。我建议用Git做版本管理,每次有实质性修改就提交一次,写清楚改了什么。比如“修复串口波特率配置错误”、“增加DHT11校验逻辑”、“更新原理图去耦电容”。这样别人能看到项目的演进过程,也方便回退到之前的版本。
如果项目有多个版本,可以在README里加一个更新日志表格:
| 版本 | 日期 | 修改内容 |
|---|---|---|
| v1.0 | 2024-01-15 | 初始版本,实现温湿度采集和串口输出 |
| v1.1 | 2024-02-03 | 增加温度阈值报警功能 |
| v1.2 | 2024-03-10 | 优化DHT11驱动时序,提高读取成功率 |
这个表格不需要多详细,但能让别人知道项目还在维护,不是弃坑了。
6.4 仿真文件的兼容性问题
Proteus的版本兼容性是个坑。高版本Proteus保存的工程文件,低版本打不开。我一般会在README里注明“Proteus 8.13及以上版本”,或者同时导出一份PDF格式的原理图,这样即使别人没有Proteus,也能看到电路设计。
Wokwi的仿真文件是JSON格式的,兼容性好很多,但Wokwi对STM32的支持有限,复杂外设可能跑不了。我的做法是:简单逻辑用Wokwi验证,完整功能用Proteus验证,两个仿真文件都放在Simulation目录下,让别人根据自己的环境选择。
提示:仿真文件里不要包含绝对路径。比如Proteus工程里加载hex文件时,用相对路径而不是“D:\Projects\STM32...”。否则别人下载后路径不对,仿真直接报错。
7. 从这个小项目延伸出去还能做什么
这个最小系统项目虽然简单,但它是一个很好的起点。你可以在这个基础上加各种外设:加一个OLED屏幕做本地显示,加一个ESP8266模块做数据上传,加一个继电器做控制输出,加一个SD卡模块做数据记录。每加一个外设,就多一个驱动层文件,应用层逻辑稍微改一下就行。
如果你想做更复杂的项目,比如基于STM32的毕业设计,这个框架也够用。把应用层换成你的业务逻辑,驱动层加上你需要的传感器和执行器,原理图加上对应的接口电路,仿真验证一下核心逻辑,然后打板焊接调试。整个流程走一遍,你对嵌入式开发的理解会深很多。
我个人在实际操作中的体会是,开源一个项目最大的价值不是代码本身,而是把设计思路和踩坑经验分享出来。代码别人可以自己写,但“为什么选这个方案”、“为什么这个参数要这么设”、“遇到这个问题怎么排查”,这些经验才是真正省时间的东西。所以如果你手头有做过的STM32项目,不妨整理一下开源出来,哪怕只是一个最小系统,对刚入门的人来说也是很有参考价值的。