文章目录
- 实验目的
- 了解擒键的工作原理及电原理图
- STM32F407中如何读取I/O的输入信号
- STM32F407对中断的编程方法
- 通过轮询实现按键捕获实验
- 如何利用已有内工程创建新工程
- 通过轮询实现按键捕获代码实现及分析
- 1 代码的流程分析
- 2 代码的实现
- Tips:下载错误的解决
实验目的
了解擒键的工作原理及电原理图
1按键功能及用途,常见按键举例
2按键的工作原理
3按键的电路表示
课后小作业:
请大家课后百度现在流行的触摸式按键的相关信息,并考虑如何使用我们开发板的CPU如何操作触摸按键。
了解STM32F407中IO输入信号读取的原理.
了解STM32F407中外部中断的原理
.学习利用CMSIS实现I/O输入信号读取的编程
.学习利用CMSIS实现外部中断的编程
简单学习工程的移植
STM32F407中如何读取I/O的输入信号
1 STM32F407如何配置I/O为输入
2 STM32F407如何读取输入信号
8.3.9输入配置
当I/O端口被编程为输入时:
•输出缓冲区被禁用
•施密特触发输入被激活
•上拉和下拉电阻被激活取决于在GPIOx_PUPDR寄存器的配置
•I/O引脚上的数据在每个AHB1时钟周期的输入数据寄存器中采样
•对输入数据寄存器的读访问提供I/O状态
图28显示了I/O端口位的输入配置。
STM32F407对中断的编程方法
12中断和事件
除非另有规定,本节适用于整个STM32F4xx系列。
12.1嵌套矢量中断控制器(NVIC)
12.1.1 NVIC特性
嵌套的矢量中断控制器NVIC包括以下特性:
•STM32F405xx/07xx和STM32F415xx/17xx的82个可屏蔽中断通道
STM32F42xxx和STM32F43xxx的最多91个可屏蔽中断通道
包括带FPU的Cortex™-M4的16条中断线)
•16个可编程优先级(使用4位中断优先级)
•低延迟异常和中断处理
•电源管理控制
•系统控制寄存器的实现
NVIC和处理器核心接口紧密耦合,从而实现低延迟
中断处理和延迟到达的中断的有效处理。
包括核心异常在内的所有中断都由NVIC管理。了解更多信息
关于异常和NVIC编程,请参见编程手册PM0214。
12.1.2 SysTick校准值寄存器
SysTick校准值固定为18750,它给出了1毫秒的参考时间基础
与SysTick时钟设置为18.75 MHz (HCLK/8,与HCLK设置为150 MHz)。
12.1.3中断和异常向量
STM32F405xx/07xx的矢量表见表62和表62
STM32F415xx/17xx和STM32F42xxx和STM32F43xxx设备。
12.2外部中断/事件控制器(EXTI)
外部中断/事件控制器由多达23个边缘检测器组成,用于生成
事件/中断请求。每条输入线都可以独立配置选择类型
(中断或事件)和相应的触发事件(上升或下降或两者)。每一行也可以独立遮罩。暂挂寄存器维护中断的状态行请求
12.2.1 EXTI的主要特性
EXTI控制器的主要特性如下:
•在每个中断/事件线上独立触发和掩码
•每个中断线的专用状态位
•生成多达23个软件事件/中断请求
•检测脉冲宽度低于APB2时钟周期的外部信号。请参考有关这方面的详细信息,请参阅STM32F4xx数据表的电气特性部分参数。
12.2.3唤醒事件管理
STM32F4xx能够处理外部或内部事件,以唤醒核心(WFE)。
唤醒事件可以通过以下方式生成:
在外设控制寄存器中使能中断,但不在NVIC中使能Cortex™-M4具有FPU系统控制寄存器的SEVONPEND位。当MCU从WFE、外设中断暂挂位和外设NVIC恢复
IRQ通道挂起位(在NVIC中断中清除挂起寄存器)必须是清除。
或在事件模式下配置外部或内部EXTI线路。CPU恢复时从WFE,不需要清除外设中断挂起位或NVIC IRQ通道挂起位作为挂起位对应的事件行未设置。
要使用外接线路作为唤醒事件,请参阅章节12.2.4:功能描述。
12.2.4功能介绍
为了生成中断,应该配置并启用中断线。完成了通过编程的两个触发寄存器与所需的边缘检测和使能
通过在中断掩码寄存器的相应位上写一个“1”来中断请求。
当选择的边缘出现在外部中断线上时,中断请求是生成的。与中断线对应的挂起位也被设置。这个请求是
通过在挂起寄存器中写入' 1 '来重置。
要生成事件,应该配置并启用事件行。这是由编程两个触发寄存器与所需的边缘检测和启用
通过向事件掩码寄存器中相应的位写入' 1 '来发送事件请求。当所选边缘发生在事件线上,则产生事件脉冲。挂起位
没有设置对应的事件行。
中断/事件请求也可以由软件通过在软件中写入' 1 '来生成中断/事件寄存器。
12.2.5外部中断/事件行映射
多达140个gpio (STM32F405xx/07xx和STM32F415xx/17xx), 168个gpio
(STM32F42xxx和STM32F43xxx)连接到16外部中断/事件线
以下方式:
图42 外部中断/事件GPIO映射(STM32F405xx/07xx)和STM32F415xx/17xx)
- 初始化中断源
- 使能中断源
- 中断服务程序的实现(interrupt handler) 例程中是Weak声明,可以进行重写或实现
通过轮询实现按键捕获实验
如何利用已有内工程创建新工程
将led工程下的所有文件拷贝至试验2.1通过轮询实现按键的检测目录中。
修改工程名称为:key_pull_test,并打开:
修改工程树上的根目录名称为:key_pull_test
新建F:\IOT\PRJ\按键试验2.1通过轮询\code\drivers\key目录,复制led.c和led.h,并改名为key.c和key.h:
查看已定义常量的定义可跳转:
keil的drivers目录中添加led.c和key.c,后期都要使用,并在option中增加头文件的路径:
接下来修改源代码。
通过轮询实现按键捕获代码实现及分析
1 代码的流程分析
编写代码框架:
//创建及修改说明
//V1.o创建第一个按键检测实验主程序代码﹑通过轮询的方式实现按键的检测
#include "systick.h"
#include "stm32f4xx.h"
#include "led.h"
#define SYS_MAX_CLK 12
#define DELAY_1S 1000
int main(void)
{
uint16_t key0_press = KEY_UP;
LED0_Init();//初始化LEDO
delay_init(SYS_MAX_CLK);//初始化系统时钟
Key_Init();
while(1)
{
if(KEY_PRESS==Detect_key(KEY0_PIN))//查询按键key0(PE4)的状态
{
Led_Ctrl(LED0_PIN_ROW,LED0_PIN,LED_ON); //如果按键按下,点灯
key0_press = KEY_PRESS;
}
delay_ms(200); //在延时(200ms)后,如果按键按下标志有效,关灯
if(key0_press == KEY_PRESS)
{
Led_Ctrl(LED0_PIN_ROW,LED0_PIN,LED_OFF);
}
}
}
2 代码的实现
在key.h中实现有关定义:
#ifndef __KEY_H
#define __KEY_H
#include "stm32f4xx.h"
#include "systick.h"
#include "stm32f4xx_hal_rcc.h"
#include "stm32f4xx_hal_gpio.h"
#define KEY0_PIN GPIO_PIN_4
#define KEY1_PIN GPIO_PIN_3
#define KEY2_PIN GPIO_PIN_2
#define KEY_PRESS GPIO_PIN_RESET //枚举变量,0,低电平
#define KEY_UP GPIO_PIN_SET //枚举变量,弹起时弱上拉,高电平
void Key_Init(void);//初始化
uint16_t Detect_key(uint16_t key_pin);
#endif
在stm32f4xx_hal_gpio.h中定义了枚举变量:
#define KEY_PRESS GPIO_PIN_RESET //枚举变量,0,低电平
#define KEY_UP GPIO_PIN_SET //枚举变量,弹起时弱上拉,高电平
key.C的代码:
#include <stdlib.h>
#include "key.h"
void Key_Init(void)
{
GPIO_InitTypeDef gpio_info;
gpio_info.Pin = KEY0_PIN | KEY1_PIN; //KEY0_PIN,KEY1_PIN同时初始化
gpio_info.Mode = GPIO_MODE_INPUT; //由定义跳转,改成输入状态
gpio_info.Speed = GPIO_SPEED_FREQ_MEDIUM; //其他参数采用复位值即可
gpio_info.Pull = GPIO_PULLUP;
__GPIOE_CLK_ENABLE(); //stm32_hal_legacy.h中有:#define __GPIOE_CLK_ENABLE __HAL_RCC_GPIOE_CLK_ENABLE
HAL_GPIO_Init(GPIOE, &gpio_info);
}
uint16_t Detect_key(uint16_t key_pin)
{
uint16_t ret = KEY_UP;
if(KEY_PRESS==HAL_GPIO_ReadPin(GPIOE,key_pin)) //GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
delay_ms(10);//延时10mS去抖动
if(KEY_PRESS==HAL_GPIO_ReadPin(GPIOE,key_pin))
{
ret = KEY_PRESS;
}
}
return ret;
}
test.C的代码:
//创建及修改说明
//V1.o创建第一个按键检测实验主程序代码﹑通过轮询的方式实现按键的检测
#include "systick.h"
#include "stm32f4xx.h"
#include "key.h"
#include "led.h"
#define SYS_MAX_CLK 12
#define DELAY_1S 1000
int main(void)
{
uint16_t key0_press = KEY_UP;
LED0_Init();//初始化LEDO
delay_init(SYS_MAX_CLK);//初始化系统时钟
Key_Init();
while(1)
{
if(KEY_PRESS==Detect_key(KEY0_PIN))//查询按键key0(PE4)的状态
{
Led_Ctrl(LED0_PIN_ROW,LED0_PIN,LED_ON); //如果按键按下,点灯
key0_press = KEY_PRESS;
}
delay_ms(200); //在延时(200ms)后,如果按键按下标志有效,关灯
if(key0_press == KEY_PRESS)
{
Led_Ctrl(LED0_PIN_ROW,LED0_PIN,LED_OFF);
}
}
}
Tips:下载错误的解决
当默认设置内存大小不足时,会出现如下错误:
解决方法:调整配置内存大小:
实验现象:按下亮灯,松手关灯。