打印
[应用相关]

GPIO输入-按键控制LED核心代码(固件库版)

[复制链接]
481|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
自动化陈稳|  楼主 | 2021-4-26 22:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
上次我们讲解了操作STM32的GPIO-输出的3种方法和关键代码,这节我们讲关于GPIO按键输入的关键要点,分为按键(查询/中断)两种方法讲解相关的核心代码。
编程要点:(查询方法)
1. 使能 GPIO 端口时钟;
2. 初始化 GPIO 目标引脚为输入模式(浮空输入);
3. 编写按键检测程序,检测按键的状态,实现按键控制 LED 灯;



使用特权

评论回复
沙发
自动化陈稳|  楼主 | 2021-4-26 22:23 | 只看该作者
/*=====================key.h=======================*/
#ifndef __KEY_H
#define        __KEY_H


#include "stm32f10x.h"

//Key 引脚定义
#define    KEY1_GPIO_CLK     RCC_APB2Periph_GPIOA
#define    KEY1_GPIO_PORT    GPIOA
#define    KEY1_GPIO_PIN         GPIO_Pin_0

#define KEY_ON        1 //按键按下
#define KEY_OFF        0 //按时松开

void Key_GPIO_Config(void);
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);


#endif /* __KEY_H */

/*=====================key.c=======================*/

#include "key.h"  

void Key_GPIO_Config(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
       
        /*开启按键端口的时钟*/
        RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK,ENABLE);
        //选择按键Key1的引脚
        GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;
        // 设置按键Key1的引脚为浮空输入
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        //使用结构体初始化按键
        GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);
}
/*====================按键检测函数===================*/
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{                       
        /*检测是否有按键按下 */
        if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )  
        {         
                /*等待按键释放 */
                while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);   
                return         KEY_ON;         
        }
        else
                return KEY_OFF;
}

使用特权

评论回复
板凳
自动化陈稳|  楼主 | 2021-4-26 22:24 | 只看该作者
/*=====================led.h=======================*/
#ifndef __LED_H
#define        __LED_H

#include "stm32f10x.h"

#define LED_GPIO_PORT            GPIOB /* GPIO端口 */
#define LED_GPIO_CLK             RCC_APB2Periph_GPIOB/* GPIO端口时钟 */
#define LED_GPIO_PIN                  GPIO_Pin_5 /* 连接到SCL时钟线的GPIO */

#define ON  0 //亮
#define OFF 1 //灭

#define LED(a)        if (a)        \
                                        GPIO_SetBits(LED_GPIO_PORT,LED_GPIO_PIN);\
                                        else                \
                                        GPIO_ResetBits(LED_GPIO_PORT,LED_GPIO_PIN)
                                        void LED_GPIO_Config(void);

#endif /* __LED_H */

/*=====================led.c=======================*/
#include "led.h"   

void LED_GPIO_Config(void)
{               
                /*定义一个GPIO_InitTypeDef类型的结构体*/
                GPIO_InitTypeDef GPIO_InitStructure;

                /*开启LED相关的GPIO外设时钟*/
                RCC_APB2PeriphClockCmd( LED_GPIO_CLK , ENABLE);
                /*选择要控制的GPIO引脚*/
                GPIO_InitStructure.GPIO_Pin = LED_GPIO_PIN;       

                /*设置引脚模式为通用推挽输出*/
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   

                /*设置引脚速率为50MHz */   
                GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

                /*调用库函数,初始化GPIO*/
                GPIO_Init(LED_GPIO_PORT, &GPIO_InitStructure);       
                /* 关闭led灯        */
                GPIO_SetBits(LED_GPIO_PORT, LED_GPIO_PIN);
}

使用特权

评论回复
地板
自动化陈稳|  楼主 | 2021-4-26 22:25 | 只看该作者
/*=====================main.c=======================*/
#include "stm32f10x.h"   
#include "led.h"
#include "key.h"

int main(void)
{
        //初始化LED的GPIO
        LED_GPIO_Config();
        //初始化Key的GPIO
        Key_GPIO_Config();
       
        while(1)
        {
                if(Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON)
                {
                        //当按键Key1按下 松开后 红灯亮
                        LED(ON);
                }
        }
}

使用特权

评论回复
5
自动化陈稳|  楼主 | 2021-4-26 22:25 | 只看该作者
以上是查询的方法,在讲按键中断的方法前,我们先说说我们之前学的51是怎么配置外部中断的?
:51单片机就2个外部中断引脚 INT0,INT1;
然后去选择中断触发方式,上升沿/下降沿;

使用特权

评论回复
6
自动化陈稳|  楼主 | 2021-4-26 22:26 | 只看该作者
最后编写中断响应子程序;
而我们的STM32是很强大的,它所以的GPIO都可以触发中断,那么这么多的中断来源,STM32是如何管理,分配的呐~?
:就是通过
:EXTI(External interrupt/event controller)—外部中断/事件控制器;
:NVIC(Nested Vectored Interrupt controller) 是嵌套向量中断控制器;
一个管理中断的配置,一个管理中断的优先级。

