ARTICLE DETAIL

资讯详情

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

课时02 嵌入式技术应用设计实训 | GPIO 输入与外部中断:按键

课时02 嵌入式技术应用设计实训 | GPIO 输入与外部中断:按键 嵌入式技术应用设计实训 | GPIO 输入与外部中断按键本课程开源地址Giteehttps://gitee.com/fujianxinxi/qianrushishixundianzi.git课件、示例代码与验收脚本都在该仓库可直接git clone或下载 ZIP 使用。B站配套视频合集https://space.bilibili.com/572740825/lists?sid9228122合集《嵌入式技术应用设计实训STM32F103 从点灯到智能家居》每课配一节视频可先看现象演示再照着做。开发板资料A盘百度网盘https://pan.baidu.com/s/1_EXrjRUewwmGMgcy38zEZg提取码zbri正点原子官方资料下载http://www.openedv.com/docs/boards/stm32/zdyz_stm32f103_nano.html模块一 基础外设开发 · 2 学时 · 环境Keil MDK5 VS Code 正点原子 STM32F103 Nano V1.3一句话概述从“读一个引脚的电平”入手先弄清板载 4 个按键KEY0/KEY1/KEY2/WK_UP按下时分别是低电平还是高电平、为什么必须配上拉或下拉再把它们配成外部中断EXTI NVIC写出中断入口与回调实现“按任意一个键8 个 LED 在全亮与全灭之间翻转一次”。重点讲清“引脚号 → EXTI 线号 → NVIC 通道号”三段绑定以及“中断里不能延时、消抖改用时间戳锁定”。课堂练习 4 条大作业把“一键翻转全部”扩成“4 个键各管一个灯、按一下亮再按一下灭”。本节目标能说出读一个按键要按“开时钟 → 配输入上拉/下拉→ 读电平”三步走并说清 KEY0/KEY1/KEY2 为什么配上拉、WK_UP 为什么配下拉会配置 EXTI NVIC含中断入口函数与回调函数让按任意一个键都能把 8 个 LED 在“全亮 / 全灭”之间翻转一次能说出“引脚号 → EXTI 线号 → NVIC 通道号”的三段对应关系并解释为什么中断里不能延时消抖一、原理说明GPIO 做输出是往外写电平做输入就反过来——读电平先给端口开时钟再把引脚配成输入、并按需要打开上拉或下拉电阻最后用HAL_GPIO_ReadPin()读回它的高低。板载 4 个按键并不是“按键直接接在 IO 上”这么简单KEY0/KEY1/KEY2 是按键另一端接地所以必须打开内部上拉不按时引脚被拉成高电平、按下才被按键拉到地低电平WK_UP 接的是 3.3V必须打开内部下拉不按时是低、按下才是高——这也是 4 个键里唯一的反相。机械按键在按下和松开的一瞬间触点会弹跳三五毫秒电平像下雨一样忽高忽低所以“读一次就当按下”往往会把一次按动读成好几次。外部中断EXTI的作用是让引脚自己盯着电平变化变化一发生硬件立刻把 CPU 拉到我们写好的那段函数里执行主循环就不用一直盯着按键了。配一个外部中断要记住三段绑定——引脚号决定 EXTI 线号EXTI 线号决定 NVIC 里的中断通道号三段错一个代码照样能编译、能下载但按键就是一点反应都没有。二、讲解内容2.1 知识讲解先认清 4 个按键接在哪、按下是什么电平以下照厂家例程HARDWARE/KEY/key.c抄别看反板载按键开发板引脚不按时按下时引脚怎么配HALKEY0PC8高内部上拉低GPIO_PULLUP 下降沿触发KEY1PC9高内部上拉低同上和 KEY0 一次配好KEY2PD2高内部上拉低同上只换引脚号WK_UPPA0低内部下拉高唯一反相GPIO_PULLDOWN 上升沿触发三段绑定引脚号 → EXTI 线号 → NVIC 通道号。EXTI 的线号不看端口PA/PC/PD 都一样只看引脚号PC8 是线 8、PC9 是线 9、PD2 是线 2、PA0 是线 0。而 NVIC 里的通道是按“线”分的并且会合并——线 0、线 1 各有独立通道线 5~9 挤在同一个通道EXTI9_5里按键引脚EXTI 线号中断入口函数向量表按函数名找NVIC 通道WK_UPPA0线 0EXTI0_IRQHandlerEXTI0_IRQnKEY2PD2线 2EXTI2_IRQHandlerEXTI2_IRQnKEY0PC8线 8EXTI9_5_IRQHandlerEXTI9_5_IRQnKEY1PC9线 9同上和 PC8 同一个入口同上“线 8、线 9 共用一个入口”是新手最容易迷糊的地方KEY0 和 KEY1 的中断都会跳进EXTI9_5_IRQHandler所以在里面一次要把两个引脚都处理掉——本课直接写成HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_8 | GPIO_PIN_9);谁触发就翻谁的状态写法最简单也最不容易漏。输入三步和输出三步一样不能少步骤干什么本课的代码不做会怎样① 开时钟给按键引脚所在端口使能时钟__HAL_RCC_GPIOA_CLK_ENABLE();等三行引脚配置全部无效按键没反应且不报错② 配模式配成输入并按需要打开上拉/下拉要中断就再加上触发边沿GPIO_MODE_IT_FALLINGGPIO_PULLUP引脚是复位后的浮空输入电平乱飘会误触发③ 使能中断让 NVIC 放行这条中断通道HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);引脚能看到电平变化但 CPU 永远不会被叫去处理STM32F1 的一个专属细节AFIO 时钟F1 的 EXTI 引脚映射要经过 AFIO 外设写寄存器版时得先__HAL_RCC_AFIO_CLK_ENABLE();。不过 HAL 库的HAL_GPIO_Init()一看到IT模式就替你把这句写好了在stm32f1xx_hal_gpio.c里所以本课代码里不用再写看到别的例程多这一句知道它在干什么就行。抖动与消抖两种做法效果一样代价不同。机械按键按下和松开的瞬间触点在几毫秒里反复通断电平会跳好几次——这就是“抖动”。不处理的话一次按动会被当成两三次做法怎么写优点代价轮询 延时消抖厂家例程的KEY_Scan()读到按下 →delay_ms(10)再确认一次 → 松手后才允许下一次直观好懂适合小实验CPU 一直盯着按键delay_ms那 10ms 里什么都干不了中断 时间戳锁定本课用回调里记HAL_GetTick()200ms 内再来就丢掉不占 CPU主循环空闲快速连按会被“吞”掉几次把KEY_LOCK_MS调小可缓解中断里为什么不能延时中断一旦进入主循环就停在原地等它执行完。如果在中断里写delay_ms(10)整个系统就被卡住 10ms按键按得急了还会互相插队现象会变得莫名其妙。另外HAL_GetTick()靠 SysTick 的 1ms 中断累计如果中断优先级配得不对它可能一直不变用时间戳会算错。本课把 EXTI 的抢占优先级设成2数值越大优先级越低而 SysTick 是 0、比它高所以在中断里HAL_GetTick()照样在走——这是“时间戳锁定”能放进中断的前提。HAL 库的中断调用链记住这三步就够引脚电平出现下降沿/上升沿KEY0~KEY2 下降沿、WK_UP 上升沿 │ 硬件自动触发 ▼ EXTI9_5_IRQHandler() ← 中断入口函数向量表按这个名字找它 │ 我们调用 ▼ HAL_GPIO_EXTI_IRQHandler(引脚) ← HAL 帮你清掉中断挂起标志 │ 它再调用 ▼ HAL_GPIO_EXTI_Callback(引脚) ← 我们干活的地方翻转 8 个灯HAL_GPIO_EXTI_Callback()在 HAL 库里是弱函数__weak我们在main.c里重写一份链接时就会用我们这份不用注册、也不用函数指针。2.2 代码示例本课只改一个文件课时文档/代码/课时02-GPIO 输入与外部中断-按键/按键实验/USER/main.c。工程里其余文件都是厂家例程现成的不用动课时文档/代码/课时02-GPIO 输入与外部中断-按键/ └── 按键实验/ ← 正点原子官方“按键实验”例程HAL 库版 ├── USER/KEY.uvprojx ← Keil 打开这个工程 ├── USER/main.c ← 本课唯一要改的文件 ├── HARDWARE/KEY/ ← 厂家按键驱动 key.c / key.h轮询版本课不调用练习 P2.3 要用 ├── HARDWARE/LED/ ← LED 驱动PC0~PC7 配成推挽输出上电默认全灭 ├── HARDWARE/BEEP/ ← 蜂鸣器驱动本课不用练习 P2.4 会用到 ├── SYSTEM/ ← sys、delaydelay_ms 就在这里、usart ├── HALLIB/ CORE/ ← HAL 库与启动文件不用改 └── OBJ/ ← 编译输出已加入 .gitignore不进仓库下面是本课USER/main.c的完整代码一个文件一个现象#includesys.h#includedelay.h#includeusart.h#includeled.h/************************************************ 嵌入式技术应用设计实训 课时02 GPIO 输入与外部中断按键 本文件基于正点原子 ALIENTEK NANO STM32F103 厂家例程按键实验-HAL库版改写。 例程版权归广州市星翼电子科技有限公司所有。 硬件正点原子 STM32F103 Nano V1.3全部板载不用接线 DS0~DS7红色 LED 接 PC0~PC7低电平点亮 KEY0 接 PC8、KEY1 接 PC9、KEY2 接 PD2 —— 按下是低电平芯片内上拉 WK_UP 接 PA0 —— 按下是高电平芯片内下拉唯一反相 本课现象只有一个按任意一个键8 个 LED 在“全亮 / 全灭”之间翻转一次。 实现方式外部中断EXTI NVIC。中断只做两件事——判断抖动、翻转灯 其余时间主循环什么都不干等着中断来敲门。 两个必须记住的坑 1) 中断里不能延时消抖delay_ms 靠 SysTick在中断里死等会把整个程序拖住 所以本课用“时间戳锁定”200ms 内的重复触发直接丢掉。 2) 中断入口函数 EXTIx_IRQHandler 必须存在否则中断触发了也进不来。 厂家这个例程是轮询版没写这三个入口本课把它们补在下面。 ************************************************//* ---------- LED低电平点亮PC0~PC7 对应 DS0~DS7与课时01 写法一致 ---------- */#defineLED_ALL_OFF()HAL_GPIO_WritePin(GPIOC,(uint16_t)0x00FF,GPIO_PIN_SET)/* 8 个灯全灭 */#defineLED_ALL_ON()HAL_GPIO_WritePin(GPIOC,(uint16_t)0x00FF,GPIO_PIN_RESET)/* 8 个灯全亮 *//* ---------- 消抖同一个键两次响应的最小间隔毫秒觉得太钝就改小 ---------- */#defineKEY_LOCK_MS200staticu8 all_on0;/* 8 个灯当前的状态0 全灭1 全亮 *//* ------------------------------------------------------------------ 中断入口Cortex-M3 的向量表按函数名找入口名字写错 中断永远进不来 PA0 - EXTI0 线 0 PD2 - EXTI2 线 2 PC8 - EXTI9_5 线 8、线 9 共用一个入口所以一次要处理两个引脚 HAL_GPIO_EXTI_IRQHandler() 会清中断标志再调用下面的 HAL_GPIO_EXTI_Callback() ------------------------------------------------------------------ */voidEXTI0_IRQHandler(void){HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);/* WK_UP */}voidEXTI2_IRQHandler(void){HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);/* KEY2 */}voidEXTI9_5_IRQHandler(void){HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_8|GPIO_PIN_9);/* KEY0 / KEY1 */}/* ------------------------------------------------------------------ 按键中断初始化4 个按键全部配成“外部中断”模式 输入三步一样不能少开时钟 - 配模式含上拉/下拉、触发边沿- 使能中断 注意 WK_UP 与另外三个相反按下是高电平所以配下拉 上升沿 ------------------------------------------------------------------ */staticvoidKEY_EXTI_Init(void){GPIO_InitTypeDef GPIO_Initure;__HAL_RCC_GPIOA_CLK_ENABLE();/* WK_UP 在 PA0 */__HAL_RCC_GPIOC_CLK_ENABLE();/* KEY0/KEY1 在 PC8/PC9 */__HAL_RCC_GPIOD_CLK_ENABLE();/* KEY2 在 PD2 *//* STM32F1 的 EXTI 引脚映射要经过 AFIOHAL 库的 HAL_GPIO_Init() 看到 IT 模式时 已经替你开了 AFIO 时钟stm32f1xx_hal_gpio.c 里那行 __HAL_RCC_AFIO_CLK_ENABLE() 所以这里不用再写写寄存器版时要自己开。 *//* KEY0(PC8)、KEY1(PC9)按下是低电平 - 上拉 下降沿 */GPIO_Initure.PinGPIO_PIN_8|GPIO_PIN_9;GPIO_Initure.ModeGPIO_MODE_IT_FALLING;GPIO_Initure.PullGPIO_PULLUP;GPIO_Initure.SpeedGPIO_SPEED_HIGH;HAL_GPIO_Init(GPIOC,GPIO_Initure);/* KEY2(PD2)同上沿用上面的结构体只改引脚 */GPIO_Initure.PinGPIO_PIN_2;HAL_GPIO_Init(GPIOD,GPIO_Initure);/* WK_UP(PA0)按下是高电平 - 下拉 上升沿触发方式与上面相反 */GPIO_Initure.PinGPIO_PIN_0;GPIO_Initure.ModeGPIO_MODE_IT_RISING;GPIO_Initure.PullGPIO_PULLDOWN;HAL_GPIO_Init(GPIOA,GPIO_Initure);/* 使能 NVIC 通道引脚号 - EXTI 线号 - 中断通道号三段要一一对上 */HAL_NVIC_SetPriority(EXTI0_IRQn,2,0);/* 线 0WK_UP */HAL_NVIC_EnableIRQ(EXTI0_IRQn);HAL_NVIC_SetPriority(EXTI2_IRQn,2,0);/* 线 2KEY2 */HAL_NVIC_EnableIRQ(EXTI2_IRQn);HAL_NVIC_SetPriority(EXTI9_5_IRQn,2,0);/* 线 5~9KEY0/KEY1 都在这 */HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);}/* ------------------------------------------------------------------ 中断回调HAL 库里所有 EXTI 线最终都进这里 它在 HAL 里是“弱函数”在 main.c 里重写一份就被调用不用注册 这里只干两件事200ms 锁定消抖、翻转 8 个灯 ------------------------------------------------------------------ */voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){staticuint32_tlast_tick0;/* 上一次响应的时间戳 */uint32_tnowHAL_GetTick();/* 开机以来的毫秒数 */if(now-last_tickKEY_LOCK_MS)return;/* 200ms 内再触发判为抖动丢掉 */last_ticknow;all_on!all_on;/* 翻转状态 */if(all_on)LED_ALL_ON();elseLED_ALL_OFF();}intmain(void){HAL_Init();/* 初始化 HAL 库顺便把 1ms 时基HAL_GetTick跑起来 */Stm32_Clock_Init(RCC_PLL_MUL9);/* 系统时钟倍频到 72MHz */delay_init(72);/* 初始化延时函数 */LED_Init();/* 初始化 LEDDS0~DS7PC0~PC7 */KEY_EXTI_Init();/* 初始化 4 个按键的外部中断 */LED_ALL_OFF();/* 上电先全灭按下第一个键就看到“全亮” */while(1){/* 主循环什么都不用做按键一按中断自己把 8 个灯翻转 这就是中断的好处——CPU 不用一直盯着按键 */}}代码里最值得盯住的 4 处位置为什么这么写GPIO_MODE_IT_FALLING/GPIO_MODE_IT_RISINGKEY0~KEY2 按下是低电平配下降沿WK_UP 按下是高电平配上升沿。配反的现象是“松手才翻”或“完全没反应”EXTI9_5_IRQHandler()里的GPIO_PIN_8与GPIO_PIN_9线 8、线 9 共用一个入口两个按键一次处理完少写一个就会“KEY1 按下没反应”HAL_GPIO_EXTI_Callback()里的HAL_GetTick()判断中断里不能延时用时间戳做 200ms 锁定消抖while (1) {}空着的主循环说明“中断把主循环解放了”按键响应不再靠轮询主循环可以什么都不干三、实验操作与现象3.1 接线与操作步骤本课不用任何额外接线LED、4 个按键都在板上这点和课时01 一样插上就能做。模块/元件开发板引脚说明KEY0PC8按下为低电平已打开内部上拉不用外接电阻KEY1PC9同上与 KEY0 共用中断入口KEY2PD2同上独立一条 EXTI 线WK_UPPA0按下为高电平已打开内部下拉唯一反相别照 KEY0 的写法套DS0~DS7PC0~PC7低电平点亮本课用来显示按键状态ST-LinkSWDIO / SWCLK / GND下载与调试课时00 已连好操作步骤Keil 打开工程课时文档/代码/课时02-GPIO 输入与外部中断-按键/按键实验/USER/KEY.uvprojx选下载器Options for Target → Debug → ST-Link Debugger → OK课时00 已设过换电脑要重设看代码确认main.c里的KEY_LOCK_MS是200消抖锁定时间编译BuildF7确认0 Error(s), 0 Warning(s)下载DownloadF8确认Programming Done. Verify OK.按复位键 RST或重新上电8 个灯全灭程序就绪依次按 KEY0、KEY1、KEY2、WK_UP每按一次8 个灯在“全亮 / 全灭”之间翻转一次3.2 观察到的现象本课现象以随课视频演示为准视频里会把 4 个按键各按几遍、再快速连按一遍文档不逐条配截图你自己做完请录一段或拍一张作为提交物。操作看到什么算成功怎么核对上电/复位后8 个灯全灭安静地等着一个灯都不亮也没有声音按一下 KEY0PC88 个灯全部亮再按一下全部灭一次按动只翻转一次不会只亮一部分按一下 KEY1PC9同上KEY1 与 KEY0 走同一个中断入口EXTI9_5现象应完全一致按一下 KEY2PD2同上它走EXTI2是独立的一条线按一下 WK_UPPA0同上它是高电平有效、走EXTI0松开时不应再翻一次快速连按同一个键每秒 4~5 下灯不会被一次按动翻两三次200ms 锁定在起作用把KEY_LOCK_MS改成500再按感觉更明显看不到现象怎么办按最可能的原因排序现象最可能的原因怎么处理4 个键按了都没反应灯一直全灭中断入口函数没写或名字拼错例如写成EXIT9_5_IRQHandler或忘了HAL_NVIC_EnableIRQ()对照 2.1 节的“三段绑定”表逐项核对入口函数名与通道号只有 WK_UP 有反应另外三个没反应KEY0/KEY1/KEY2 的配置不对漏了GPIO_PULLUP或漏开 GPIOC / GPIOD 时钟检查三行__HAL_RCC_GPIOx_CLK_ENABLE()是否都在只有 KEY0 有反应KEY1 没反应EXTI9_5_IRQHandler里只写了GPIO_PIN_8补成GPIO_PIN_8与GPIO_PIN_9按键一按灯闪两三次才停消抖没生效KEY_LOCK_MS被改成 0恢复KEY_LOCK_MS 200松手才翻 / 按住不翻触发边沿配反了低有效的键配成了上升沿KEY0~KEY2 用GPIO_MODE_IT_FALLINGWK_UP 用GPIO_MODE_IT_RISING编译报重复定义multiply defined中断入口函数在stm32f1xx_it.c里也写了一份本工程没有换别的例程时可能遇到只保留一处本课统一写在main.c一上电 8 个灯就是全亮少了LED_ALL_OFF()那句在LED_Init()之后补上下载报No Cortex-M Device found下载器没连好 / 板子没上电查 SWD 三根线与供电课时00 练过一遍四、学生练习课堂上按顺序做一条一条改、一条一条看现象编号任务提示预期结果P2.1只让 KEY0 有效注释掉__HAL_RCC_GPIOA_CLK_ENABLE();、__HAL_RCC_GPIOD_CLK_ENABLE();以及 WK_UP、KEY2 的HAL_GPIO_Init()与两次HAL_NVIC_EnableIRQ()EXTI0、EXTI2只有 KEY0 能翻转 8 个灯另外三个键按了没反应EXTI9_5里只处理线 8 也行P2.2亲眼看抖动把KEY_LOCK_MS改成0快速连按同一个键 10 次看完再改回200改 0 时灯会多翻好几下一次按动翻两三次改回 200 后恢复正常P2.3改成轮询版用工程自带的HARDWARE/KEY/key.cwhile (1)里key KEY_Scan(0);判断KEY0_PRES~WKUP_PRES去掉 NVIC 配置与三个中断入口函数按键照样能翻转灯再把KEY_Scan里的delay_ms(10)注释掉快速按几下看会不会变“脏”P2.4加一声“嘀”选做本板蜂鸣器接 PB8、低电平响课时01 已实测按键时HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET)100ms 后写回GPIO_PIN_SET每按一次“嘀”一声同时 8 个灯翻转注意别在中断里用delay_ms等 100msP2.5挑战把边沿改成双边沿把 WK_UP 配成GPIO_MODE_IT_RISING_FALLING下拉不变按住、松开各看一次按住翻一次、松开又翻一次——直观体会“边沿触发”与“电平”的差别五、大作业实验二4按键控制 LED 亮灭本作业对应课程大纲里的实验二「4按键控制 LED 亮灭」当堂完成、当堂验收做不完的带回宿舍接着做下次课开课先收。5.1 任务书把课上“任意一个键按下8 个灯一起翻转”扩成“4 个键各管一个灯按一下亮、再按一下灭”4 个灯互不影响必须用本课学的外部中断EXTI NVIC实现处理都在HAL_GPIO_EXTI_Callback()里每盏灯的状态要用变量记住例如static u8 led_on[4];——不要“读灯现在的电平再取反”那是另一种写法键与灯不是一对一的时候会立刻出错键与灯的对应KEY0 → DS0、KEY1 → DS1、KEY2 → DS2、WK_UP → DS3其余四个灯DS4~DS7保持全灭保留 200ms 锁定消抖同一个键连按 10 次该灯亮灭各 5 次编译输出0 Error(s), 0 Warning(s)5.2 分步提示先想清“谁管谁”GPIO_PIN_8KEY0→ 第 0 号灯GPIO_PIN_9KEY1→ 第 1 号灯GPIO_PIN_2KEY2→ 第 2 号灯GPIO_PIN_0WK_UP→ 第 3 号灯回调里先认出是哪个键用GPIO_Pin判断得到一个序号n 0~3用数组记状态static u8 led_on[4] {0, 0, 0, 0};翻转led_on[n] !led_on[n];按状态写电平HAL_GPIO_WritePin(GPIOC, (uint16_t)(1U n), led_on[n] ? GPIO_PIN_RESET : GPIO_PIN_SET);——本板低电平点亮别写反编译下载4 个键各按两轮确认互不干扰再做 P2.2 那样的快速连按确认不会多翻HAL_GPIO_EXTI_Callback()改写后的样子关键部分其余保持课上代码不变staticu8 led_on[4]{0,0,0,0};/* DS0~DS3 各自的状态0 灭1 亮 */voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){staticuint32_tlast_tick0;uint32_tnowHAL_GetTick();u8 n;if(now-last_tickKEY_LOCK_MS)return;/* 消抖200ms 内不重复响应 */last_ticknow;if(GPIO_PinGPIO_PIN_8)n0;/* KEY0 - DS0 */elseif(GPIO_PinGPIO_PIN_9)n1;/* KEY1 - DS1 */elseif(GPIO_PinGPIO_PIN_2)n2;/* KEY2 - DS2 */elsen3;/* WK_UP - DS3 */led_on[n]!led_on[n];/* 翻转这个灯的状态 */HAL_GPIO_WritePin(GPIOC,(uint16_t)(1Un),led_on[n]?GPIO_PIN_RESET:GPIO_PIN_SET);/* 低电平点亮 */}5.3 现象与验收标准验收项标准单键按一下 KEY0DS0 亮再按一下DS0 灭互相独立4 个键各按两轮4 个灯各自亮灭互不影响DS1 亮着时按 KEY0DS1 不受影响连按同一个键连按 10 次该灯亮灭各 5 次不多翻、不跳消抖按得快、按得慢都不出现“一次按动翻两次”其余灯DS4~DS7 全程全灭编译下载0 Error(s), 0 Warning(s)Programming Done. Verify OK.5.4 提交物代码课时文档/代码/课时02-GPIO 输入与外部中断-按键/按键实验/USER/main.c现象一段 20 秒以内的视频4 个键各按两轮能让老师看清“哪个键亮了哪个灯”或按动前后的两张照片一句话说明“灯的状态记在哪个变量里为什么不能靠读灯的电平再取反来做”六、本节小结与下节预告本节把 GPIO 输入这条线完整走了一遍4 个按键接在哪、按下是高还是低、为什么必须配上拉或下拉KEY0/KEY1/KEY2 按下是低、WK_UP 按下是高再用外部中断把它接到 CPU 上——HAL_GPIO_Init()配成GPIO_MODE_IT_FALLING/..._RISING、HAL_NVIC_EnableIRQ()放行通道、EXTIx_IRQHandler()当入口、HAL_GPIO_EXTI_Callback()干活最后只剩一句“翻转 8 个灯”。三句话记住本课电平配反了现象就拧着来按住才响应、或松手才翻中断有三段绑定引脚号 → EXTI 线号 → NVIC 通道号缺一段就是“编译没报错、按键没反应”中断里要短消抖用时间戳锁定绝不在中断里delay_ms。下节进入串口通信把板子里的信息打到电脑上看USART printf 重定向。本节函数与宏速查名称一句话作用__HAL_RCC_GPIOA_CLK_ENABLE()等给按键所在端口开时钟PA0 / PC8 / PC9 / PD2 三个端口HAL_GPIO_Init(端口, 结构体)配成外部中断模式GPIO_MODE_IT_FALLING/..._RISING 上拉/下拉F1 上它会自动开 AFIO 时钟HAL_GPIO_ReadPin(端口, 引脚)读引脚电平轮询版用厂家key.c里就是这么读的HAL_NVIC_SetPriority(通道, 抢占, 子)给中断排优先级本课统一用 2数值越大越低HAL_NVIC_EnableIRQ(通道)放行通道EXTI0_IRQn/EXTI2_IRQn/EXTI9_5_IRQnEXTIx_IRQHandler()中断入口函数向量表按名字找它里面调HAL_GPIO_EXTI_IRQHandler(引脚)HAL_GPIO_EXTI_IRQHandler(引脚)HAL 提供的“清中断标志 转回调”HAL_GPIO_EXTI_Callback(引脚)弱函数我们在main.c里重写消抖与翻转灯都在这里HAL_GetTick()开机以来的毫秒数1ms 时基本课用它做 200ms 锁定消抖LED_ALL_ON()/LED_ALL_OFF()8 个灯一起亮 / 一起灭沿用课时01 的写法附录A. 怎么编译下载照着做就能跑1. 上电接线板子 USB 供电 → ST-Link 接 SWD 三根线SWDIO / SWCLK / GND→ ST-Link 插电脑 2. Keil 打开课时文档/代码/课时02-GPIO 输入与外部中断-按键/按键实验/USER/KEY.uvprojx 3. 选下载器Options for Target → Debug → ST-Link Debugger → OK 4. 看参数 main.c 开头的 #define KEY_LOCK_MS 200消抖锁定时间改小响应快但容易多翻 5. 编译 BuildF7确认 0 Error(s), 0 Warning(s) 6. 下载 DownloadF8确认 Programming Done. Verify OK. 7. 复位 按 RST 键8 个灯全灭按任意一个键8 个灯在全亮 / 全灭之间翻转B. 本课代码本课只改一个文件课时文档/代码/课时02-GPIO 输入与外部中断-按键/按键实验/USER/main.c完整代码见 2.2 节。工程里其余文件都是厂家例程现成的不用动文件作用USER/KEY.uvprojxKeil 工程文件用 Keil 打开这个USER/main.c本课自写代码按键 EXTI 初始化 三个中断入口 中断回调USER/stm32f1xx_it.c中断入口的“官方住处”本课三个 EXTI 入口写在main.c里这个文件不用改HARDWARE/KEY/key.c、key.h厂家按键驱动轮询版KEY_Init()/KEY_Scan()/KEY0_PRES等练习 P2.3 要用HARDWARE/LED/led.c、led.hLED 驱动PC0~PC7 配成推挽输出并上电置全灭HARDWARE/BEEP/beep.c、beep.h蜂鸣器驱动PB8练习 P2.4 要用SYSTEM/sys、delay、usartdelay_ms在这里HALLIB/、CORE/STM32F1 HAL 库与启动文件OBJ/编译输出已加入.gitignore不进仓库C. 引脚对照表贴在板子旁边用引脚板载元件不按时 / 按下时说明PC8KEY0高 /低内部上拉按下翻转 8 个灯PC9KEY1高 /低与 KEY0 共用中断入口EXTI9_5_IRQHandlerPD2KEY2高 /低独立中断入口EXTI2_IRQHandlerPA0WK_UP低 /高唯一反相中断入口EXTI0_IRQHandlerPC0~PC7DS0~DS7——低电平点亮课时01 已实测PB8蜂鸣器 BEEP——低电平响课时01 已实测练习 P2.4 用相关文档课程大纲课时02 在“一、基础外设开发模块”课程文档写作规范0.1 教学环境约定上一课课时01 GPIO 输出跑马灯与蜂鸣器下一课课时03 串口通信USART 收发与 printf
返回列表