2019蓝桥杯嵌入式寒假学习记录(2)中断与按键
这几天我又接着学习了中断和按键的知识,感觉上手还是挺慢的,但是快的话理解方面会有一些欠缺,学习感觉还是要抓住本质应该建立在理解的基础上这样以后才能用的更加熟练和自信。中断是很重要的一个知识点,因为有了中断就可以实现只有事件发生的时候才去处理不用一直去占用cpu,而可以去做其他任务,当中断来到时再去处理,提高工作效率。对于按键的学习刚好可以分为两种方式;1.循环刷新2.中断响应,下面会分别介绍这两种方法。
中断
中断包括系统异常和外部中断,而我们大部分用的外设都使用外部中断,在stm32f10x.h这个头文件中可以查询到在IRQn_Type这个结构体里面包含了F103系列全部的异常声明。NVIC是嵌套向量中断控制器。控制着整个芯片的中断的相关功能,是内核里面的一个外设。中断优先级,F103使用4位表达优先级,又被分分成抢占优先级和子优先级,抢占优先级高的优先执行,如果抢占优先级相同,就比较他们的子优先级。设置优先级分组调用库函数NVIC_PriorityGroupConfig()实现,有关NVIC中断相关的库函数在misc.c和.h中。如果要使用外部中断的话,只配置NVIC是不行的,还要配置EXTi叫做外部中断事件控制器,要想实现外部中断响应还要配置EXTI,EXTI有20个中断事件先,每个GPIO都可以被设置为输入线,占用EXTI0-15,另外7个其他用途。初始化结构体在stm30f10x_exti.h中。最后写中断服务函数在stm32f10x_it.c中写中断服务函数,每个中断都有特殊的函数名,在期待那个文件starup_stm32f10x_hd.s中查找,总的中断设置流程如下;
- 配置GPIO,打开时钟
- 配置NVIC优先级分组,初始化结构体
- 配置EXTI信号源,初始化结构体
- 写中断服务函数
代码实现
#include"key.c"
---------------------------------------------------------------------------------------
#include"key.h"
void Key_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//打开与LED相关的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//初始化按键GPIO
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//初始化NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel =EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//初始化EXTI
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
#include"key.h"
---------------------------------------------------------------------------------------
#ifndef _KEY_H
#define _KEY_H
#include"stm32f10x.h"
#define KEY1 GPIO_Pin_0;
#define KEY2 GPIO_Pin_8;
#define KEY3 GPIO_Pin_1;
#define KEY4 GPIO_Pin_2;
void Key_Init(void);
#endif
---------------------------------------------------------------------------------------
中断服务函数stm32f10x_it.c
extern uint32_t TimingDelay;
extern uint8_t EXTI_Status;
extern void Delay_Ms(uint32_t nTime);
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0)!= RESET)
{
EXTI_Status=1;
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
---------------------------------------------------------------------------------------
#include"led.h"
#include"key.h"
uint32_t TimingDelay=0;
uint8_t EXTI_Status=0;
void Delay_Ms(uint32_t nTime);
int main()
{
SysTick_Config(SystemCoreClock/1000); //配置系统时钟
LED_Init();//初始化LED
Key_Init(); //初始化按键
while(1)
{
LED_Control(LED1,on);
Delay_Ms(500);
LED_Control(LED1,off);
Delay_Ms(500);
if(EXTI_Status==1)//中断响应LED2亮
{
LED_Control(LED2,on);
EXTI_Status=0;
}
}
}
void Delay_Ms(uint32_t nTime)
{
TimingDelay=nTime;
while(TimingDelay!=0);
}
按键循环扫描
按键的要掌握的点有两个,一个事按键去抖动,另一个是按键的循环扫秒。先来讨论一下这两个问题,什么是按键消抖,其实就是按键的机械的上下震荡,由于32工作速度很快,当你按下去的时候产生的抖动会多次就行触发影响按键效果。按键扫描就是每隔一定的时间间隔对按键的寄存器进行查询,判断按键是否被按下。
代码实现
#include"key.c"
---------------------------------------------------------------------------------------
#include"key.h"
extern void Delay_Ms(u32 nTime);
void Key_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
//打开与LED相关的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
//key1
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0; //选择控制GPIO引脚
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //引脚设为通用推挽输出
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置引脚速录为50MHZ
GPIO_Init(GPIOA,&GPIO_InitStructure); //调用库函数,初始化GPIO
//key2
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8; //选择控制GPIO引脚
// GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //引脚设为通用推挽输出
// GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置引脚速录为50MHZ
GPIO_Init(GPIOA,&GPIO_InitStructure); //调用库函数,初始化GPIO
//key3
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1; //选择控制GPIO引脚
// GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //引脚设为通用推挽输出
// GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置引脚速录为50MHZ
GPIO_Init(GPIOB,&GPIO_InitStructure); //调用库函数,初始化GPIO
//key4
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2; //选择控制GPIO引脚
// GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //引脚设为通用推挽输出
// GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置引脚速录为50MHZ
GPIO_Init(GPIOB,&GPIO_InitStructure); //调用库函数,初始化GPIO
}
void Key_Scan()
{
static u16 key1_sum,key2_sum,key3_sum,key4_sum;
if(KEY1 == 0)
{
Delay_Ms(10);//延时消抖
if(KEY1 == 0)
{
key1_sum ++;
if(key1_sum==1) //每按一次按键LED1取反一次
{
GPIOC->ODR ^= (1<<8);
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
}
if(key1_sum == 40) //长按2s以上LED以0.5s闪烁
{
GPIOC->ODR ^= (1<<8);
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
key1_sum = 30;
}
}
}
else
{
key1_sum = 0;
}
if(KEY2 == 0)
{
key2_sum ++;
if(key2_sum == 1) //每按一次按键2,LED2取反一次
{
GPIOC->ODR ^= (1<<9);
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
}
}else
{
key2_sum = 0;
}
if(KEY3 == 0)
{
key3_sum ++;
if(key3_sum == 1) //每按一次按3,LED3取反一次
{
GPIOC->ODR ^= (1<<10);
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
}
}else
{
key3_sum = 0;
}
if(KEY4 == 0)
{
key4_sum ++;
if(key4_sum == 1) //每按一次按,4,LED4取反一次
{
GPIOC->ODR ^= (1<<11);
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
}
}else
{
key4_sum = 0;
}
}
--------------------------------------------------------------------------------------------------------------------
#ifndef _KEY_H
#define _KEY_H
#include"stm32f10x.h"
#define KEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define KEY2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)
#define KEY3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)
#define KEY4 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2)
void Key_Init(void);
void Key_Scan(void);
#endif
---------------------------------------------------------------------------------------
main.c
#include"stm32f10x.h"
#include"core_cm3.h"
#include "misc.h"
#include"key.h"
#include"led.h"
u32 TimingDelay = 0;
u8 KEY_Flag = 0;
int main()
{
LED_Init();
Key_Init();
SysTick_Config(SystemCoreClock/1000);
while(1)
{
if(KEY_Flag) //按键读取
{
KEY_Flag = 0;
Key_Scan();
}
}
}
void Delay_Ms(u32 nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
(以上是本人个人观点,如有错误欢迎交流QQ:1186672409,Mr.shi)