当前位置: 首页 > wzjs >正文

维力安网站建设公司谷歌关键词

维力安网站建设公司,谷歌关键词,微信公众号免费导入wordpress,中英文网站建设方案接续上文:普中STM32F103ZET6开发攻略(二)-CSDN博客 点关注不迷路哟。你的点赞、收藏,一键三连,是我持续更新的动力哟!!! 目录 3.GPIO端口实验_中断控制: 3.1 实验目的…

接续上文:普中STM32F103ZET6开发攻略(二)-CSDN博客

点关注不迷路哟。你的点赞、收藏,一键三连,是我持续更新的动力哟!!!

目录

3.GPIO端口实验_中断控制:

3.1 实验目的:

3.2 实验环境:

3.3 实验原理

3.4 实验思路

3.5 实验代码

3.5.1 LED头、源

3.5.2 key头、源

3.5.3 beep头、源

3.5.4 exit头、源

3.5.5 实验现象

3.6 实验思考和拓展

3.6.1 如何增强中断服务函数中的按键消抖处理,使其更加可靠?

3.6.2 如何通过修改中断优先级,实现不同按键间的优先级控制?

3.6.3 如何在中断服务函数中实现按键长按和短按的区分?

3.6.4 如何实现组合按键功能(同时按下多个按键)?在中断方式下有何困难?

3.6.5 中断方式与轮询方式检测按键各有什么优缺点?在什么场景下选择中断方式更合适?

3.7 注意事项


3.GPIO端口实验_中断控制

3.1 实验目的:

  1. 熟悉STM32F10x微控制器的外部中断(EXTI)系统结构和基本操作

  1. 掌握STM32标准库函数对外部中断的配置方法

  1. 学会使用中断方式处理按键输入,控制LED和蜂鸣器的工作状态

  1. 理解中断优先级设置和中断服务函数编写原则

3.2 实验环境:

  • 开发板:STM32F103ZET6

  • IDE:Keil MDK 5 /Visual Studio

  • 调试工具:CMSIS-DAP

3.3 实验原理

1. *外部中断基本原理*

STM32的外部中断系统可以监测IO口电平变化,并在符合预设触发条件时执行中断服务函数。触发条件包括:

上升沿触发:电平从低变高时触发中断

下降沿触发:电平从高变低时触发中断

双边沿触发:电平变化时均触发中断 本实验中KEY_UP按键使用上升沿触发,KEY0、KEY1、KEY2按键使用下降沿触发。

2. *中断优先级控制*

STM32微控制器通过嵌套向量中断控制器(NVIC)管理各种中断请求。中断优先级分为抢占优先级子优先级

抢占优先级:决定是否可以打断当前正在执行的中断服务函数

子优先级:决定同时发生的同级抢占优先级中断的执行顺序

当抢占优先级相同时比较子优先级谁的数字更小谁先执行

3. *中断消抖技术*

机械按键在中断模式下仍需要消抖处理,通常的做法是在中断服务函数中加入短时延时,再次检测按键状态以确认。

4. *LED和蜂鸣器控制原理*

本实验板上的LED采用共阳极连接方式,GPIO输出低电平时LED点亮;蜂鸣器则是GPIO输出高电平时发声。

3.4 实验思路

3.5 实验代码

3.5.1 LED头、源

led.h

#ifndef __LED_H
#define __LED_H
​
#include "stm32f10x.h"
​
#define LED0_GPIO_PORT GPIOB
#define LED0_GPIO_PIN  GPIO_Pin_5 //LED0
​
#define LED1_GPIO_PORT GPIOE
#define LED1_GPIO_PIN  GPIO_Pin_5 //LED1
​
void LED_Init(void);
void LED0_TOGGLE(void);
void LED1_ON(void);
void LED1_OFF(void);
​
#endif
​

led.c

#include "led.h"
​
void LED_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 开启 GPIOB 和 GPIOE 的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);
​//配置PB5(LED0)GPIO_InitStructure.GPIO_Pin = LED0_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(LED0_GPIO_PORT, &GPIO_InitStructure);
​//配置PE5(LED1)GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);
​//低电平输出GPIO_ResetBits(LED0_GPIO_PORT, LED0_GPIO_PIN);GPIO_ResetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);
}
​
void LED0_TOGGLE(void)
{LED0_GPIO_PORT->ODR ^= LED0_GPIO_PIN;
}
​
void LED1_ON(void)
{GPIO_ResetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);
}
​
void LED1_OFF(void)
{GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);
}
​

3.5.2 key头、源

key.h

