新闻详情

新闻详情

首页 / 资讯中心 / 详情

STM32 实验任务3:HAL 库 + 按键中断控制流水灯暂停/恢复

发布时间:2026/9/30 2:53:00来源:尧图网络
STM32 实验任务3:HAL 库 + 按键中断控制流水灯暂停/恢复
STM32 实验任务3HAL 库 按键中断控制流水灯暂停/恢复任务要求在前面实验寄存器、标准外设库流水灯基础上改用HAL 库 按键中断方式控制流水灯运行的暂停、恢复继续。问 1没有 CubeMXHAL 库工程怎么手动搭建通常用 HAL 库开发会用 STM32CubeMX 自动生成工程但我电脑上没有 CubeMX也没有官方 CubeF1 固件包所以选择手动下载 HAL 库文件 手写工程顺便把 HAL 库工程结构彻底搞明白。1.1 下载 HAL 库文件HAL 库STM32CubeF1在 GitHub 上其实拆成了两个仓库都是 git submodulecmsis_device_f1设备头文件、启动文件、系统时钟源文件stm32f1xx_hal_driverHAL 外设驱动.c/.h把需要的 16 个文件下载后整理成工程目录stm32-led-hal/ ├── main.c ← 用户主程序 ├── stm32f1xx_hal_conf.h ← HAL 配置头文件外设模块总开关 ├── Device/ │ ├── Include/ ← 芯片头文件stm32f1xx.h 等 │ ├── Source/ ← system_stm32f1xx.c系统时钟初始化 │ └── Startup/ ← startup_stm32f103xb.s启动文件 └── HAL/ ├── Inc/ ← HAL 驱动头文件hal.h、hal_gpio.h 等 └── Src/ ← HAL 驱动源文件hal.c、hal_gpio.c 等1.2 Keil 工程配置点魔术棒Options for Target→C/C页配置项值说明DefineSTM32F103xB,USE_HAL_DRIVER芯片型号宏 使用 HAL 库宏Include Paths.\;.\HAL\Inc;.\Device\Include头文件搜索路径Language Cc99HAL 库/CMSIS 6.x 要求Run-Time Environment 里只勾选CMSIS → CORE不勾 Device → Startup启动文件用 HAL 仓库下载的 startup_stm32f103xb.s。1.3 踩坑记录编译/链接报错排查坑 1Legacy/stm32_hal_legacy.h file not found编译 HAL 驱动时报找不到Legacy/stm32_hal_legacy.h。这个头文件在 HAL 仓库的Inc/Legacy/子目录里补下载到HAL/Inc/Legacy/下解决。坑 2stm32f1xx_hal_rcc_ex.h file not foundRCC 驱动里还引用了_ex扩展头文件。预防性把stm32f1xx_hal_flash_ex.h、stm32f1xx_hal_gpio_ex.h、stm32f1xx_hal_rcc_ex.h全部补下载。坑 3链接报错Undefined symbol HAL_GPIO_Init等关键坑编译通过但链接报一串 undefined symbolFLASH_PageErase、HAL_GPIO_Init、HAL_GPIO_WritePin……排查发现根因是stm32f1xx_hal_conf.h里漏写了HAL_GPIO_MODULE_ENABLED。新版 HAL 库每个驱动文件整体被这种宏包住#ifdefHAL_GPIO_MODULE_ENABLED...gpio 驱动全部内容...#endif宏没定义 → gpio 驱动文件编译出来是空文件链接时自然找不到函数。把用到的模块宏全补上#defineHAL_FLASH_MODULE_ENABLED#defineHAL_GPIO_MODULE_ENABLED#defineHAL_RCC_MODULE_ENABLED#defineHAL_CORTEX_MODULE_ENABLED并且还需要在工程里添加stm32f1xx_hal_flash_ex.cFLASH_PageErase在这个文件里。补完后0 Error 0 Warning。问 2按键中断怎么实现2.1 硬件接线器件引脚说明红灯PA0高电平点亮绿灯PB0高电平点亮蓝灯PC14高电平点亮PC13/14/15 低速引脚板载灯PC13低电平点亮极性相反轻触按键PA1 → GND按下时 PA1 被拉低按键一端接 PA1另一端接 GND按下按键 PA1 产生下降沿正好用 EXTI 外部中断的下降沿触发来检测。2.2 按键初始化外部中断 上拉voidKEY_Init(void){GPIO_InitTypeDef GPIO_InitStruct{0};/* PA1外部中断模式下降沿触发按下→低电平内部上拉平时为高 */GPIO_InitStruct.PinGPIO_PIN_1;GPIO_InitStruct.ModeGPIO_MODE_IT_FALLING;GPIO_InitStruct.PullGPIO_PULLUP;HAL_GPIO_Init(GPIOA,GPIO_InitStruct);/* 使能 EXTI1 中断优先级 0最高 */HAL_NVIC_SetPriority(EXTI1_IRQn,0,0);HAL_NVIC_EnableIRQ(EXTI1_IRQn);}2.3 中断服务函数与回调HAL 库的中断处理分三层中断服务函数 → HAL 通用处理函数 → 用户回调/* ① 中断服务函数框架自动调用 */voidEXTI1_IRQHandler(void){HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);}/* ② 用户回调按键按下 → 翻转暂停标志 */voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){if(GPIO_PinGPIO_PIN_1){g_pause!g_pause;/* 暂停 ↔ 恢复切换 */}}按键按下 → 硬件进入 EXTI1 中断 →HAL_GPIO_EXTI_IRQHandler清中断标志并调用HAL_GPIO_EXTI_Callback→ 我们只在回调里翻转一个标志变量g_pause不做复杂操作中断里代码越短越好。2.4 踩坑 4烧录后只亮红灯不流水、按键无反应烧录后红灯常亮、完全不流水按键也没反应。排查很久发现根因是main.c 里漏写了SysTick_HandlervoidSysTick_Handler(void){HAL_IncTick();/* 每 1ms 中断一次tick 计数 1 */}HAL_Delay 依赖 SysTick 每 1ms 触发一次中断累计 tick这个服务函数没实现HAL_Delay 就永远卡死——红灯点亮后延时无限长看起来就是只亮红灯不流水。补上后流水立刻正常。问 3怎么做到按下立即暂停、再按恢复3.1 最初的设计有缺陷一开始只在主循环开头检查暂停标志while(1){while(g_pause)HAL_Delay(10);/* 只有每轮开头检查 */红灯亮1s;绿灯亮1s;蓝灯亮1s;板载亮1s;}实测发现问题流水过程中按按键不会立即停而是要等一整轮4 秒走完才停。原因g_pause 只在每轮开头被检查按键按下时主循环正卡在某一盏灯的 HAL_Delay(1000) 里要等当前灯亮完 后面所有灯亮完才回到检查点。3.2 改进把暂停检查做进延时函数把每一盏灯的延时改成delay_pause()延时期间每 10ms 检查一次按键标志按下立即原地等待当前灯保持点亮voiddelay_pause(uint32_tms){uint32_ti;for(i0;ims;i10){if(g_pause){/* 暂停保持当前灯亮着等按键恢复 */while(g_pause){HAL_Delay(10);}return;/* 恢复后跳过本灯剩余时间进入下一盏 */}HAL_Delay(10);}}主循环里把所有HAL_Delay(1000)换成delay_pause(1000)。这样按下→ 最多 10ms 内响应当前灯停在点亮状态再按→ 恢复跳过当前灯剩余时间进入下一盏灯3.3 完整代码main.c#includestm32f1xx_hal.hvolatileuint8_tg_pause0;/* 暂停标志0运行 1暂停中断中修改 *//* 系统时钟HSE 8MHz × PLL9 72MHz */voidSystemClock_Config(void){RCC_OscInitTypeDef RCC_OscInitStruct{0};RCC_ClkInitTypeDef RCC_ClkInitStruct{0};RCC_OscInitStruct.OscillatorTypeRCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEStateRCC_HSE_ON;RCC_OscInitStruct.HSEPredivValueRCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.PLL.PLLStateRCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSourceRCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMULRCC_PLL_MUL9;HAL_RCC_OscConfig(RCC_OscInitStruct);RCC_ClkInitStruct.ClockTypeRCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSourceRCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDividerRCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDividerRCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDividerRCC_HCLK_DIV1;HAL_RCC_ClockConfig(RCC_ClkInitStruct,FLASH_LATENCY_2);}/* LED 初始化PA0红 PB0绿 PC14蓝 PC13板载 */voidLED_Init(void){GPIO_InitTypeDef GPIO_InitStruct{0};__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();GPIO_InitStruct.PinGPIO_PIN_0;GPIO_InitStruct.ModeGPIO_MODE_OUTPUT_PP;GPIO_InitStruct.SpeedGPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,GPIO_InitStruct);/* PA0 红灯 */GPIO_InitStruct.PinGPIO_PIN_0;HAL_GPIO_Init(GPIOB,GPIO_InitStruct);/* PB0 绿灯 */GPIO_InitStruct.PinGPIO_PIN_14;GPIO_InitStruct.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOC,GPIO_InitStruct);/* PC14 蓝灯低速引脚 */GPIO_InitStruct.PinGPIO_PIN_13;HAL_GPIO_Init(GPIOC,GPIO_InitStruct);/* PC13 板载灯 */HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);}/* 按键初始化PA1 下降沿中断 */voidKEY_Init(void){GPIO_InitTypeDef GPIO_InitStruct{0};GPIO_InitStruct.PinGPIO_PIN_1;GPIO_InitStruct.ModeGPIO_MODE_IT_FALLING;GPIO_InitStruct.PullGPIO_PULLUP;HAL_GPIO_Init(GPIOA,GPIO_InitStruct);HAL_NVIC_SetPriority(EXTI1_IRQn,0,0);HAL_NVIC_EnableIRQ(EXTI1_IRQn);}/* SysTick 中断服务函数HAL_Delay 的时基必须实现 */voidSysTick_Handler(void){HAL_IncTick();}voidEXTI1_IRQHandler(void){HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);}/* 中断回调按键按下 → 翻转暂停标志 */voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){if(GPIO_PinGPIO_PIN_1){g_pause!g_pause;}}/* 带暂停检测的延时每 10ms 检查按键按下立即暂停 */voiddelay_pause(uint32_tms){uint32_ti;for(i0;ims;i10){if(g_pause){while(g_pause)HAL_Delay(10);/* 灯保持亮等恢复 */return;}HAL_Delay(10);}}intmain(void){HAL_Init();/* SysTick 1ms 时基、NVIC 分组 */SystemClock_Config();/* 72MHz */LED_Init();KEY_Init();while(1){HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);/* 红灯 */delay_pause(1000);HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);/* 绿灯 */delay_pause(1000);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);/* 蓝灯 */delay_pause(1000);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);/* 板载灯 */delay_pause(1000);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);}}运行效果流水灯正常轮流点亮按下按键立即暂停当前灯保持点亮再按一次恢复继续流水总结这个实验让我把 STM32 的开发方式从寄存器、标准外设库推进到了 HAL 库而且是在没有 CubeMX 的情况下纯手动搭建工程把 HAL 库设备层 驱动层 配置文件的结构彻底看了一遍中间解决了三个编译链接坑legacy 头文件、ex 扩展头文件、HAL_xxx_MODULE_ENABLED 模块开关和两个运行逻辑坑SysTick_Handler 漏写导致 HAL_Delay 卡死、暂停检查位置不对导致不能立即暂停。按键中断的思路也很有价值中断服务函数里只翻转一个标志主循环轮询标志两者通过共享变量协作避免在中断里做耗时操作。同时 HAL_Delay 基于 SysTick 定时器与实验 2 的软件循环延时实测 0.88s 对比体现了硬件定时器比软件延时精确得多这一嵌入式开发的重要原则。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

