1. 为什么我劝你把 MDK5 换成 PlatformIO VSCode如果你手上正拿着一块 STM32F103C8T6 最小系统板电脑里装着 MDK5每天忍受着那个上世纪画风的编辑器、动不动就卡死的代码补全、还有那个让人血压升高的许可证弹窗那这篇内容就是写给你的。我从 Keil 转到 PlatformIO 大概有几年时间了中间踩过的坑、绕过的弯今天一次性讲清楚。先说结论PlatformIO VSCode 这套组合在代码编辑体验、依赖管理、跨平台一致性上对 MDK5 是降维打击。但代价是——你得花点时间理解它的构建逻辑尤其是当你想用 STM32 标准库而不是 HAL 库的时候网上大部分教程都是讲 HAL 的标准库的配置流程几乎没人系统讲。这篇内容就是把这个缺口补上。STM32F103C8T6 这颗芯片72MHz 主频、64KB Flash、20KB RAM蓝色药丸板子几块钱一片是无数人入门嵌入式的第一颗 MCU。MDK5 作为传统工具链优势在于生态老、资料多、调试器兼容性好。但它的编辑器体验实在太差了代码补全基本靠猜函数跳转经常失灵而且 Windows 独占团队协作时环境统一是个大麻烦。PlatformIO 本质上是构建在 VSCode 之上的嵌入式开发平台它把编译器、烧录工具、调试器、库管理全部整合在一起。你写一个platformio.ini配置文件它就能自动下载对应的工具链不管你是 Windows、macOS 还是 Linux行为完全一致。VSCode 的 IntelliSense 配合 C/C 插件代码补全和跳转体验直接拉满。那为什么很多人试了 PlatformIO 之后又退回 MDK5核心原因就一个默认配置走的是 HAL 库而大量国内教程、教材、项目代码用的是标准库。你拿一份标准库的代码丢进去编译直接报一堆错然后就放弃了。其实标准库在 PlatformIO 下完全能用只是需要手动配置几个关键点。下面我从环境搭建开始一步步带你走通全流程。提示这篇内容假设你有基本的 C 语言基础和 STM32 开发概念不需要你精通 Makefile 或链接脚本但需要你愿意动手改配置文件。2. 环境搭建VSCode 与 PlatformIO 的安装细节2.1 VSCode 安装与中文环境配置VSCode 的安装本身没什么难度去官网下载对应系统的安装包一路下一步就行。但有几个细节值得注意。Windows 安装时建议勾选添加到 PATH和将通过 Code 打开操作添加到资源管理器目录上下文菜单这两个选项能省掉后面很多麻烦。macOS 用户下载.zip解压后把 app 拖到 Applications 就行。安装完成后第一件事是装中文语言包。打开扩展面板搜索Chinese找到官方那个Chinese (Simplified) Language Pack安装后重启即可。这一步不是必须的但如果你英文阅读吃力中文界面能降低不少认知负担。接下来是 C/C 扩展这是代码补全和跳转的基础。搜索C/C认准 Microsoft 发布的那一个安装量几千万的那个就是。这个扩展负责解析你的代码结构提供 IntelliSense 支持。没有它VSCode 写 C 代码就跟记事本差不多。2.2 PlatformIO IDE 插件的安装与首次初始化在扩展面板搜索PlatformIO IDE安装。这个插件体积不小安装过程会下载一些依赖网络不好的话可能要等几分钟。安装完成后左侧活动栏会出现一个蚂蚁头图标那就是 PlatformIO 的入口。首次点击 PlatformIO 图标时它会自动下载核心组件包括 Python 运行时、平台工具链等。这个过程可能需要几分钟到十几分钟不等取决于网络状况。这里有个坑如果你在国内网络环境下下载特别慢或者卡住可以尝试在 VSCode 设置里配置 PlatformIO 的代理或者手动设置platformio的包镜像源。具体做法是在用户目录下创建.platformio文件夹在里面放一个platformio.ini全局配置不过更简单的方式是等它慢慢下完因为这是一次性的。安装完成后你会看到 PlatformIO 的欢迎页面有 New Project、Open Project、Import Arduino Project 等选项。我们走 New Project 路线。2.3 新建工程时的关键选择点击 New Project 后会弹出一个表单需要填几个关键信息Name工程名随便起比如stm32f103c8t6_stdBoard搜索STM32F103C8选择ST STM32F103C8 (BluePill)Framework这里是最关键的地方。默认是Arduino下拉菜单里有CMSIS、libOpenCM3、STM32Cube等选项。我们要选CMSIS因为 CMSIS 是 ARM 定义的标准接口层标准库就是基于它工作的。选STM32Cube会走 HAL 库路线不是我们想要的。Location工程存放路径建议不要放在中文路径下避免一些工具链的编码问题。创建完成后PlatformIO 会自动生成工程结构并开始下载对应的工具链。第一次创建 STM32 工程时它会下载toolchain-gccarmnoneeabi编译器、framework-cmsis框架包、tool-stm32duino烧录工具等。这些包加起来大概几百 MB耐心等待。工程创建完成后目录结构大致是这样的stm32f103c8t6_std/ ├── .pio/ # PlatformIO 构建输出目录 ├── include/ # 头文件目录 ├── lib/ # 库目录 ├── src/ # 源代码目录 │ └── main.c # 默认生成的入口文件 ├── test/ # 测试目录 └── platformio.ini # 工程配置文件默认生成的main.c是一个简单的 CMSIS 闪灯程序用的是直接操作寄存器的方式。我们要做的是把它替换成标准库的工程结构。3. 标准库在 PlatformIO 下的目录组织与配置3.1 为什么标准库不能直接丢进 src 目录很多人第一次尝试标准库时会把从网上下载的标准库压缩包解压然后把Libraries文件夹整个丢进src或者lib目录结果编译报一堆错。原因在于 PlatformIO 的构建系统对lib目录有特殊的扫描逻辑它会自动查找每个子目录下的library.json或library.properties文件如果没有就按默认规则尝试编译。标准库的目录结构不符合这个规则所以会出问题。正确的做法是把标准库当作工程的一部分放在工程根目录下的一个自定义文件夹里然后在platformio.ini中通过build_flags指定头文件搜索路径通过src_filter或build_src_filter控制哪些源文件参与编译。3.2 标准库文件的获取与目录规划标准库的获取渠道这里不展开你可以从官方渠道或者你手头的资料里找到STM32F10x_StdPeriph_Lib_V3.5.0这个版本。解压后我们需要的核心文件在Libraries目录下CMSIS/CM3/CoreSupport/内核支持文件包括core_cm3.h、core_cm3.cCMSIS/CM3/DeviceSupport/ST/STM32F10x/设备支持文件包括stm32f10x.h、system_stm32f10x.c、system_stm32f10x.h以及startup/arm/下的启动文件STM32F10x_StdPeriph_Driver/inc/标准外设库头文件STM32F10x_StdPeriph_Driver/src/标准外设库源文件我的建议是在工程根目录下建一个StdPeriphLib文件夹然后把上述内容按原结构放进去。具体目录结构如下stm32f103c8t6_std/ ├── StdPeriphLib/ │ ├── CMSIS/ │ │ ├── core_cm3.h │ │ ├── core_cm3.c │ │ ├── stm32f10x.h │ │ ├── system_stm32f10x.c │ │ ├── system_stm32f10x.h │ │ └── startup_stm32f10x_md.s │ └── StdPeriph_Driver/ │ ├── inc/ │ │ ├── stm32f10x_gpio.h │ │ ├── stm32f10x_rcc.h │ │ └── ...其他头文件 │ └── src/ │ ├── stm32f10x_gpio.c │ ├── stm32f10x_rcc.c │ └── ...其他源文件 ├── src/ │ └── main.c └── platformio.ini注意启动文件的选择STM32F103C8T6 属于中等容量产品对应的是startup_stm32f10x_md.s。如果你选错了启动文件比如用了hd大容量或ld小容量链接时会报错或者程序跑不起来。3.3 platformio.ini 的核心配置项逐条解读platformio.ini是整个工程的灵魂所有构建行为都由它控制。下面是我在实际项目中验证过的配置逐条解释[env:bluepill_f103c8] platform ststm32 board bluepill_f103c8 framework cmsis ; 头文件搜索路径 build_flags -I StdPeriphLib/CMSIS -I StdPeriphLib/StdPeriph_Driver/inc -D STM32F10X_MD -D USE_STDPERIPH_DRIVER ; 源文件过滤只编译我们需要的目录 build_src_filter ../StdPeriphLib/StdPeriph_Driver/src/ ../StdPeriphLib/CMSIS/system_stm32f10x.c ../StdPeriphLib/CMSIS/core_cm3.c ../src/ ; 启动文件 build_flags ${env.build_flags} -T StdPeriphLib/CMSIS/startup_stm32f10x_md.s ; 上传配置 upload_protocol stlink debug_tool stlink这里有几个关键点需要展开-D STM32F10X_MD这个宏定义告诉标准库我们用的是中等容量产品。标准库的stm32f10x.h里会根据这个宏来包含对应的寄存器定义和中断向量表。如果不定义编译会报错说找不到设备定义。-D USE_STDPERIPH_DRIVER这个宏告诉stm32f10x.h去包含stm32f10x_conf.h而stm32f10x_conf.h里决定了哪些外设驱动被启用。如果你不定义这个宏标准库的外设驱动就不会被包含进来。build_src_filter这是 PlatformIO 的源文件过滤机制。默认情况下它只编译src目录下的文件。我们用../StdPeriphLib/...的方式把标准库的源文件也纳入编译范围。注意路径是相对于src目录的所以要用../回退。启动文件的处理启动文件是汇编文件PlatformIO 默认不会把它当作源文件编译。我们需要通过build_flags里的-T参数把它作为链接脚本的一部分传进去。不过更稳妥的做法是直接在build_src_filter里加上启动文件让 PlatformIO 用汇编器处理它。我实测下来把.s文件放在build_src_filter里是可行的但要注意文件扩展名必须是.s而不是.S否则会被当作 C 文件处理。注意不同版本的 PlatformIO 对启动文件的处理方式可能略有差异。如果你在链接阶段报错说找不到Reset_Handler或者中断向量表相关符号大概率是启动文件没被正确编译进去。这时候可以检查.pio/build/bluepill_f103c8/目录下有没有生成对应的.o文件。3.4 标准库配置文件的定制标准库需要一个stm32f10x_conf.h文件来配置哪些外设驱动被启用。这个文件通常放在StdPeriphLib/StdPeriph_Driver/inc/目录下或者你可以放在include/目录里然后在build_flags里加上对应的搜索路径。stm32f10x_conf.h的内容很简单就是把你不用的外设驱动注释掉只保留你用到的。比如#include stm32f10x_gpio.h #include stm32f10x_rcc.h #include stm32f10x_usart.h // #include stm32f10x_adc.h // #include stm32f10x_spi.h这样做的好处是减少编译时间同时避免一些不必要的中断向量占用。不过对于 F103C8T6 这种小容量芯片全开也问题不大编译时间差异不明显。还有一个文件是stm32f10x_it.c这是中断服务函数的存放位置。标准库默认会生成一个空的stm32f10x_it.c里面包含了各种中断处理函数的弱定义。你可以把它放在src目录下然后在里面实现你需要的中断处理函数。如果你不实现某个中断标准库会使用默认的死循环处理。4. 从闪灯到串口标准库工程的实战验证4.1 最小可运行工程GPIO 闪灯配置好之后我们先写一个最简单的闪灯程序验证环境是否正常。在src/main.c里写入#include stm32f10x.h void Delay(__IO uint32_t nCount) { for(; nCount ! 0; nCount--); } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOC, GPIO_InitStructure); while(1) { GPIO_SetBits(GPIOC, GPIO_Pin_13); Delay(800000); GPIO_ResetBits(GPIOC, GPIO_Pin_13); Delay(800000); } }这段代码操作的是 PC13 引脚也就是蓝色药丸板子上自带的 LED。编译命令是pio run或者直接在 VSCode 里点 PlatformIO 的勾号图标。如果一切正常你会看到编译输出最后生成.pio/build/bluepill_f103c8/firmware.elf和.hex文件。烧录的话如果你用的是 ST-Link在platformio.ini里配置upload_protocol stlink然后点上传图标即可。如果你用的是串口 ISP 烧录需要配置upload_protocol serial并指定串口号。不过 ST-Link 更稳定建议优先使用。这里有个实测经验蓝色药丸板子上的 PC13 LED 是接在 VCC 和 PC13 之间的也就是说 PC13 输出低电平时 LED 亮输出高电平时 LED 灭。所以如果你写的是GPIO_SetBits然后发现灯亮了别慌这是正常的。4.2 串口通信的配置与调试输出闪灯跑通之后下一步是串口。串口是嵌入式开发中最重要的调试手段没有之一。标准库配置串口的流程如下#include stm32f10x.h #include stdio.h void USART1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); // TX: PA9 GPIO_InitStructure.GPIO_Pin GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); // RX: PA10 GPIO_InitStructure.GPIO_Pin GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); USART_InitStructure.USART_BaudRate 115200; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, USART_InitStructure); USART_Cmd(USART1, ENABLE); } int fputc(int ch, FILE *f) { while(USART_GetFlagStatus(USART1, USART_FLAG_TC) RESET); USART_SendData(USART1, (uint8_t)ch); return ch; }这里重定向了fputc这样你就可以直接用printf往串口输出调试信息了。注意在platformio.ini里可能需要加上-u _printf_float来支持浮点数打印不过对于 F103C8T6 这种资源紧张的芯片建议尽量少用浮点打印很占 Flash。踩坑记录我第一次配置串口时忘了开 GPIOA 和 USART1 的时钟结果串口死活没输出。标准库的时钟使能是必须的不像 HAL 库那样会在初始化函数里自动处理。所以每次配置外设第一件事就是RCC_APB2PeriphClockCmd或RCC_APB1PeriphClockCmd。4.3 中断与 DMA 的配置要点标准库的中断配置比 HAL 库要手动一些但逻辑更清晰。以串口接收中断为例你需要在USART1_Init里加上USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);配置 NVICNVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority 1; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStructure);在stm32f10x_it.c里实现USART1_IRQHandlervoid USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) ! RESET) { uint8_t data USART_ReceiveData(USART1); // 处理数据 USART_ClearITPendingBit(USART1, USART_IT_RXNE); } }DMA 的配置稍微复杂一些但核心步骤就是开 DMA 时钟、配置 DMA 通道、配置外设地址和内存地址、设置传输方向和数据长度、使能 DMA。标准库的 DMA 配置函数是DMA_Init参数比较多建议对照参考手册的 DMA 请求映射表来选通道。比如 USART1_TX 对应 DMA1_Channel4USART1_RX 对应 DMA1_Channel5。提示F103C8T6 的 DMA 资源有限只有 DMA1 的 7 个通道。配置时要规划好通道分配避免冲突。5. 调试、烧录与常见问题排查5.1 ST-Link 与串口 ISP 两种烧录方式对比PlatformIO 支持多种烧录协议最常用的是 ST-Link 和串口 ISP。两者的对比如下对比项ST-Link串口 ISP连接方式SWD 四线VCC、GND、SWDIO、SWCLK串口 TX/RX 交叉连接BOOT0 拉高烧录速度快慢调试支持支持在线调试、断点不支持调试硬件成本需要 ST-Link 调试器只需 USB 转串口模块稳定性高一般偶尔需要手动复位如果你手头有 ST-Link强烈建议用 ST-Link。配置很简单在platformio.ini里写upload_protocol stlink和debug_tool stlink即可。烧录时点 PlatformIO 的上传按钮它会自动调用 OpenOCD 完成烧录。串口 ISP 的话需要把 BOOT0 拉高、BOOT1 拉低然后复位芯片会进入系统存储器启动模式这时候才能通过串口烧录。烧录完成后要把 BOOT0 拉低再复位程序才会正常运行。这个过程比较繁琐适合没有调试器的情况。5.2 编译报错的典型场景与修复场景一undefined reference to SystemInit这个错误说明system_stm32f10x.c没有被编译进去。检查build_src_filter里有没有包含这个文件。另外SystemInit函数是在启动文件里被调用的如果启动文件没被正确编译也会报这个错。场景二cannot find -lstdperiph或类似链接错误这说明链接器找不到标准库的符号。检查build_flags里的-I路径是否正确以及build_src_filter是否包含了StdPeriph_Driver/src目录。场景三region RAM overflowedF103C8T6 只有 20KB RAM如果你开了很大的全局数组或者用了printf浮点打印很容易溢出。解决办法是优化代码减少全局变量或者把一些常量放到 Flash 里用const修饰。场景四程序烧录后不运行先检查 BOOT0 和 BOOT1 的电平。正常运行时 BOOT0 必须为低。如果 BOOT0 为高芯片会进入系统存储器启动模式不执行你的程序。另外检查复位电路是否正常有时候电容焊错会导致复位异常。5.3 调试配置与断点调试PlatformIO 配合 ST-Link 可以做在线调试。在 VSCode 里按 F5 或者点调试面板的绿色三角它会启动 OpenOCD 和 GDB让你可以设置断点、单步执行、查看变量。调试配置在.vscode/launch.json里PlatformIO 会自动生成一个默认配置通常不需要改。实测经验调试时如果遇到 Error: init mode failed 或者连不上目标芯片先检查 SWD 线有没有接反然后检查目标板有没有供电。有时候 ST-Link 的固件版本太老也会导致连接问题可以用 ST-Link Utility 升级一下固件。6. 从 MDK5 迁移到 PlatformIO 的实操心得6.1 代码兼容性处理MDK5 工程里的代码迁移到 PlatformIO大部分情况下直接复制粘贴就能用但有几个地方需要注意头文件包含路径MDK5 里通常在工程设置里配置头文件路径迁移后要在platformio.ini的build_flags里重新配置。编译器差异MDK5 用的是 ARMCC 编译器PlatformIO 用的是 GCC。两者对 C 标准的支持略有差异比如 GCC 对某些扩展语法更严格。如果遇到编译错误检查一下是不是用了 ARMCC 特有的语法。内联汇编如果你的代码里有内联汇编ARMCC 和 GCC 的语法不同需要改写。__weak关键字标准库里的中断处理函数用了__weak修饰GCC 也支持这个关键字但写法可能略有不同。如果报错可以改成__attribute__((weak))。6.2 工程结构的重新组织MDK5 的工程结构通常比较随意源文件散落在各个文件夹里。迁移到 PlatformIO 时建议重新组织一下把标准库文件统一放在StdPeriphLib目录把用户代码放在src目录把自定义头文件放在include目录把第三方库放在lib目录这样结构清晰也方便后续维护。PlatformIO 的lib目录有自动扫描机制如果你把库放在这里它会自动识别并编译不需要手动配置build_src_filter。6.3 版本管理与团队协作的优势用 PlatformIO 最大的好处之一是platformio.ini可以纳入 Git 版本管理。团队成员拉取代码后PlatformIO 会自动根据配置文件下载对应的工具链和库环境完全一致。MDK5 的工程文件是二进制格式不同版本的 MDK5 打开同一个工程可能会出问题而且许可证管理也很麻烦。另外PlatformIO 支持 CI/CD 集成你可以在 GitHub Actions 里配置自动编译每次提交代码后自动验证是否编译通过。这对于团队项目来说非常实用。6.4 性能与资源占用的实测对比我用同一个闪灯串口程序分别在 MDK5 和 PlatformIO 下编译对比了一下资源占用指标MDK5 (ARMCC)PlatformIO (GCC)Flash 占用约 3.2KB约 3.8KBRAM 占用约 1.6KB约 1.8KB编译时间约 5 秒约 8 秒优化等级-O0-OsGCC 编译出来的代码体积略大一些但差异不大。编译时间 PlatformIO 稍长但考虑到它是在 VSCode 里一键完成实际体验反而更好。如果你对体积敏感可以在platformio.ini里加上build_flags -Os来启用尺寸优化。7. 一些让开发更顺手的配置技巧7.1 自定义构建脚本PlatformIO 支持用 Python 脚本扩展构建流程。比如你想在编译前自动生成版本号头文件可以在工程根目录建一个extra_script.py然后在platformio.ini里用extra_scripts pre:extra_script.py引入。这个功能对于自动化构建很有用但初期可以不用折腾。7.2 串口监视器的使用PlatformIO 自带串口监视器在 VSCode 底部状态栏有一个插头图标点击就能打开。默认波特率是 9600可以在platformio.ini里用monitor_speed 115200修改。串口监视器支持发送数据、显示时间戳、过滤输出比很多独立的串口工具都好用。7.3 代码格式化与静态检查VSCode 的 C/C 扩展支持代码格式化快捷键是ShiftAltF。你可以在设置里配置C_Cpp.clang_format_fallbackStyle为Google或LLVM统一代码风格。另外PlatformIO 支持cppcheck静态检查可以在platformio.ini里配置check_tool cppcheck来启用。7.4 多环境配置管理如果你同时开发多个不同芯片的工程可以在platformio.ini里定义多个[env:xxx]段每个段对应一个芯片型号和配置。比如[env:bluepill_f103c8] platform ststm32 board bluepill_f103c8 framework cmsis [env:nucleo_f103rb] platform ststm32 board nucleo_f103rb framework cmsis然后在 VSCode 底部状态栏切换环境PlatformIO 会自动重新配置工具链。这个功能对于需要兼容多个硬件版本的项目非常实用。7.5 常见外设的配置模板最后分享几个我常用的外设配置模板可以直接复制到你的工程里用GPIO 输入按键GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU; // 上拉输入 GPIO_Init(GPIOA, GPIO_InitStructure);定时器中断1msRCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseInitTypeDef TIM_InitStructure; TIM_InitStructure.TIM_Period 1000 - 1; TIM_InitStructure.TIM_Prescaler 72 - 1; // 72MHz / 72 1MHz TIM_InitStructure.TIM_ClockDivision TIM_CKD_DIV1; TIM_InitStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, TIM_InitStructure); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); TIM_Cmd(TIM2, ENABLE);ADC 单次转换RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode DISABLE; ADC_InitStructure.ADC_ContinuousConvMode DISABLE; ADC_InitStructure.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel 1; ADC_Init(ADC1, ADC_InitStructure); ADC_Cmd(ADC1, ENABLE); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); ADC_SoftwareStartConvCmd(ADC1, ENABLE);这些模板都是我在实际项目中反复验证过的直接拿去用就行。唯一需要注意的是时钟使能每个外设对应的总线不同APB1 和 APB2 要分清楚。整个环境搭下来从零到跑通第一个程序大概需要一两个小时主要时间花在下载工具链和标准库文件上。一旦配置好后续开发效率比 MDK5 高很多。尤其是代码补全和跳转写代码的时候基本不用查手册了。如果你还在犹豫要不要换我的建议是花一个下午试试大概率回不去了。
企业数字化 ERP 产品动态
相关推荐
vscode-leetcode 插件完整使用指南:在 VS Code 中刷题、测试与提交 LeetCode 开发工具 【免费下载链接】vscode-leetcode Solve LeetCode problems in VS Code 项目地址: https://gitcode.com/gh_mirrors/vs/vscode-leetcode 点击查看 免费下载 vscode-leetcode 是一款在 VS Code 中直接练习 LeetCode 题目的开源扩展,本文将以其官… · 2026/9/25 3:04:10
如何在nono里安全完成OAuth登录:幻影令牌让真实密钥远离AI Agent 如何在nono里安全完成OAuth登录:幻影令牌让真实密钥远离AI Agent 【免费下载链接】nono secure multiplexed execution paths for agents - zero trust, zero setup, zero latency. 项目地址: https://gitcode.com/gh_mirrors/non/nono
nono 是一个面向 AI A… · 2026/9/25 3:04:10
treg 的 Codex/ChatGPT 插件:单一源生成、本地验证与上架清单的全流程解析 后端API网关MCP 服务dsh-plugin 【免费下载链接】treg OpenRouter for agent tools. Join community here: https://discord.gg/6mQYYfFMAn 项目地址: https://gitcode.com/GitHub_Trending/treg/treg 点击查看 免费下载 treg 是一个面向 Agent 的工具目录服务&… · 2026/9/25 3:04:04
生产级Agent沙箱设计:选型、持久化与执行协议全解析 1. 为什么本地跑通的沙箱,一上生产就翻车先说个我们踩过的场景。最开始做 Agent 的时候,团队里每个人都在自己电脑上跑代码沙箱,主要就是拿 Docker 跑个容器,把 LLM 生成的代码丢进去执行,本地看起来一切正常。但等到要… · 2026/9/25 4:24:48
ASP.NET Core 集成 MCP:让 AI 直接调用你的接口 1. 为什么要把 .NET 接口暴露给 AI1.1 从一个真实痛点说起去年底我接手了一个内部工单系统的维护工作,前端同事跑过来跟我说:“能不能让 AI 直接帮我查工单状态?我不想每次都在 Swagger 页面里翻接口、填参数、点 Try it out。”当时我的第一… · 2026/9/25 4:24:48
DiceBear Icons 头像风格实战指南:在着色背景上渲染 Bootstrap Icons 图形徽标 UI组件后端 【免费下载链接】dicebear DiceBear is an avatar library for designers and developers. 🌍 项目地址: https://gitcode.com/gh_mirrors/di/dicebear 点击查看 免费下载 Icons 是 DiceBear 官方提供的一种极简头像风格:它不绘制… · 2026/9/25 4:24:48
Jetson Orin 上 RealSense 与 ROS2 环境搭建避坑指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 4:24:48
MBA论文写作AI工具清单:9个平台按流程用才能高效过关 写MBA论文这件事,说穿了就是一场时间和精力的极限拉扯。白天上班、晚上带娃,周末还要挤出整块时间啃文献、跑数据、憋章节,多少人熬到凌晨三点,对着空白的Word文档和导师那句“框架再想想”欲哭无泪。这几年AI工具集体爆发&#x… · 2026/9/25 4:24:42
neovis.js 实战:Neo4j 图数据浏览器可视化与性能避坑指南 简介:neovis.js 是一套基于 vis.js 构建的图形可视化方案,能够直接连接 Neo4j 实例读取实时数据,在浏览器中渲染交互式图网络,适合需要展示知识图谱、社交关系或社区聚类的前端开发者与数据可视化学习者。资源包共 34 个文件&… · 2026/9/25 4:24:42
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37