#ifndef __KEY_H
#define __KEY_H
​
#include "stm32f10x.h"
​
// GPIO 输入宏
#define PAin(n)  (GPIO_ReadInputDataBit(GPIOA, (1 << (n))))
#define PEin(n)  (GPIO_ReadInputDataBit(GPIOE, (1 << (n))))
​
// 按键 GPIO 宏定义
#define KEY0_PIN      GPIO_Pin_4
#define KEY1_PIN      GPIO_Pin_3
#define KEY2_PIN      GPIO_Pin_2
#define KEY_UP_PIN    GPIO_Pin_0
​
#define KEY_PORT      GPIOE
#define KEY_UP_PORT   GPIOA
​
#define KEY_UP        PAin(0)
#define KEY0          PEin(4)
#define KEY1          PEin(3)
#define KEY2          PEin(2)
​
// 返回值宏定义
#define KEY_UP_PRESS  1
#define KEY0_PRESS    2
#define KEY1_PRESS    3
#define KEY2_PRESS    4
​
void KEY_Init(void);
u8 KEY_Scan(u8 mode);
​
#endif
​

key.c

#include "key.h"
#include "delay.h"
​
void KEY_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOE, ENABLE);
​// KEY_UP: 下拉输入GPIO_InitStructure.GPIO_Pin = KEY_UP_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_Init(KEY_UP_PORT, &GPIO_InitStructure);
​// KEY0, KEY1, KEY2: 上拉输入GPIO_InitStructure.GPIO_Pin = KEY0_PIN | KEY1_PIN | KEY2_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(KEY_PORT, &GPIO_InitStructure);
}
​
u8 KEY_Scan(u8 mode)
{static u8 key_up = 1;
​if (mode) key_up = 1;
​if (key_up && (KEY_UP || !KEY0 || !KEY1 || !KEY2)){Delay_ms(10);  // 消抖key_up = 0;if (KEY_UP)   return KEY_UP_PRESS;if (!KEY0)    return KEY0_PRESS;if (!KEY1)    return KEY1_PRESS;if (!KEY2)    return KEY2_PRESS;}else if (!KEY_UP && KEY0 && KEY1 && KEY2){key_up = 1;}
​return 0;
}
​

3.5.3 beep头、源

bepp.h

#ifndef __BEEP_H
#define __BEEP_H
​
#include "stm32f10x.h"
​
#define BEEP_GPIO_PORT GPIOB
#define BEEP_GPIO_PIN  GPIO_Pin_8
​
void BEEP_Init(void);
void BEEP_ON(void);
void BEEP_OFF(void);
​
#endif
​

beep.c

#include "beep.h"
​
void BEEP_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//初始化各项参数:GPIO_InitStructure.GPIO_Pin = BEEP_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(BEEP_GPIO_PORT, &GPIO_InitStructure);
​GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);  // 默认关闭蜂鸣器
}
​
void BEEP_OFF(void)
{GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);
}
​
void BEEP_ON(void)
{GPIO_SetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);
}
​

3.5.4 exit头、源

exit.h

#ifndef __EXTI_H
#define __EXTI_H
​
#include "stm32f10x.h"  // 基础库头文件
​
void my_exti_int(void);  // 外部中断初始化函数声明
​
#endif
​

exit.c

#include "exti.h"
#include "key.h"
​
void my_exti_int(void)
{EXTI_InitTypeDef EXTI_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;// 开启 GPIO 时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // AFIO 复用功能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 开启 GPIO 时钟:灯光RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
​// 配置 KEY_UP 为下拉输入模式(PA0)//GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = KEY_UP_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;  // 下拉输入GPIO_Init(GPIOA, &GPIO_InitStructure);
​// 配置 KEY0~2 为上拉输入模式(PE2、PE3、PE4)GPIO_InitStructure.GPIO_Pin = KEY0_PIN | KEY1_PIN | KEY2_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOE, &GPIO_InitStructure);
​// GPIO 映射到 EXTI 通道GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); // KEY_UP -> EXTI0GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4); // KEY0 -> EXTI4GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3); // KEY1 -> EXTI3GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource2); // KEY2 -> EXTI2
​// 配置 EXTI0(KEY_UP)EXTI_InitStructure.EXTI_Line = EXTI_Line0;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  // 上升沿触发EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能特定的 EXTI 中断线EXTI_Init(&EXTI_InitStructure);
​// 配置 EXTI2(KEY2)EXTI_InitStructure.EXTI_Line = EXTI_Line2;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  // 下降沿触发EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);
​// 配置 EXTI3(KEY1)EXTI_InitStructure.EXTI_Line = EXTI_Line3;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  // 下降沿触发EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);
​// 配置 EXTI4(KEY0)EXTI_InitStructure.EXTI_Line = EXTI_Line4;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  // 下降沿触发EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);
​// 配置 NVIC 中断优先级// EXTI0_IRQnNVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
​// EXTI2_IRQnNVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
​// EXTI3_IRQnNVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
​// EXTI4_IRQnNVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
​
}
​

