按键–在众多外设中也是仅此于led的最基本的、简单的外设。
在本文介绍两种方法进行按键的驱动(中断、循环扫描)。
对于中断不懂的可以看下我另外一篇文章:STM32中断
蓝桥杯嵌入式的板子里面有四个按键,在原理图上我们可以看出当GPIO输入为低电平时导通。连接的IO口为PA0、PA8、PB1、PB2四个口。
1、循环扫描
key.c
#include "key.h"
#include "lcd.h"
void key_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_8;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_1;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
}
unsigned char key_scanf(void)
{
unsigned char key_but=0;
if(key0==0||key1==0||key2==0||key3==0)
{
Delay_LCD(100);
if(key0==0) key_but=1;
if(key1==0) key_but=2;
if(key2==0) key_but=3;
if(key3==0) key_but=4;
}
return key_but;
}
key.h
#include "stm32f10x.h"
#define key0 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define key1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)
#define key2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)
#define key3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2)
void key_init(void);
unsigned char key_scanf(void);
在key_scanf()函数上我们可以看出当检测到第一个按键按下的时候,函数返回1;检测到第二个按键按下的时候,函数返回2,以此类推。
因此我们用扫描的方法的时候,我们要一个中间存储按键的值进行操作。例如:
unsigned char key_val;
int main(void)
{
key_init();
....
while(1)
{
key_val=key_scanf();
if(key_val==1) //检测到第一个按键按下
{
......... //要执行的操作
}
if(key_Val==2) //第二个按键按下
{
.........
}
...........
}
}
2、中断
#include "key.h"
#include "lcd.h"
void key_Init()
{
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
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_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource8);
EXTI_InitStructure.EXTI_Line = EXTI_Line8;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
EXTI_InitStructure.EXTI_Line = EXTI_Line1;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource2);
EXTI_InitStructure.EXTI_Line = EXTI_Line2;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void EXTI0_IRQHandler(void)
{
Delay_LCD(100);
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
void EXTI9_5_IRQHandler(void)
{
Delay_LCD(100);
if(EXTI_GetITStatus(EXTI_Line8) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line8);
}
}
void EXTI1_IRQHandler(void)
{
Delay_LCD(100);
if(EXTI_GetITStatus(EXTI_Line1) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line1);
}
}
void EXTI2_IRQHandler(void)
{
Delay_LCD(100);
if(EXTI_GetITStatus(EXTI_Line2) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line2);
}
}
在中断上,我们就没有扫描这个环节,我们可以直接在中断里面执行按键的操作。但我们使能中断后要对按键进行操作的时候要加上中断服务函数,并且中断服务函数不能写错,不然会执行不了中断。虽然编译时没问题的,但就是执行不了中断。
例:
void EXTI0_IRQHandler(void)
{
Delay_LCD(100);
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
.......... //这里编写第一个按键按下要进行的操作
EXTI_ClearITPendingBit(EXTI_Line0);
}
}