迪派全屋定制安装落地装修性价比怎么样 2026/9/30 9:55:17

迪派全屋定制安装落地装修性价比怎么样

近十年来,杭州家居定制行业发生了翻天覆地的变化:从早期木工现场打柜的手工时代,到品牌门店代理层层加价的销售时代,再到如今源头工厂直供的透明消费时代,消费者对全屋定制的要求也从有柜子用转向用好柜子、用性价比高…

阅读更多 →
虚幻引擎5 AnimNext实战:用神经网络控制器替代传统状态机 2026/9/30 9:55:16

虚幻引擎5 AnimNext实战:用神经网络控制器替代传统状态机

这次我们来看虚幻引擎 5 的 AnimNext。它不是一次普通的动画蓝图优化,而是 Epic 正在推进的下一代角色动画实验框架。其中最吸引人的部分,是那个被称为“神经网络控制器”的方案:把手写的动画状态机、大量的状态切换规则和手工混合参数&#…

阅读更多 →
树覆盖算法 2026/9/30 9:55:16

树覆盖算法

概述 树覆盖(Tree Covering)是编译器后端做指令选择的经典算法。它的核心思想是:把 IR 表示成一棵表达式树,然后用机器指令对应的“瓦片(tile)”去覆盖这棵树,每覆盖一块就生成一条指令。 IR 表…

