STM32学习笔记4——按键

在学习了GPIO和SYSTICK之后,我来开始按键的操作,其中按键的控制可以分为两种情况:按键扫描和按键中断。按键扫描是用cpu对按键的情况进行不断扫描,检测到按键变化执行按键控制。按键中断是一但出现IO口的变化就触发中断,执行中断内的程序。相比按键扫描,按键中断可以大幅节省cpu效率。
下面我就开始进行按键实验。
首先,我们找到按键的位置,按照官方给的PCB文件可以容易的找到
这里写图片描述
按键是被挂在PC13管脚上的,根据以前我们的经验我们已经能控制LED灯的亮灭了,所以,今天控制按键就用LED的亮灭表示,按键时LED的亮灭反转。关于GPIO控制LED的方法:点这里

  • 按键扫描

按键扫描就只是多了一个检测按键的函数,一旦检测到按键变化就对其进行LED的的反转。关于按键的函数如下:

#include "KEY.h"

void Key_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;    
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_PuPd =  GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_ResetBits(GPIOC ,GPIO_Pin_13);
}

void Delay(uint32_t uCount)
{
    for(;uCount>0;uCount--);
}

uint8_t KeyDown(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
    if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)==0)//检测按键是否被按下
    {   Delay(1000);   //消抖
        if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)==0)
        {
            while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)==0);//等待按键释放
          return 0;
        }
        else 
            return 1;
    }
    else 
        return 1;

}

此函数可以对按键的IO口进行配置,并对按键状态不断扫描,检测按键的状态,通过主函数对其调用就可以实现按键的扫描并进行反转LED。
主函数:

#include "stm32f0xx.h"
#include "KEY.h"
#include "LED.h"
#include "main.h"
int main(void)
{
    Led_Init();
    Key_Init();
    GPIO_ResetBits(GPIOA,GPIO_Pin_5);

  while (1)
  {
            if(KeyDown(GPIOC,GPIO_Pin_13)==0)
            {
                GPIO_WriteBit(GPIOA, GPIO_Pin_5  , 
                     (BitAction)((1-GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_5))));
            }
  }
}

这是实现按键反转LED的一种方法。

  • 外部中断
    中断是指由于接收到来自外围硬件(相对于中央处理器和内存)的异步信号或来自软件的同步信号,而进行相应的硬件/软件处理。发出这样的信号称为进行中断请求(interrupt request,IRQ)。硬件中断导致处理器通过一个上下文切换(context switch)来保存执行状态(以程序计数器和程序状态字等寄存器信息为主);软件中断则通常作为CPU指令集中的一个指令,以可编程的方式直接指示这种上下文切换,并将处理导向一段中断处理代码。中断在计算机多任务处理,尤其是实时系统中尤为有用,这样的系统,包括运行于其上的操作系统,也被称为“中断驱动的”。简单的来说就比如某个人正在做某事,突然来了个电话,他就要停下手中的事情去接电话,中断相当于这个电话。触发中断后跳出原来运行的程序去执行中断处理。
    下面我们来写一下这个外部中断程序:
#include "exti.h"

void EXTI_KEY_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    EXTI_InitTypeDef EXTI_InitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC,ENABLE);  

    NVIC_InitStruct.NVIC_IRQChannel=EXTI4_15_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority=1;
  NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    GPIO_InitStruct.GPIO_Pin=13;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN;
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_Level_2;
    GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
    GPIO_Init(GPIOC,&GPIO_InitStruct);

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC,EXTI_PinSource13);
   EXTI_InitStruct.EXTI_Line=EXTI_Line13;
    EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
    EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
    EXTI_InitStruct.EXTI_LineCmd=ENABLE;
    EXTI_Init(&EXTI_InitStruct);
}

主函数:

#include "main.h"
#include "LED.h"
#include "exti.h"
int main(void)
{
  SystemInit();
    Led_Init();
    GPIO_ResetBits(GPIOA ,GPIO_Pin_5);
    EXTI_KEY_Init();

  while (1)
  {

  }
}

stm32f0xx_it.c中的中断配置函数:

void EXTI4_15_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line13)!=RESET)
    {
        GPIO_WriteBit(GPIOA, GPIO_Pin_5  , 
                     (BitAction)((1-GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_5))));
        EXTI_ClearFlag(EXTI_Line13);
    }
}

现在让我们来看一下这个程序,在外部中断函数中,我们首先要对外部中断用到的按键所连接的GPIO端口和管理连接到 GPIO 口的外部中断的SYSCFG的时钟打开,然后对嵌套向量中断控制器 (NVIC)进行设置。
  由于在STM32的库函数中有stm32f0xx_misc.h的第54行有如下定义:
  

typedef struct
{
  uint8_t NVIC_IRQChannel;          
  uint8_t NVIC_IRQChannelPriority;    
  FunctionalState NVIC_IRQChannelCmd;                                             
} NVIC_InitTypeDef;

这个结构体对NVIC的配置通道和优先级及使能进行了定义,设置中断通道为4—15通道,优先级为1,使能通道。然后对按键的GPIO进行定义,设置为上拉输入,再对EXTI进行操作,和NVIC一样,在stm32f0x_exti.h的第79行也有如下定义:

typedef struct
{
  uint32_t EXTI_Line;             
  EXTIMode_TypeDef EXTI_Mode;    
  EXTITrigger_TypeDef EXTI_Trigger; 
  FunctionalState EXTI_LineCmd;  
}EXTI_InitTypeDef;

由图可知
这里写图片描述
配置为外部中断线程为13,模式为外部中断,下降沿中断,并且在SYSCFG中有管理连接到 GPIO 口的外部中断的功能,所以在函数:

void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex)
{
  uint32_t tmp = 0x00;

  /* Check the parameters */
  assert_param(IS_EXTI_PORT_SOURCE(EXTI_PortSourceGPIOx));
  assert_param(IS_EXTI_PIN_SOURCE(EXTI_PinSourcex));

  tmp = ((uint32_t)0x0F) << (0x04 * (EXTI_PinSourcex & (uint8_t)0x03));
  SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] &= ~tmp;
  SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] |= (((uint32_t)EXTI_PortSourceGPIOx) << (0x04 * (EXTI_PinSourcex & (uint8_t)0x03)));
}

中可以对EXTICR寄存器进行操作,打开对应管脚的外部中断。

主函数很简单。在此不多做解释。

在解释下stm32f0xx_it.c中的中断配置函数,中断配置函数必须和.s文件中的函数一致,不能改动,笔者在此吃了很大的亏,由于和.s文件中的函数不一样,不能进入中断,系统只能将其作为一个普通函数,不具有中断功能,切记!!!在函数中一旦读取中断通道变化,就会对LED进行反转,实现按键中断。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值