打印
[STM32F1]

STM32 学习13 库函数实现按键检测

[复制链接]
244|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
说明

本文学习内容来自普中开发板官方学习文档。
STM32实现按键检测,可以使用扫描或中断的方式。本文采用扫描的方式来实现。
本文使用的按键电路原理图如下:



使用特权

评论回复
沙发
回复就哭哭|  楼主 | 2022-9-28 23:23 | 只看该作者

使用特权

评论回复
板凳
回复就哭哭|  楼主 | 2022-9-28 23:26 | 只看该作者
按键KEY_UP接在GPIOA端口上,其他按键连接在GPIOE上;LED接在GPIOC上。

使用特权

评论回复
地板
回复就哭哭|  楼主 | 2022-9-28 23:27 | 只看该作者
其中KEY_UP通过电阻连接到3.3v,连接到PA0口,其具有一个唤醒的功能,连接高电平有效。要判断是否按下,看其是不是高电平。初始化时设置为下拉输入。

使用特权

评论回复
5
回复就哭哭|  楼主 | 2022-9-28 23:29 | 只看该作者
而其他按键,判断按下是看其是不是低电平,初始化时设置为上拉输入。

使用特权

评论回复
6
回复就哭哭|  楼主 | 2022-9-28 23:33 | 只看该作者
要实现的功能:使能按键端口时钟初始化GPIO口 , 按键是初始化为输入模式。按键检测软件消抖,延迟50ms的软件消抖。相应LED灯亮。

使用特权

评论回复
7
回复就哭哭|  楼主 | 2022-9-28 23:35 | 只看该作者
实现要点:

通过位操作定义按键、LED灯
通过宏定义按键的引脚
程序的要点是要扫描按键,扫描

使用特权

评论回复
8
回复就哭哭|  楼主 | 2022-9-28 23:36 | 只看该作者
实现过程
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

使用特权

评论回复
9
回复就哭哭|  楼主 | 2022-9-28 23:37 | 只看该作者
system.c
#include "system.h"

1
为了对按键有反应,使用LED来响应。

使用特权

评论回复
10
回复就哭哭|  楼主 | 2022-9-28 23:38 | 只看该作者
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

使用特权

评论回复
11
回复就哭哭|  楼主 | 2022-9-28 23:38 | 只看该作者
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
}




使用特权

评论回复
12
回复就哭哭|  楼主 | 2022-9-28 23:39 | 只看该作者
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

使用特权

评论回复
13
回复就哭哭|  楼主 | 2022-9-28 23:40 | 只看该作者
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;
}


使用特权

评论回复
14
回复就哭哭|  楼主 | 2022-9-28 23:41 | 只看该作者
主函数 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);       
        }
}

使用特权

评论回复
15
回复就哭哭|  楼主 | 2022-9-28 23:42 | 只看该作者
执行效果
按下按键,看到LED显示有相应变化。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

24

主题

358

帖子

0

粉丝