使用特权

评论回复
7
自动化陈稳|  楼主 | 2021-4-26 22:27 | 只看该作者
/*=====================exti.h=======================*/
#ifndef __EXTI_H
#define __EXTI_H

#include "stm32f10x.h"

//按键1外部中断定义
#define KEY1_INT_GPIO_PORT         GPIOA                                      /* GPIO端口 */
#define KEY1_INT_GPIO_CLK                RCC_APB2Periph_GPIOA                  /* GPIO端口时钟 */
#define KEY1_INT_GPIO_PIN                     GPIO_Pin_0                                  /* 连接到SCL时钟线的GPIO */
#define KEY1_INT_EXTI_PORTSOURCE   GPIO_PortSourceGPIOA     /*中断GPIO端口*/
#define KEY1_INT_EXTI_PINSOURCE    GPIO_PinSource0          /*中断GPIO引脚*/
#define KEY1_INT_EXTI_LINE         EXTI_Line0               /*中断输入线*/
#define KEY1_INT_EXTI_IRQ          EXTI0_IRQn                                                                /*中断源*/
#define KEY1_IRQHandler            EXTI0_IRQHandler         /*中断响应函数名*/
void EXTI_Key_Config(void);

#endif /* __EXTI_H */

/*=====================exti.c=======================*/
#include "exti.h"

/**
  * @brief  配置嵌套向量中断控制器NVIC
  * @param  无
  * @retval 无
  */
static void NVIC_Config(void)//只能被“exti.c”调用
{
        NVIC_InitTypeDef NVIC_InitStructure;

        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);/* 配置NVIC为优先级组1 */
       
        NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;/* 配置中断源:按键1 */
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; /* 配置抢占优先级 */
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;/* 配置子优先级 */
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /* 使能中断通道 。开总中断 */
        NVIC_Init(&NVIC_InitStructure);//配置好后,写入寄存器
}
/**
  * @brief  配置 IO为EXTI中断口,并设置中断优先级
  * @param  无
  * @retval 无
  */
void EXTI_Key_Config(void)
{
       
        GPIO_InitTypeDef GPIO_InitStructure;
        EXTI_InitTypeDef EXTI_InitStructure;
       
        /*开启按键GPIO口的时钟*/
        RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK ,ENABLE);

        /* 配置 NVIC 中断*/
        NVIC_Config();//调用设置中断优先级函数
       
/*--------------------------KEY1配置-----------------------------*/
  /* 选择按键用到的GPIO */       
  GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;
  /* 配置为浮空输入 */       
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);

  /* 选择EXTI的信号源 */
  GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, KEY1_INT_EXTI_PINSOURCE);
  //2.配置EXTI 结构体
  EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE; //GPIO引脚0---Line0
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//选择EXTI---中断模式
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//选择上升沿---触发中断
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能EXTI中断响应
  EXTI_Init(&EXTI_InitStructure);//配置好后,写入寄存器
}

使用特权

评论回复
8
自动化陈稳|  楼主 | 2021-4-26 22:30 | 只看该作者
//:中断响应函数名 在启动文件中找对应的
void KEY1_IRQHandler(void)
{
  //确保是否产生了EXTI Line中断
        if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET)
        {
                //LED点亮               
                LED(ON);
        //清除中断标志位
                EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);     
        }  
}

使用特权

评论回复
9
自动化陈稳|  楼主 | 2021-4-26 22:31 | 只看该作者
/*=====================main.c=======================*/
#include "stm32f10x.h"   
#include "led.h"
#include "exti.h"

int main(void)
{
        /* LED 端口初始化 */
        LED_GPIO_Config();
                 
/* 初始化EXTI中断,按下按键会触发中断,
  *  触发中断会进入stm32f4xx_it.c文件中的函数
  *  KEY1_IRQHandler和KEY2_IRQHandler,处理中断,点亮LED灯。
  */
        EXTI_Key_Config();
       
        /* 等待中断,由于使用中断方式,CPU不用轮询按键 */
        while(1)                           
        {
                ;
        }
}

使用特权

评论回复
10
自动化陈稳|  楼主 | 2021-4-26 22:31 | 只看该作者
如果大家觉得实验中一些寄存器的配置不是很明白,大家就拿出咱们吃饭的家伙数据手册来把实验中出现的寄存器在手册中查找,去理解。

使用特权

评论回复
11
自动化陈稳|  楼主 | 2021-4-26 22:32 | 只看该作者

使用特权

评论回复
12
coshi| | 2021-5-11 20:49 | 只看该作者
哪种去抖效果好啊

使用特权

评论回复
13
zljiu| | 2021-5-11 20:50 | 只看该作者
是中断方式还是轮训方式啊

使用特权

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

本版积分规则

82

主题

1200

帖子

1

粉丝