原创 STM32 学习13 库函数实现按键检测
Posted 编程圈子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原创 STM32 学习13 库函数实现按键检测相关的知识,希望对你有一定的参考价值。
一、说明
本文学习内容来自普中开发板官方学习文档。
STM32实现按键检测,可以使用扫描或中断的方式。本文采用扫描的方式来实现。
本文使用的按键电路原理图如下:
- 按键KEY_UP接在GPIOA端口上,其他按键连接在GPIOE上;LED接在GPIOC上。
- 其中KEY_UP通过电阻连接到3.3v,连接到PA0口,其具有一个唤醒的功能,连接高电平有效。要判断是否按下,看其是不是高电平。初始化时设置为下拉输入。
- 而其他按键,判断按下是看其是不是低电平,初始化时设置为上拉输入。
要实现的功能:
- 使能按键端口时钟
- 初始化GPIO口 , 按键是初始化为输入模式。
- 按键检测
- 软件消抖,延迟50ms的软件消抖。
- 相应LED灯亮。
实现要点:
- 通过位操作定义按键、LED灯
- 通过宏定义按键的引脚
- 程序的要点是要扫描按键,扫描
二、实现过程
1. 按键接口定义
system.h
#ifndef _system_H
#define _system_H
#include "stm32f10x.h"
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C
#define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808
#define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入
#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入
#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入
#endif
system.c
#include "system.h"
为了对按键有反应,使用LED来响应。
led.h
#ifndef _led_H
#define _led_H
#include "system.h"
/* LED时钟端口、引脚定义 */
#define LED_PORT GPIOC
#define LED_PIN (GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7)
#define LED_PORT_RCC RCC_APB2Periph_GPIOC
#define led1 PCout(0)
#define led2 PCout(1)
#define led3 PCout(2)
void LED_Init(void);
#endif
led.c
#include "led.h"
/*******************************************************************************
* 函 数 名 : LED_Init
* 函数功能 : LED初始化函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void LED_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量
RCC_APB2PeriphClockCmd(LED_PORT_RCC,ENABLE);
GPIO_InitStructure.GPIO_Pin=LED_PIN; //选择你要设置的IO口
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //设置推挽输出模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置传输速率
GPIO_Init(LED_PORT,&GPIO_InitStructure); /* 初始化GPIO */
GPIO_SetBits(LED_PORT,LED_PIN); //将LED端口拉高,熄灭所有LED
}
key.h
#ifndef _key_H
#define _key_H
#include "system.h"
// 下面宏定义主要用在引脚初始化
#define KEY_LEFT_Pin GPIO_Pin_2 //定义K_LEFT管脚
#define KEY_DOWN_Pin GPIO_Pin_3 //定义K_DOWN管脚
#define KEY_RIGHT_Pin GPIO_Pin_4 //定义K_RIGHT管脚
#define KEY_UP_Pin GPIO_Pin_0 //定义KEY_UP管脚
#define KEY_Port (GPIOE) //定义其他按键端口
#define KEY_UP_Port (GPIOA) //定义KEY_UP按键端口
// 下面使用位操作和库函数 选择其中一种即可。作用是用来读取按键值
//使用位操作定义
#define K_UP PAin(0)
#define K_DOWN PEin(3)
#define K_LEFT PEin(2)
#define K_RIGHT PEin(4)
//使用读取管脚状态库函数定义
//#define K_UP GPIO_ReadInputDataBit(KEY_UP_Port,KEY_UP_Pin)
//#define K_DOWN GPIO_ReadInputDataBit(KEY_Port,KEY_DOWN_Pin)
//#define K_LEFT GPIO_ReadInputDataBit(KEY_Port,KEY_LEFT_Pin)
//#define K_RIGHT GPIO_ReadInputDataBit(KEY_Port,KEY_RIGHT_Pin)
//定义各个按键值
#define KEY_UP 1
#define KEY_DOWN 2
#define KEY_LEFT 3
#define KEY_RIGHT 4
void KEY_Init(void);
u8 KEY_Scan(u8 mode);
#endif
key.c
#include "key.h"
#include "SysTick.h"
/*******************************************************************************
* 函 数 名 : KEY_Init
* 函数功能 : 按键初始化
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);
GPIO_InitStructure.GPIO_Pin=KEY_UP_Pin; //选择你要设置的IO口
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;//下拉输入
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置传输速率
GPIO_Init(KEY_UP_Port,&GPIO_InitStructure); /* 初始化GPIO */
GPIO_InitStructure.GPIO_Pin=KEY_DOWN_Pin|KEY_LEFT_Pin|KEY_RIGHT_Pin;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //上拉输入
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(KEY_Port,&GPIO_InitStructure);
}
/*******************************************************************************
* 函 数 名 : KEY_Scan
* 函数功能 : 按键扫描检测
* 输 入 : mode=0:单次按下按键
mode=1:连续按下按键
* 输 出 : 0:未有按键按下
KEY_UP:K_UP键按下
KEY_DOWN:K_DOWN键按下
KEY_LEFT:K_LEFT键按下
KEY_RIGHT:K_RIGHT键按下
*******************************************************************************/
u8 KEY_Scan(u8 mode)
{
static u8 key=1;
if(key==1&&(K_UP==1||K_DOWN==0||K_LEFT==0||K_RIGHT==0)) //任意一个按键按下
{
delay_ms(10); //消抖
key=0;
// 下面判断到底哪个按键被按下
if(K_UP==1)
{
return KEY_UP;
}
else if(K_DOWN==0)
{
return KEY_DOWN;
}
else if(K_LEFT==0)
{
return KEY_LEFT;
}
else
{
return KEY_RIGHT;
}
}
else if(K_UP==0&&K_DOWN==1&&K_LEFT==1&&K_RIGHT==1) //无按键按下
{
key=1;
}
if(mode==1) //连续按键按下
{
key=1;
}
return 0;
}
主函数 main.c
main.c
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
int main()
{
u8 key,i;
SysTick_Init(72);
LED_Init();
KEY_Init();
while(1)
{
key=KEY_Scan(0); //扫描按键
switch(key)
{
case KEY_UP: led2=0;break; //按下K_UP按键 点亮D2指示灯
case KEY_DOWN: led2=1;break; //按下K_DOWN按键 熄灭D2指示灯
case KEY_LEFT: led3=1;break; //按下K_LEFT按键 点亮D3指示灯
case KEY_RIGHT: led3=0;break; //按下K_RIGHT按键 熄灭D3指示灯
}
// 200ms闪烁一次led1
i++;
if(i%20==0)
{
led1=!led1; //LED1状态取反
}
delay_ms(10);
}
}
三、执行效果
按下按键,看到LED显示有相应变化。
以上是关于原创 STM32 学习13 库函数实现按键检测的主要内容,如果未能解决你的问题,请参考以下文章
STM32_按键_外部中断_定时器扫描_循环扫描_FIFO机制