ARTICLE DETAIL

资讯详情

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

STM32 实验任务 2:标准外设库流水灯 + Keil 逻辑分析仪测波形

STM32 实验任务 2:标准外设库流水灯 + Keil 逻辑分析仪测波形 STM32 实验任务 2标准外设库流水灯 Keil 逻辑分析仪测波形任务要求在实验 1寄存器方式流水灯的基础上改用STM32 标准外设库方式使用 GPIOx 端口控制几个 LED 轮流闪烁间隔 1 秒。要求写出工程项目创建、添加标准外设库文件.c/.h的详细过程用 Keil 软件仿真逻辑分析仪观察 GPIO 输出波形分析时序是否正确、LED 闪烁周期实际为多少。问 1标准外设库工程怎么建1.1 准备工作下载标准外设库STM32F1 的标准外设库STM32F10x_StdPeriph_Driver从官方渠道下载后解压里面Libraries目录有两大块CMSIS芯片内核相关core、设备头文件 stm32f10x.h、启动文件STM32F10x_StdPeriph_Driver外设驱动gpio、rcc、flash、usart 等每个外设一个 .c .h注意本项目只用到了 GPIO、RCC、FLASH 三个外设所以只把这三个驱动文件复制进工程其他外设不添加工程更干净。1.2 创建工程文件夹我在D:\Project\STM32Project\下创建工程目录stm32-led-stdlib/ ├── main.c ← 用户主程序 ├── stm32f10x\_conf.h ← 外设配置头文件声明启用哪些外设 └── StdPeriph/ ← 标准外设库驱动文件 ├── stm32f10x\_gpio.c / .h ├── stm32f10x\_rcc.c / .h └── stm32f10x\_flash.c / .h文件夹的作用StdPeriph/专门放标准外设库的驱动源码和用户代码分开结构清晰stm32f10x_conf.h是标准库的 “总开关”它 include 哪些外设头文件工程就能用哪些外设。1.3 新建 Keil 工程Keil →Project → New uVision Project→ 定位到stm32-led-stdlib文件夹工程名main→ 保存选择芯片STM32F103C8弹出 Manage Run-Time Environment 时勾选CMSIS → CORE提供内核头文件 core_cm3.hDevice → Startup提供启动文件和系统时钟初始化文件点 OK。1.4 添加源文件左侧Source Group 1上右键 →Add Existing Files to Group...添加 4 个文件main.cStdPeriph\stm32f10x_gpio.cStdPeriph\stm32f10x_rcc.cStdPeriph\stm32f10x_flash.c1.5 配置宏和头文件路径重点点魔术棒Options for Target→C/C页配置项值说明DefineUSE_STDPERIPH_DRIVER让 stm32f10x.h 自动包含 stm32f10x_conf.hInclude Paths.\;.\StdPeriph告诉编译器去哪找头文件Language Cc99CMSIS 6.x 内核头文件要求1.6 踩坑记录编译报错排查坑 1宏名写错 → 20 个错误第一次编译报了一堆GPIO_InitTypeDef、GPIO_Pin_0未定义的错误。原因是很多网络教程写的是USE_STDPERIPH_DEVICE但我这台 KeilSTM32F1xx_DFP 2.4.0 包里的 stm32f10x.h 实际要求的是\#ifdef USE\_STDPERIPH\_DRIVER #x20; #include stm32f10x\_conf.h \#endif宏名必须改成USE_STDPERIPH_DRIVER标准库的所有定义才能被包含进来。坑 2conf.h 引用不存在的头文件宏改对后又报stm32f10x_adc.h file not found。原因官方模板stm32f10x_conf.h默认 include 了全部外设头文件adc、can、dac……而我工程里只添加了 gpio/rcc/flash 三个驱动。解决把 conf.h 精简只保留用到的三个\#include stm32f10x\_flash.h \#include stm32f10x\_gpio.h \#include stm32f10x\_rcc.h编译通过0 Error。1.7 流水灯代码标准外设库版\#include stm32f10x.h void delay\_ms(unsigned int ms) // 软件延时 { #x20; volatile unsigned int i, j; #x20; for (i 0; i ms; i) #x20; for (j 0; j 5000; j) {} } int main(void) { #x20; GPIO\_InitTypeDef GPIO\_InitStructure; #x20; // 1. 使能 GPIOA/B/C 时钟 #x20; RCC\_APB2PeriphClockCmd(RCC\_APB2Periph\_GPIOA | RCC\_APB2Periph\_GPIOB | #x20; RCC\_APB2Periph\_GPIOC, ENABLE); #x20; // 2. PA0 红灯 #x20; GPIO\_InitStructure.GPIO\_Pin GPIO\_Pin\_0; #x20; GPIO\_InitStructure.GPIO\_Mode GPIO\_Mode\_Out\_PP; #x20; GPIO\_InitStructure.GPIO\_Speed GPIO\_Speed\_50MHz; #x20; GPIO\_Init(GPIOA, \GPIO\_InitStructure); #x20; // 3. PB0 绿灯复用同一结构体 #x20; GPIO\_InitStructure.GPIO\_Pin GPIO\_Pin\_0; #x20; GPIO\_Init(GPIOB, \GPIO\_InitStructure); #x20; // 4. PC14 蓝灯PC13/14/15 低速引脚2MHz #x20; GPIO\_InitStructure.GPIO\_Pin GPIO\_Pin\_14; #x20; GPIO\_InitStructure.GPIO\_Speed GPIO\_Speed\_2MHz; #x20; GPIO\_Init(GPIOC, \GPIO\_InitStructure); #x20; // 5. PC13 板载灯低电平点亮 #x20; GPIO\_InitStructure.GPIO\_Pin GPIO\_Pin\_13; #x20; GPIO\_Init(GPIOC, \GPIO\_InitStructure); #x20; // 6. 初始全灭 #x20; GPIO\_ResetBits(GPIOA, GPIO\_Pin\_0); #x20; GPIO\_ResetBits(GPIOB, GPIO\_Pin\_0); #x20; GPIO\_ResetBits(GPIOC, GPIO\_Pin\_14); #x20; GPIO\_SetBits(GPIOC, GPIO\_Pin\_13); #x20; while (1) { #x20; GPIO\_SetBits(GPIOA, GPIO\_Pin\_0); delay\_ms(1000); #x20; GPIO\_ResetBits(GPIOA, GPIO\_Pin\_0); #x20; GPIO\_SetBits(GPIOB, GPIO\_Pin\_0); delay\_ms(1000); #x20; GPIO\_ResetBits(GPIOB, GPIO\_Pin\_0); #x20; GPIO\_SetBits(GPIOC, GPIO\_Pin\_14); delay\_ms(1000); #x20; GPIO\_ResetBits(GPIOC, GPIO\_Pin\_14); #x20; GPIO\_ResetBits(GPIOC, GPIO\_Pin\_13); delay\_ms(1000); #x20; GPIO\_SetBits(GPIOC, GPIO\_Pin\_13); #x20; } }相比实验 1 的寄存器操作标准外设库把所有寄存器操作封装成了函数GPIO_Init、GPIO_SetBits可读性明显更好。问 2软件延时的 “1 秒” 到底准不准2.1 思路LED 亮 / 灭靠delay_ms(1000)软件循环延时。它到底是精确 1 秒还是存在误差没有示波器的情况下可以用Keil 软件仿真的逻辑分析仪直接观察 GPIO 波形、测量时间。2.2 仿真配置步骤Target 页设置晶振Xtal (MHz) 设为8.0STM32F103C8T6 外部晶振 8MHz。这一步很重要仿真时间计算依赖它。我的 Keil 工程 Xtal 显示undefined改不动直接修改工程文件main.uvprojx里的CLOCK(12000000)为CLOCK(8000000)解决Debug 页勾选Use SimulatorRun to main()Dialog DLL 填DARMSTM.DLLParameter 填-pSTM32F103C8点CtrlF5进入仿真菜单View → Analysis Windows → Logic Analyzer打开逻辑分析仪菜单View → Symbols Window找到GPIOA_ODR拖入逻辑分析仪窗口点逻辑分析仪里的SetupDisplay Type 选Bit按位显示And Mask 填0x00000001只看 bit0 PA0点 Close按F5全速运行观察波形。2.3 波形分析PA0 是红灯的控制脚波形如下绿色方波从波形可以清楚看到高电平段红灯亮0.879936s ≈0.88s低电平段红灯灭其他三灯轮流亮约 3 秒完整周期两个上升沿之间3.519741s验证自洽性3.519741 ÷ 4 0.879935 ≈ 0.879936正好等于单灯点亮时间—— 说明四盏灯确实是轮流各亮约 0.88s程序逻辑和波形完全对应。2.4 结论软件延时准确吗以下是波形图图片数据记录结论不准确。实测数据如下项目理论值实测值误差单灯点亮时间1.000 s0.879936 s约 12%PA0 完整周期4.000 s3.519741 s约 12%误差原因分析软件延时本质是 “数指令周期”delay_ms里 5000 这个参数是按经验估的循环次数而每条循环指令实际占几个时钟周期、volatile 变量访问的内存开销都和估算有偏差编译优化等级-O0也影响循环开销所以软件延时的 “1 秒” 只能做到 “大约 1 秒”误差在 10% 左右完全正常。如果想精确到 1 秒应该改用硬件定时器SysTick 系统节拍定时器或 TIM 通用定时器实验任务 3 的 HAL 库方案正是用 SysTick 实现精确延时可以对比。总结这个实验把 STM32 的开发方式从 “寄存器直接操作” 推进到了 “标准外设库函数调用”工程从建文件夹、复制库文件、配置宏、到解决两个编译坑宏名、conf.h完整走了一遍标准外设库工程的搭建流程。更重要的是通过 Keil 逻辑分析仪把 “软件延时到底准不准” 这个看不见的问题变成了看得见的波形和数据实测 0.88s 与理论 1s 的 12% 误差让我真正理解了为什么嵌入式开发里讲究 “能用定时器就别用软件延时”。
返回列表