基于正点原子miniSTM32开发板、STM32RCT6、库函数
一、硬件原理
按键 KEY0连接在 PC5 上、KEY1 连接在 PA15 上、WK_UP 连接在 PA0 上。KEY0 和 KEY1 是低电平有效的,而 WK_UP 是高电平有效的,除了KEY1 有上拉电阻,其他两个都没有上下拉电阻,所以,需要在 STM32 内部设置上下拉。
二、软件设计
1、static变量
(1)static申明的是局部变量,存储在静态存储区。
(2)它在函数调用结束后不会被释放,值会一直被保留下来
(3)用static申明的变量具有记忆功能。
2、KEY.H
#ifndef __KEY_H
#define __KEY_H
#include <sys.h>
#define KEY0 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)
#define KEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)
#define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define KEY0_PRES 1 //KEY0
#define KEY1_PRES 2 //KEY1
#define WKUP_PRES 3 //WK_UP
void KEY_Init(void);
u8 KEY_Scan(u8 mode);
#endif
KEY0、 KEY1、WK_UP3个宏定义用于申明他们所对应的IO口的位;KEY0_PRES、 KEY1_PRES 、WKUP_PRES 3 个宏定义用于申明他们所对应的按键按下时KEY_Scan所返回的值。
3、KEY.C
#include <KEY.H>
#include <delay.h>
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//PA15
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//PC5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//PA0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
u8 KEY_Scan(u8 mode)
{
static u8 key_up = 1;
if(mode) key_up = 1;
if(key_up && (KEY0 == 0 || KEY1 == 0 || WK_UP == 1))
{
delay_ms(10);
key_up = 0;
if(KEY0 == 0 ) return KEY0_PRES;
else if(KEY1 == 0) return KEY1_PRES;
else if(WK_UP == 1) return WKUP_PRES;
}else if(KEY0 == 1 && KEY1 == 1 && WK_UP == 0) key_up = 1;
return 0;
}
(1)KEY_Init 是用来初始化按键输入的 IO 口的, PA0、PA15 和 PC5 输入设置,GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);这个函数,用于禁止 JTAG,开启 SWD,因为 PA15 占用了 JTAG 的一个 IO,所以要禁止 JTAG,从而让 PA15 用作普通 IO输入。
(2)KEY_Scan 函数,则是用来扫描这 3 个 IO 口是否有按键按下。KEY_Scan 函数,支持两种扫描方式,通过 mode 参数来设置。
1).当 mode 为 0 的时候,KEY_Scan 函数将不支持连续按,扫描某个按键,该按键按下之后必须要松开,才能第二次触发,否则不会再响应这个按键,这样的好处就是可以防止按一次多次触发,而坏处就是在需要长按的时候就不合适了。
2).当 mode 为 1 的时候,KEY_Scan 函数将支持连续按,如果某个按键一直按下,则会一直返回这个按键的键值,这样可以方便的实现长按检测。
因为该函数里面有 static 变量,所以该函数不是一个可重入函数,该函数的按键扫描是有优先级的,最优先的是 KEY0,第二优先的是 KEY1,最后是 WK_UP 按键。该函数有返回值,如果有按键按下,则返回相应的值,如果没有或者按键不正确,则返回 0。
4、main.c
#include <LED.H>
#include "delay.h"
#include "sys.h"
#include "KEY.H"
int main(void)
{
u8 t=0;
delay_init();
LED_Init();
KEY_Init();
LED0 = 0;
while(1)
{
t=KEY_Scan(0);
switch(t)
{
case KEY0_PRES:
LED0 = !LED0;
break;
case KEY1_PRES:
LED1 = !LED1;
break;
case WKUP_PRES:
LED0 = !LED0;
LED1 = !LED1;
break;
default:
delay_ms(10);
}
}
}
先点亮LED0,按键扫面方式采用不支持连续按模式;当KEY0按下时,LED0取反, KEY1按下时LED1取反, WKUP按下时LED0,LED1同时取反。