分析:

在 STM32 系列微控制器中,GPIO 引脚映射到 EXTI(外部中断 / 事件控制器)通道时,不同的 EXTI 通道具有以下区别:

通道编号与引脚限制

STM32 的 EXTI 通道分为两种类型:

  • 0-15 号通道:每个通道对应一组 GPIO 引脚中的

    同一位号。

    • 例如:EXTI0 只能连接到所有 GPIO 端口的Pin0(如 PA0、PB0、PC0 等)。

    • 同一时刻,每个通道只能映射一个 GPIO 引脚

  • 16-22 号通道:用于特殊功能(如 RTC 闹钟、USB 唤醒等),与 GPIO 无关。

总结

  • 通道编号决定中断函数:不同通道对应不同的中断服务函数。

  • 同一通道只能映射一个引脚:例如EXTI0不能同时连接 PA0 和 PB0。

  • 触发方式和优先级独立配置:每个通道可单独设置触发条件和中断优先级。

通过合理分配 EXTI 通道,你可以高效处理多个按键的中断事件。

 EXTI_InitStructure.EXTI_LineCmd = ENABLE;`EXTI_LineCmd = ENABLE`是启用外部中断功能必不可少的一步。只有完成了这一步,当 GPIO 引脚出现电平变化时,才会触发相应的中断服务函数。

3.5.5 实验现象
  1. DS0指示灯会不断闪烁(200ms翻转一次)

  1. 按下KEY_UP键,DS1指示灯点亮

  1. 按下KEY2键,DS1指示灯熄灭

  1. 按下KEY1键,蜂鸣器发声

  1. 按下KEY0键,蜂鸣器停止发声

3.6 实验思考和拓展

3.6.1 如何增强中断服务函数中的按键消抖处理,使其更加可靠?

改进方案

  1. 硬件消抖 + 软件消抖结合

    • 硬件:添加 0.1μF 电容到按键两端,滤除高频抖动

    • 软件:采用定时器消抖,避免阻塞中断服务函数

  2. 状态机消抖

    • 将按键状态分为:按下抖动→稳定按下→释放抖动→稳定释放

    • 使用定时器确认状态变化的稳定性

    • 基本原理:

      状态机消抖将按键的整个生命周期划分为多个稳定状态过渡状态,利用定时器对每个状态的持续时间进行验证,只有当信号在足够长的时间内保持稳定时,才认为状态发生了有效变化。

    • 典型状态划分:

      1. IDLE(空闲状态):按键未被按下,引脚保持高电平。

      2. PRESS_DEBOUNCE(按下抖动):检测到引脚电平下降,进入消抖验证。

      3. PRESSED(稳定按下):确认按键已稳定按下。

      4. RELEASE_DEBOUNCE(释放抖动):检测到引脚电平上升,进入释放消抖。

3.6.2 如何通过修改中断优先级,实现不同按键间的优先级控制?

实现步骤

  1. 配置 NVIC 优先级分组

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 2位抢占+2位子优先级
  2. 设置不同的抢占优先级

    // 紧急按键(如复位)
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 最高抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    ​
    // 普通按键
    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 次高抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  3. 优先级规则

    • 抢占优先级高的中断可打断正在执行的低优先级中断

    • 抢占优先级相同的中断按子优先级排序,但不能互相打断。子优先级数字越小,优先级就越高~~~

3.6.3 如何在中断服务函数中实现按键长按和短按的区分?

