STM32C5开发实战:从工具链搭建到TrustZone安全配置全指南
发布时间:2026/10/18 11:24:56 锦皓数字建站

1. 为什么现在值得重新审视STM32C5的软件开发STM32C5这个系列最近在圈子里讨论度明显上来了不少做工业控制和消费电子的朋友都在问同一个问题这颗芯片到底该怎么上手开发流程跟以前用的F1、F4系列有什么不一样。我自己前前后后搭过三套基于C5的开发环境踩了不少坑也总结了一些能直接抄作业的配置方法今天就把这些经验完整地摊开来讲。先说清楚这个系列的基本定位。STM32C5属于主流级MCU产品线核心架构基于Arm Cortex-M33带TrustZone安全扩展主频和存储配置比传统的F1系列高出一截同时功耗控制又比L4系列更激进。它瞄准的是那些既要一定算力、又要安全隔离、还得控制成本的应用场景比如智能门锁的主控、工业传感器的边缘节点、消费类电器的触控面板等等。如果你之前一直在用F103或者F407做项目现在想迁移到C5平台或者你是个刚接触STM32的新手想直接从较新的系列入门这篇内容都能给你一条清晰的路径。我写这篇东西的出发点很简单网上关于C5的中文资料还比较零散官方文档虽然全面但读起来费劲很多细节需要自己反复试错才能搞明白。所以我会按照实际开发的顺序从工具链选型、工程创建、时钟配置、外设驱动、低功耗调试到安全特性启用一步步把关键节点讲透。每个环节我都会解释为什么这么做以及不这么做会出什么问题。文章里涉及的代码和配置都经过实际验证你可以直接拿去用也可以根据自己的项目需求做调整。2. 开发环境搭建与工具链选型2.1 主流工具链的对比与选择逻辑搞STM32开发第一步永远是选工具链。目前市面上能支持C5系列的方案主要有三类ST官方的STM32CubeIDE、Keil MDK配合ST的器件支持包、以及基于GCC的开源方案比如STM32CubeCLT加VSCode。这三种方案我都实际用过各有各的适用场景没有绝对的好坏关键看你的项目需求和团队习惯。STM32CubeIDE是ST自家推出的免费集成开发环境基于Eclipse框架集成了CubeMX配置工具、编译器和调试器。它的最大优势是跟ST的生态无缝衔接新建工程时可以直接从芯片选型开始自动生成初始化代码外设配置图形化操作对新手极其友好。缺点是Eclipse底子导致界面响应偏慢代码补全和索引速度不如专业的商业IDE大型工程编译时间也比较长。我实测下来一个中等规模的C5工程全量编译大概在40秒到1分钟之间增量编译倒是很快。Keil MDK是很多老工程师的习惯选择编译器优化做得好生成的代码体积小、执行效率高调试功能也很成熟。但Keil是商业软件需要购买License而且对C5系列的支持需要单独安装器件包。另外Keil的编辑器功能相对基础代码导航和重构能力比不上VSCode。如果你所在的公司已经有Keil的授权而且团队都熟悉这套工具继续用Keil没问题。但如果是个人学习或者新项目起步我建议优先考虑CubeIDE或者VSCode方案。VSCode加STM32CubeCLT的组合是最近两年越来越流行的方案。CubeCLT是ST提供的命令行工具集包含GCC编译器、CMake构建系统和调试工具可以在VSCode里通过插件调用。这套方案的优势是编辑器体验极佳插件生态丰富配合CMake可以做出非常灵活的构建配置。缺点是需要自己搭建工程结构对新手来说门槛稍高而且调试配置需要手动写launch.json文件。不过一旦搭好开发效率是最高的。我现在的个人项目基本都用这套方案下面也会重点讲怎么配置。2.2 CubeIDE的安装与C5支持包配置如果你决定用CubeIDE安装过程本身不复杂但有几个细节需要注意。首先去ST官网下载最新版本的STM32CubeIDE建议选1.16以上的版本对C5系列的支持更完善。安装时它会让你选择安装路径尽量避开中文路径和带空格的目录否则后面编译时可能出一些莫名其妙的错误。安装完成后第一次启动会提示你选择工作空间同样建议用纯英文路径。接下来是关键一步安装C5系列的器件支持包。CubeIDE启动后点击Help菜单里的Manage Embedded Software Packages在弹出的窗口里找到STM32C5系列勾选最新的固件包版本点击Install。这个过程需要联网下载根据网速不同大概需要几分钟到十几分钟。安装完成后新建工程时就能在芯片选型列表里看到C5的各个型号了。这里有个坑要提醒有些朋友安装完器件包后新建工程发现生成的代码里头文件路径报错编译通不过。这通常是因为器件包安装不完整或者CubeIDE的索引没有刷新。解决办法是右键点击工程选择Index下的Rebuild然后Project菜单里Clean一下再Build。如果还不行删掉工程重新建一次新建时注意在Project Manager里把“Copy only necessary library files”勾上这样会把用到的库文件复制到工程目录下避免路径引用问题。2.3 VSCode加CubeCLT的完整配置流程这套方案稍微复杂一点但值得花时间搭好。首先去ST官网下载STM32CubeCLT的安装包安装到默认路径就行。然后安装VSCode在扩展市场里搜索并安装以下几个插件STM32 VS Code ExtensionST官方出的、Cortex-Debug用于调试、CMake Tools用于构建管理。安装完插件后打开VSCode的设置搜索STM32CubeCLT把CLT的安装路径填进去。然后新建一个文件夹作为工程目录在VSCode里打开这个文件夹。按F1调出命令面板输入STM32Cube: Create New Project按照提示选择C5系列的具体型号配置外设和时钟树工具会生成完整的工程结构包括CMakeLists.txt、链接脚本和初始化代码。生成的工程默认使用CMake构建你可以在VSCode底部的状态栏看到构建按钮。点击构建后CMake会调用CubeCLT里的GCC编译器生成elf文件。调试配置需要手动创建.vscode/launch.json文件指定调试器类型为ST-Link或者J-Link以及elf文件的路径。具体配置内容可以参考ST官方提供的模板把路径改成你自己的工程路径即可。注意使用VSCode方案时CubeMX生成的代码和用户代码是分开的用户代码要写在/* USER CODE BEGIN/和/USER CODE END */之间否则重新生成代码时会被覆盖。这个规则在CubeIDE里也一样养成好习惯能省很多事。3. 新建工程与时钟系统配置要点3.1 从芯片选型到工程骨架生成新建工程的第一步是选对芯片型号。C5系列下面有多个具体型号区别主要在Flash和RAM大小、封装形式、外设数量上。选型时不要只看价格要预留至少30%的Flash和RAM余量因为后期加功能、加协议栈、加日志输出都会吃掉不少空间。我一般建议Flash至少选256KB起步RAM至少64KB这样跑个RTOS加几个外设驱动不会太紧张。在CubeMX的Pinout视图里你会看到芯片的引脚分布图。配置外设时先点开System Core里的RCC把高速外部时钟源设为Crystal/Ceramic Resonator这样后面时钟树才能用外部晶振。然后配置SYS里的Debug为Serial Wire否则下载一次程序后SWD接口可能被禁用导致下次连不上。这个坑我踩过不止一次新手特别容易忽略。时钟树的配置是C5开发里比较关键的一环。C5的最高主频根据具体型号不同一般在144MHz到250MHz之间。配置时先确定外部晶振的频率常见的是8MHz或者25MHz。然后在时钟树里设置PLL的倍频和分频参数让系统时钟达到目标频率。CubeMX会自动计算各个总线的分频系数你只需要关注最终的系统时钟、AHB、APB1、APB2频率是否在允许范围内。APB1和APB2的频率不能超过数据手册规定的上限否则外设工作会不稳定。3.2 时钟树参数计算与验证方法举个例子假设你用8MHz的外部晶振目标系统时钟设为200MHz。PLL的配置可以是输入分频M设为2得到4MHz的参考频率倍频N设为100得到400MHz的VCO输出输出分频P设为2得到200MHz的系统时钟。同时VCO输入频率要在1MHz到16MHz之间VCO输出频率要在192MHz到836MHz之间这些约束条件CubeMX都会自动检查如果参数不合法会标红提示。配置完成后不要急着生成代码先点开Clock Configuration界面下方的“Show actual frequencies”按钮确认每个节点的实际频率都符合预期。特别要检查Flash等待周期Latency的设置主频越高Flash读取需要的等待周期越多。C5系列在200MHz主频下通常需要4到5个等待周期这个值CubeMX会根据主频自动计算但你要确认它跟参考手册里的表格一致。生成代码之前在Project Manager里把Toolchain/IDE设为你用的工具链比如STM32CubeIDE或者Makefile。Code Generator里勾选“Generate peripheral initialization as a pair of .c/.h files”这样每个外设的初始化代码会单独成文件工程结构更清晰。最后点Generate CodeCubeMX会生成完整的工程骨架。3.3 启动文件与链接脚本的关键修改生成的工程里有两个文件值得特别关注启动文件startup_stm32c5xxxx.s和链接脚本.ld文件。启动文件里定义了中断向量表和复位处理流程一般不需要改动但如果你要启用TrustZone安全特性需要在启动时配置安全属性这部分后面会单独讲。链接脚本定义了Flash和RAM的地址范围以及各个段的分配如果你用了Bootloader或者需要把某些数据放到特定区域就需要修改这个文件。我遇到过一个问题工程编译后提示RAM溢出但实际用的变量并不多。排查后发现是栈stack的大小设置得太小而某个函数里定义了一个大数组导致栈溢出。解决办法是在启动文件里找到Stack_Size的定义把它从默认的0x400改大到0x800或者0x1000。堆Heap的大小也要根据是否使用动态内存分配来调整如果用malloc/freeHeap_Size至少设0x200。实操心得每次修改时钟配置或者链接脚本后建议先编译一个最简单的点灯程序验证系统能正常运行再逐步添加外设驱动。这样一旦出问题排查范围小容易定位。4. 外设驱动开发与代码组织4.1 GPIO与中断控制器的配置方法GPIO是所有外设里最简单但也最常用的一个。C5的GPIO配置跟其他STM32系列大同小异每个引脚可以独立设置为输入、输出、复用功能或模拟模式。输出模式要选择推挽还是开漏推挽适合驱动LED和数字信号开漏适合I2C总线和需要外部上拉的场景。输出速度也要根据实际信号频率选择低速信号用Low档可以降低EMI高速信号比如SPI的时钟线要用High档。中断配置是GPIO里的重点。C5的EXTI中断线跟引脚号的对应关系是固定的比如PA0、PB0、PC0共用EXTI0线同一时刻只能有一个引脚触发该中断。配置时在CubeMX的GPIO选项卡里把引脚设为GPIO_EXTI模式然后在NVIC选项卡里使能对应的中断通道设置优先级。优先级分组建议用NVIC_PRIORITYGROUP_4这样每个中断都有独立的抢占优先级和子优先级调度更灵活。中断服务函数要写在stm32c5xx_it.c文件里函数名必须跟启动文件里的向量表一致。中断里尽量只做标志位设置和简单的状态切换耗时的处理放到主循环里做。如果非要在中断里做复杂操作注意控制执行时间避免影响其他中断的响应。我一般会在中断里翻转一个GPIO来测量中断响应时间用示波器看波形确保在微秒级别。4.2 串口通信的DMA收发实现串口是调试和通信最常用的外设。C5的USART支持最高十几兆的波特率实际用的时候115200或者921600就够大部分场景了。配置时选异步模式设置波特率、数据位、停止位和校验位。如果要使用DMA收发在DMA Settings选项卡里添加对应的请求模式选Normal或者Circular。Circular模式适合连续接收不定长数据的场景Normal模式适合定长收发。DMA接收不定长数据的经典做法是用空闲中断IDLE配合DMA。具体流程是启动DMA接收设置接收缓冲区使能USART的IDLE中断当一帧数据接收完毕总线空闲时触发IDLE中断在中断里计算接收到的数据长度处理数据然后重新启动DMA接收。这个方案的好处是不需要预先知道数据长度也不占用CPU轮询。代码实现上在USART的中断服务函数里判断IDLE标志位清除标志后调用HAL_UART_DMAStop用缓冲区总大小减去DMA剩余传输数量得到实际接收长度。发送方面如果数据量不大直接用HAL_UART_Transmit阻塞发送就行。数据量大或者发送频率高的话用DMA发送可以解放CPU。注意DMA发送完成中断里要清除标志并做好状态管理避免连续发送时数据被覆盖。我通常会在发送函数里加一个忙状态判断如果上一次DMA发送还没完成就把新数据放入队列等待或者直接返回错误码让上层处理。4.3 定时器与PWM输出的精度控制C5的定时器资源很丰富有基本定时器、通用定时器和高级定时器。基本定时器只能计数和触发中断通用定时器支持输入捕获、输出比较和PWM高级定时器还支持互补输出和死区插入适合电机控制。配置定时器时先确定时钟源频率然后根据需要的定时周期计算预分频器PSC和自动重载值ARR。公式是定时周期 (PSC1) * (ARR1) / 定时器时钟频率。PWM输出的配置稍微复杂一点。以通用定时器为例选择一个通道设为PWM Generation模式设置Pulse值决定占空比Pulse值除以ARR值就是占空比。频率由ARR和PSC共同决定。如果要输出互补PWM需要用高级定时器在通道配置里使能互补输出设置死区时间。死区时间的计算要根据驱动器的开关特性来定一般设几百纳秒到几微秒。死区时间寄存器BDTR的值跟定时器时钟频率有关具体公式参考参考手册。注意修改定时器的PSC和ARR值会影响PWM频率和占空比如果运行中需要动态调整建议先停止定时器改完寄存器再重新启动避免出现异常脉冲。另外高级定时器的刹车功能Break要配置好否则电机控制时可能出现意外。5. 低功耗设计与安全特性启用5.1 低功耗模式的进入与唤醒策略C5系列在低功耗方面做了不少优化支持Sleep、Stop和Standby三种主要模式。Sleep模式只关闭CPU时钟外设继续运行唤醒最快适合短时间空闲。Stop模式关闭大部分时钟保留RAM和寄存器内容唤醒后继续执行功耗在微安级别。Standby模式关闭所有电源域只保留备份域唤醒相当于复位功耗最低适合长时间待机。进入低功耗模式前要做好几件事把不用的外设时钟关掉把GPIO设为模拟输入或者根据外部电路设为合适的状态避免悬空引脚漏电。如果用Stop模式要配置好唤醒源比如EXTI中断、RTC闹钟或者串口唤醒。唤醒源的配置在CubeMX的对应外设里设置比如RTC的WakeUp功能或者GPIO的EXTI中断。进入Stop模式的函数是HAL_PWR_EnterSTOPMode参数选择调节器状态和唤醒后的时钟源。实测下来C5在Stop模式下的功耗可以做到几微安具体数值跟供电电压、温度、保留的外设有关。测量功耗时要注意调试器连接着的时候功耗会偏高因为调试接口在耗电。正确的做法是拔掉调试器用独立的电源供电在电源线上串一个电流表测量。另外如果用了外部晶振Stop模式下晶振会停振唤醒后需要重新配置时钟HAL库提供了相应的处理函数但要注意唤醒后的时钟切换时间。5.2 TrustZone安全隔离的配置入门TrustZone是C5系列的一个重要特性它把芯片的资源划分为安全世界和非安全世界两个世界之间通过特定的接口通信。对于需要保护密钥、固件或者敏感数据的应用TrustZone可以提供硬件级别的隔离。配置TrustZone的第一步是在CubeMX里使能TrustZone然后划分安全属性和非安全属性的外设及内存区域。具体操作上在CubeMX的Security选项卡里你可以为每个外设和每块内存区域指定安全属性。比如把Flash的前128KB设为安全区存放安全固件和密钥把SRAM的前32KB设为安全区存放安全数据。非安全区的代码不能直接访问安全区的资源必须通过安全网关SAU或者安全服务调用来请求。SAU的配置在CubeMX里图形化完成生成代码时会自动生成SAU的初始化函数。安全和非安全世界之间的函数调用需要通过特定的跳转表实现。ST提供了相应的模板你需要在安全工程里定义安全服务函数在非安全工程里通过 veneer 函数调用。这个过程涉及两个工程的编译和链接配置起来比较繁琐建议先用ST的示例工程跑通流程再根据自己的需求修改。如果项目对安全要求不高可以先不启用TrustZone等需要的时候再开启。5.3 调试接口保护与固件升级考虑产品量产时调试接口的保护很重要。C5提供了多种保护级别可以通过选项字节Option Bytes配置。最基本的保护是禁用调试接口这样外部无法通过SWD读取Flash内容。更高级的保护包括读保护和写保护读保护开启后即使通过调试接口也无法读出Flash里的代码。写保护可以防止意外擦除或者篡改特定区域。配置选项字节可以通过STM32CubeProgrammer工具在图形界面里勾选相应的保护选项然后点击应用。注意开启读保护后如果要重新烧录程序需要先解除保护而解除保护会自动擦除整个Flash。所以量产前一定要确认代码已经最终版本并且做好备份。另外如果启用了TrustZone安全区的选项字节配置和非安全区是分开的要分别设置。固件升级方面C5支持通过Bootloader进行串口、CAN、USB等接口的升级。ST提供了系统Bootloader可以通过BOOT0引脚进入。如果要做自定义的OTA升级需要自己写Bootloader程序划分Flash区域实现固件接收、校验和跳转逻辑。这部分内容比较多建议参考ST的IAP示例结合自己的通信协议来实现。6. 常见问题排查与实战避坑指南6.1 编译链接错误的快速定位编译链接阶段最常见的问题是头文件找不到、符号未定义和内存溢出。头文件找不到通常是路径配置问题检查CubeMX生成的工程里Include路径是否包含了所有必要的目录。如果用了自定义的库手动添加路径到CMakeLists.txt或者IDE的工程设置里。符号未定义一般是函数声明了但没实现或者库文件没链接进来。检查对应的.c文件是否加入了编译以及链接脚本里是否包含了需要的库。内存溢出分两种情况Flash溢出和RAM溢出。Flash溢出会提示regionFLASH overflowed解决办法是优化代码体积比如降低编译器优化等级、去掉不用的功能模块、使用更小的库。RAM溢出提示regionRAM overflowed除了优化变量使用外还可以调整栈和堆的大小或者把大数组放到外部RAM如果芯片支持。我遇到过一次RAM溢出是因为在函数里定义了一个2KB的局部数组改成静态或者全局后就解决了。还有一种比较隐蔽的问题是链接脚本里的段分配不合理导致某些数据被放到了错误的地址。比如中断向量表必须放在Flash的起始地址如果链接脚本里把其他段放在了前面向量表就会被覆盖程序跑不起来。检查生成的map文件确认各个段的起始地址和大小符合预期。6.2 程序跑飞与硬件异常的排查思路程序跑飞是嵌入式开发里最头疼的问题之一。表现可能是死机、复位、或者进入HardFault中断。排查HardFault的第一步是找到出错时的现场信息。在HardFault_Handler里加一段代码把栈里的寄存器值打印出来或者用调试器查看LR、PC寄存器的值定位到出错的指令地址。然后结合反汇编和map文件找到对应的函数和代码行。常见的原因包括数组越界访问、空指针解引用、栈溢出、中断优先级配置错误导致的中断嵌套异常。数组越界在C语言里不会报错但会破坏相邻内存的数据症状可能延迟出现很难定位。建议在开发阶段开启编译器的边界检查选项或者用静态分析工具扫描代码。栈溢出可以通过在栈顶和栈底填充特定模式运行一段时间后检查这些模式是否被改写来判断。硬件异常方面电源不稳、晶振不起振、复位电路设计不当都会导致程序运行异常。用示波器测量电源纹波和晶振波形确认在允许范围内。复位引脚的电容和电阻值要按参考设计选取太小会导致复位不可靠太大影响复位速度。如果用了外部看门狗喂狗时间要留足余量避免正常运行时被误复位。6.3 外设不工作的检查清单外设不工作的时候按照以下顺序排查通常能快速定位问题。先确认时钟是否使能C5的外设时钟默认是关闭的CubeMX里配置了外设后会自动使能对应的时钟但手动写代码时容易忘记。然后检查引脚复用配置是否正确每个外设的引脚都有特定的复用功能编号AF配错了信号就出不来。用CubeMX配置的话一般不会错手动配置时要查数据手册的复用功能表。接着检查外设的初始化参数比如串口的波特率、数据位、停止位是否和对方一致SPI的时钟极性、相位是否匹配I2C的地址是否正确。这些参数不匹配会导致通信失败或者数据错乱。最后检查中断是否使能NVIC里的中断通道有没有打开优先级设置是否合理。如果用了DMA还要确认DMA通道和外设的请求映射是否正确DMA的传输方向和数据宽度是否匹配。下面这张表整理了我遇到过的典型问题和解决方法可以当作速查表用现象可能原因排查方法程序下载后不运行BOOT引脚状态错误检查BOOT0和BOOT1电平串口无输出引脚复用未配置确认TX/RX的AF编号中断不触发NVIC未使能检查中断通道和优先级PWM无输出定时器未启动确认HAL_TIM_PWM_Start调用DMA传输不完成通道映射错误核对DMA请求映射表低功耗唤醒失败唤醒源未配置检查EXTI和RTC配置程序频繁复位看门狗超时调整喂狗周期或禁用Flash写入失败未解锁或未擦除检查FLASH解锁和擦除流程避坑技巧每次调试新外设时先用最简单的轮询方式验证功能正常再改成中断或DMA方式。这样能把问题范围缩小到外设配置本身而不是中断或DMA的配置问题。另外善用ST-Link的调试功能在关键代码处设断点查看寄存器的实际值比盲目猜测高效得多。7. 工程模板化与后续扩展方向7.1 建立可复用的工程模板做过几个C5项目之后你会发现很多配置是重复的时钟树、调试串口、GPIO初始化、SysTick配置等等。把这些通用部分抽出来做成工程模板新项目直接复制模板改外设配置能省不少时间。我的做法是建一个基础工程包含最简系统时钟、一个调试串口、一个LED和一个按键的驱动以及一个简单的任务调度框架。新项目从这个模板开始只添加项目特有的外设和逻辑。模板工程里要注意把用户代码和CubeMX生成的代码严格分开所有自定义代码都写在USER CODE区域内。这样重新生成代码时不会丢失。另外把常用的工具函数也放进模板比如延时函数、软件定时器、环形缓冲区、简单的日志输出等。这些工具函数经过多个项目验证后稳定性和可靠性都有保障。版本管理方面建议用Git管理模板工程每次CubeMX重新生成代码后提交一次方便对比变化。如果团队协作可以把模板放在内部代码仓库里大家共享。模板的更新要谨慎改动核心配置后要在新项目里充分测试避免引入隐藏问题。7.2 从裸机到RTOS的平滑过渡裸机开发适合逻辑简单的项目但功能一多任务调度和实时性就不好保证。这时候可以考虑上RTOS比如FreeRTOS或者RT-Thread。C5的性能跑RTOS绰绰有余CubeMX里也集成了FreeRTOS的配置选项勾选后会自动生成任务创建和调度的代码。从裸机迁移到RTOS主要改动是把原来的主循环逻辑拆分成多个任务每个任务负责一个功能模块。任务之间通过队列、信号量或者事件组通信。中断服务函数里尽量只做通知具体处理放到任务里做。共享资源的访问要加互斥保护避免竞态条件。栈大小的分配要根据任务的实际需求来定太小会溢出太大浪费RAM。我一般先给每个任务分配512字节到1KB的栈运行一段时间后通过FreeRTOS的栈使用统计功能查看实际用量再调整。RTOS的引入会增加系统的复杂性调试难度也上升。建议先用裸机把各个外设驱动调通再逐步迁移到RTOS。迁移过程中保持功能不变每迁移一个模块就测试一次确保没有引入新问题。7.3 后续可以深入的技术方向C5平台还有很多可以深挖的方向。比如利用TrustZone做安全启动和固件签名验证提升产品的安全性。再比如用C5的硬件加密引擎AES、SHA、PKA实现加密通信和数据保护减少软件加密的CPU开销。还有C5的低功耗特性配合能量采集技术可以做一些无电池或者电池寿命极长的应用。通信协议方面C5支持CAN-FD、USB、以太网等接口可以做工业网关或者物联网节点。结合无线模块可以实现远程监控和数据采集。如果项目涉及电机控制C5的高级定时器和快速ADC采样能力可以做出性能不错的FOC驱动器。这些方向每一个都值得单独写一篇深入的文章后面有机会再展开。我个人在实际操作中的体会是C5这个平台的学习曲线比F1系列陡一些主要是TrustZone和低功耗部分的概念比较多但一旦理解了基本框架后面的开发效率会很高。建议新手先从简单的GPIO和串口入手把工具链和调试流程跑顺再逐步挑战复杂特性。遇到问题多查参考手册和官方示例少走弯路。最后再分享一个小技巧ST的官方例程在CubeIDE里可以直接通过File菜单的Import导入每个外设都有对应的示例工程是学习配置的最好参考。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。