阅读更多 →
运维人自研!把拓扑+远程+AI运维搓进一个免费工具 2026/9/30 9:55:16

运维人自研!把拓扑+远程+AI运维搓进一个免费工具

做网络的都懂这些痛👇 设备一多,拓扑全靠脑记,连过哪些口凭印象;排障翻三天前的聊天记录;每台设备的账号密码散落在记事本里……受不了就自己搓了一个:灵枢 LinkPivot,Windows 桌面工具,一个工具…

阅读更多 →
西宁比较好的工业扫地车租售企业避坑挑选指南与价格公道不玩套路 2026/9/30 9:55:16

西宁比较好的工业扫地车租售企业避坑挑选指南与价格公道不玩套路

青海利尔优环保科技有限公司,是深耕青海本地清洁领域二十余年的专业工业扫地车租售服务商,立足西宁辐射全省,为省内工厂、园区、物流仓库、堆场等各类场景提供适配性强的大面积清扫解决方案,以本地化全链条服务为核心优势&#xf…

阅读更多 →
SWIFT报文全解析:外汇与跨境结算的金融血管 2026/9/30 9:55:09

SWIFT报文全解析:外汇与跨境结算的金融血管

简介:这份幻灯片课件聚焦SWIFT外汇与国际结算,适合财务管理、国际经济与贸易专业学生及金融行业入门者使用。课件从外汇的含义与三大特点讲起,梳理国际支付手段从贵金属、英镑、美元到多种可兑换货币的演变过程,并区分自由外汇、记…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