方案设计

  1. 时间阈值法

    • 按下时记录时间戳,释放时计算持续时间

    • 超过 2 秒为长按,否则为短按

  2. 示例代码:

    static uint32_t pressTime = 0;
    static bool longPressDetected = false;
    ​
    void EXTI0_IRQHandler(void) {if(EXTI_GetITStatus(EXTI_Line0) != RESET) {if(KEY_PIN == 0) { // 按下pressTime = HAL_GetTick();longPressDetected = false;HAL_TIM_Base_Start_IT(&htim2); // 启动长按检测定时器} else { // 释放HAL_TIM_Base_Stop_IT(&htim2);if(!longPressDetected) {ShortPressCallback(); // 短按处理}}EXTI_ClearITPendingBit(EXTI_Line0);}
    }
    ​
    // 长按检测定时器回调
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {if(htim == &htim2 && KEY_PIN == 0) {if(HAL_GetTick() - pressTime > 2000) { // 2秒长按longPressDetected = true;LongPressCallback();HAL_TIM_Base_Stop_IT(&htim2);}}
    }

3.6.4 如何实现组合按键功能(同时按下多个按键)?在中断方式下有何困难?

组合按键实现

  1. 轮询方式

    void ScanKeyCombination(void) {static uint8_t keyState = 0;keyState = (KEY1 << 0) | (KEY2 << 1);switch(keyState) {case 0b00: Key1AndKey2Pressed(); break;case 0b01: Key1Pressed(); break;case 0b10: Key2Pressed(); break;}
    }
  2. 中断方式的困难

    • 时序同步问题:多个按键的中断可能不同时触发

    • 抖动叠加:多个按键同时按下时抖动可能互相影响

    • 解决方案:

      • 检测到第一个按键中断时启动定时器,在定时窗口内检测其他按键

      • 使用状态机记录各按键状态变化

3.6.5 中断方式与轮询方式检测按键各有什么优缺点?在什么场景下选择中断方式更合适?
特性中断方式轮询方式
响应速度即时响应,不受主程序影响依赖扫描周期,可能有延迟
CPU 占用空闲时不占用 CPU持续占用 CPU(即使无按键操作)
资源消耗需要配置 NVIC、EXTI 等资源仅需 GPIO 读取
实现复杂度较高(需处理中断优先级、抖动)较低(简单循环检测)
多按键处理适合少量紧急按键适合大量按键同时检测
适用场景实时性要求高(如安全关键系统)按键数量多、响应时间要求宽松

推荐使用中断的场景

  • 低功耗设计(仅在按键操作时唤醒 CPU)

  • 紧急停机、复位等关键功能

  • 要求立即响应的人机交互(如游戏控制器)

3.7 注意事项

(1) 外部中断的触发方式需要与按键接线方式一致(KEY_UP用上升沿触发,其他按键用下降沿触发)

(2) 中断服务函数中必须清除中断标志位,否则会造成中断反复触发

(3) 中断服务函数应尽量简短,避免长时间占用CPU

(4) 使用标准库函数时,需要注意头文件的包含和依赖关系

(5) GPIO和外部中断初始化前必须先使能相应的外设时钟

(6) 避免在中断服务函数中使用过长的延时函数

文章有写的不当的地方,欢迎在评论区中指正修改。如果感觉文章实用对你有帮助,欢迎点赞收藏和关注,你的点赞关注就是我动力,大家一起学习进步。

有不懂的可以在评论区里提出来哟,博主看见后会及时回答的。

http://www.dtcms.com/wzjs/347009.html

相关文章:

  • 怎么做frontpage网站今日头条seo
  • 广州外贸网站推广如何推广宣传一个品牌
  • 济南高端网站设计日本樱花免m38vcom费vps
  • 福田做棋牌网站建设多少钱百度知道电脑版网页入口
  • 网站普查建设背景怎么自己制作网站
  • 国外游戏ui设计网站河南郑州最新消息今天
  • 医院网站前置审批深圳优化公司
  • 有哪些做场景秀的网站可以商用的电视app永久软件
  • 厦门网站排名营销推广网站
  • 茂名网站建设技术托管seo 工具
  • ink域名网站如何做网站优化seo
  • 免费b站推广网站入口2020360竞价推广怎么做
  • seo营销推广平台百度seo搜索营销新视角
  • wordpress建站怎么样seo软文推广工具
  • 国家建设公债拍卖网站电商网站建设制作
  • 开网店的流程视频seo公司官网
  • 湖南电商平台网站建设泰安优化关键词排名哪家合适
  • 青岛做网站搜索关键词的方法
  • 网站图片链接怎么做的黄页推广引流网站
  • 自己建网站模板济南网站万词优化
  • 辽宁省住建厅建设网站网页设计制作网站教程
  • 桂林餐饮兼职网站建设如何做seo优化
  • 沈阳网站搭建网络营销优化推广
  • 宏润建设集团有限公司网站如何做一个自己的网页
  • 自己做的网站怎么推广网络营销促销方案
  • 免费国外网站江西seo推广软件
  • 上海网站建设套餐seo有哪些经典的案例
  • 网站病毒怎么做互联网平台有哪些
  • 营销型网站设计服务网上销售平台怎么做
  • 做私人网站nba最新消息新闻