历史上的今天
今天是:2024年09月13日(星期五)
2021年09月13日 | STM8S自学笔记-006 GPIO输入:按键输入 与 按键滤波
2021-09-13 来源:eefocus
GPIO输入
在 《STM8S自学笔记-003 GPIO输出:点亮LED灯 and 跑马灯特效》中,我们曾经把LED的GPIO设置为推挽输出模式,而它只是GPIO输出功能中的一种。同样,GPIO的输入功能也不止有一种。
浮空输入,无中断
上拉输入,无中断
浮空输入,有中断
上拉输入,有中断
今天不讨论带有中断的的输入功能。
我的STM8S开发板上有3个按键,位置分别与3个LED对应,这些按键都有外部的上拉电阻。所以在初始化按键GPIO时,我们可以设置为浮空输入,也可以设置为上拉输入,两种设置方式对按键检测来说没有差别;如果没有外部上拉电阻,那就建议设置为内部上拉,以保证GPIO输入端口电压的稳定。
按键检测
目标功能
今天要实现的功能是:如果按住某个按键,那么,这个按键对应的LED就点亮,否则就熄灭。
对应代码
在Drv_GPIO.c中追加按键GPIO初始化、按键检查 共2个函数。同时,在Drv_GPIO.h中追加新增函数的声明与按键定义。
当前,完整的Drv_GPIO.c内容如下:
/**
******************************************************************************
* @file Drv_GPIO.c
* @author Elsa
* @version V1.0.0
* @date 7-August-2021
* @brief
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "Drv_GPIO.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
* @brief Initializes the LEDx according to the specified parameters.
* @param led_map : This parameter contains the pin number
* @retval None
*/
void LED_Init(uint8_t led_map)
{
if (led_map & LED1) GPIO_Init(LED1_GPIO, LED1_GPIO_PIN, GPIO_MODE_OUT_PP_LOW_SLOW); //LED1 ON
if (led_map & LED2) GPIO_Init(LED2_GPIO, LED2_GPIO_PIN, GPIO_MODE_OUT_PP_LOW_SLOW); //LED2 ON
if (led_map & LED3) GPIO_Init(LED3_GPIO, LED3_GPIO_PIN, GPIO_MODE_OUT_PP_LOW_SLOW); //LED3 ON
}
/**
* @brief Light on the specified LEDs.
* @param led_map : This parameter contains the pin number
* @retval None
*/
void LED_On(uint8_t led_map)
{
if (led_map & LED1) GPIO_WriteLow(LED1_GPIO, LED1_GPIO_PIN);
if (led_map & LED2) GPIO_WriteLow(LED2_GPIO, LED2_GPIO_PIN);
if (led_map & LED3) GPIO_WriteLow(LED3_GPIO, LED3_GPIO_PIN);
}
/**
* @brief Light off the specified LEDs.
* @param led_map : This parameter contains the pin number
* @retval None
*/
void LED_Off(uint8_t led_map)
{
if (led_map & LED1) GPIO_WriteHigh(LED1_GPIO, LED1_GPIO_PIN);
if (led_map & LED2) GPIO_WriteHigh(LED2_GPIO, LED2_GPIO_PIN);
if (led_map & LED3) GPIO_WriteHigh(LED3_GPIO, LED3_GPIO_PIN);
}
/**
* @brief Blink the specified LEDs.
* @param led_map : This parameter contains the pin number
* @retval None
*/
void LED_Reverse(uint8_t led_map)
{
if (led_map & LED1) GPIO_WriteReverse(LED1_GPIO, LED1_GPIO_PIN);
if (led_map & LED2) GPIO_WriteReverse(LED2_GPIO, LED2_GPIO_PIN);
if (led_map & LED3) GPIO_WriteReverse(LED3_GPIO, LED3_GPIO_PIN);
}
/**
* @brief Control the specified LEDs.
* @param led_map : This parameter contains the pin number
* @retval None
*/
void LED_Control(uint8_t led_map)
{
if (led_map & LED1) GPIO_WriteLow(LED1_GPIO, LED1_GPIO_PIN);
else GPIO_WriteHigh(LED1_GPIO, LED1_GPIO_PIN);
if (led_map & LED2) GPIO_WriteLow(LED2_GPIO, LED2_GPIO_PIN);
else GPIO_WriteHigh(LED2_GPIO, LED2_GPIO_PIN);
if (led_map & LED3) GPIO_WriteLow(LED3_GPIO, LED3_GPIO_PIN);
else GPIO_WriteHigh(LED3_GPIO, LED3_GPIO_PIN);
}
/**
* @brief Initializes the KEYx according to the specified parameters.
* @param key_map : This parameter contains the pin number
* @retval None
*/
void KEY_Init(uint8_t key_map)
{
if (key_map & KEY1) GPIO_Init(KEY1_GPIO, KEY1_GPIO_PIN, GPIO_MODE_IN_FL_NO_IT); //KEY1
if (key_map & KEY2) GPIO_Init(KEY2_GPIO, KEY2_GPIO_PIN, GPIO_MODE_IN_FL_NO_IT); //KEY2
if (key_map & KEY3) GPIO_Init(KEY3_GPIO, KEY3_GPIO_PIN, GPIO_MODE_IN_FL_NO_IT); //KEY3
}
/**
* @brief Read input of specified KEYs.
* @param key_map : This parameter contains the pin number
* @retval None
*/
uint8_t KEY_Read(uint8_t key_map)
{
uint8_t result = 0;
if (key_map & KEY1 != RESET && GPIO_ReadInputPin(KEY1_GPIO, KEY1_GPIO_PIN) == RESET)
result |= KEY1;
if (key_map & KEY2 != RESET && GPIO_ReadInputPin(KEY2_GPIO, KEY2_GPIO_PIN) == RESET)
result |= KEY2;
if (key_map & KEY3 != RESET && GPIO_ReadInputPin(KEY3_GPIO, KEY3_GPIO_PIN) == RESET)
result |= KEY3;
return result;
}
/***************************************************************END OF FILE****/
当前,完整的Drv_GPIO.h内容如下:
/**
******************************************************************************
* @file Drv_GPIO.h
* @author ANNA
* @version V1.0.0
* @date 03-August-2021
* @brief This file contains the headers of the Drv_GPIO.c
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __DRV_GPIO_H
#define __DRV_GPIO_H
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Exported types ------------------------------------------------------------*/
/* Exported defines ----------------------------------------------------------*/
//Maps of LEDx
#define LED(n) ((uint8_t)(0x01<<(uint8_t)(n-1)))
#define LED1 LED(1)
#define LED2 LED(2)
#define LED3 LED(3)
//GPIO Definition of LEDx
#define LED1_GPIO GPIOC
#define LED1_GPIO_PIN GPIO_PIN_3
#define LED2_GPIO GPIOC
#define LED2_GPIO_PIN GPIO_PIN_4
#define LED3_GPIO GPIOD
#define LED3_GPIO_PIN GPIO_PIN_2
//Maps of KEYs
#define KEY(n) ((uint8_t)(0x01<<(uint8_t)(n-1)))
#define KEY1 KEY(1)
#define KEY2 KEY(2)
#define KEY3 KEY(3)
//GPIO Definition of KEYx
#define KEY1_GPIO GPIOB
#define KEY1_GPIO_PIN GPIO_PIN_3
#define KEY2_GPIO GPIOD
#define KEY2_GPIO_PIN GPIO_PIN_3
#define KEY3_GPIO GPIOD
#define KEY3_GPIO_PIN GPIO_PIN_7
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/
void LED_Init(uint8_t led_map);
void LED_On(uint8_t led_map);
void LED_Off(uint8_t led_map);
void LED_Reverse(uint8_t led_map);
void LED_Control(uint8_t led_map);
void KEY_Init(uint8_t key_map);
uint8_t KEY_Read(uint8_t key_map);
#endif
/***************************************************************END OF FILE****/
【提示】
在Drv_GPIO.c中,定义了LED和KEY初始化和操作函数,这些函数的入口是我们自己定义的LED1/2/3和KEY1/2/3,与STM8的底层寄存器无关。也就是说,在调用这些函数时,不会直接调用这些MCU的底层寄存器,而是通过我们自定义的(入口)接口来实现对应的功能。所以,可以将Drv_GPIO.h中形如
#define LED1_GPIO GPIOC
#define LED1_GPIO_PIN GPIO_PIN_3
的代码块全部移入Drv_GPIO.c。
功能实现
在主函数中,添加下述代码,实现按键检测与LED显示:
/**
* @brief Main program.
* @param None
* @retval None
*/
void main(void)
{
static uint8_t key_value;
CLOCK_HSE(CLK_PRESCALER_CPUDIV1);
KEY_Init(KEY1 | KEY2 | KEY3);
LED_Init(LED1 | LED2 | LED3);
while (1)
{
/* Key_Scan */
key_value = KEY_Read(KEY1 | KEY2 | KEY3);
/* Led Show */
if (key_value & KEY1)
LED_On(LED1);
else
LED_Off(LED1);
if (key_value & KEY2)
LED_On(LED2);
else
LED_Off(LED2);
if (key_value & KEY3)
LED_On(LED3);
else
LED_Off(LED3);
}
}
按键滤波
虽然开发板在按键的硬件层面上,从相应的GPIO口各引出了一个接地的滤波电容,但是按下后仍可能有抖动。对此,我们可以从软件上进行滤波。
延时滤波
延时滤波是一种简便的办法。在学校里做单片机实验时,我们就用过这种方法;但在工作中,我从没在按键检测函数里面加过“无用的”延时函数。
if (key_map & KEY1 != RESET && GPIO_ReadInputPin(KEY1_GPIO, KEY1_GPIO_PIN) == RESET)
{
Delay_1ms(7);
if (key_map & KEY1 != RESET && GPIO_ReadInputPin(KEY1_GPIO, KEY1_GPIO_PIN) == RESET)
{
result |= KEY1;
}
}
循环滤波
循环滤波可能是最为常见的按键软件检测方法。它要求在按键按下的情况呈现一定规律时,就认为按下有效。
在本例中,我设定的规律是:按键连续按下100次。那么,对应的修改是:
/**
* @brief Read input of specified KEYs.
* @param key_map : This parameter contains the pin number
* @retval None
*/
uint8_t KEY_Read(uint8_t key_map)
{
volatile uint8_t result = 0;
static uint8_t count[3] = {0};
/* Cyclic filtering */
count[0] = (key_map & KEY1 != RESET && GPIO_ReadInputPin(KEY1_GPIO, KEY1_GPIO_PIN) == RESET)? (++count[0]):0;
count[1] = (key_map & KEY2 != RESET && GPIO_ReadInputPin(KEY2_GPIO, KEY2_GPIO_PIN) == RESET)? (++count[1]):0;
count[2] = (key_map & KEY3 != RESET && GPIO_ReadInputPin(KEY3_GPIO, KEY3_GPIO_PIN) == RESET)? (++count[2]):0;
/* Overflow check */
count[0] = (count[0] >= 250)? 250:count[0];
count[1] = (count[1] >= 250)? 250:count[1];
下一篇:STM8的线中断和端口中断
史海拾趣
|
1>.\\YX_GPS\\port\\c\\yu_port_gui.c(79) : error C2039: \'Release\' : is not a member of \'IDirectDrawSurface\' 1> D:\\Program Files\\Windows CE Tools\\wce500\\STANDARDSDK_500\\include\\ARMV4I\ ...… 查看全部问答> |
|
当我和厂里的师傅们在为了使数控机床提高一级精度而不分白夜进行调试、翻译德文资料时,当我费尽千辛万苦又没有假期和加班费、满身污垢,满手是伤,操作失败了无数次但最终第一次加工制造出精度达到预计的0.0001毫米要求的样品时,我兴奋了一阵子, ...… 查看全部问答> |
|
本人初次接触陀螺仪,读了此陀螺仪datasheet后感到很晕,要做一堆配置…..请大家指点一下该怎么配置,有个范例程序就再好不过了……datasheet 和application note请见附件。… 查看全部问答> |
|
由于很多人总问这个问题,所以这里做一个总结文档供大家参考。这里必须先说明,以下的步骤都是针对Linux系统的,并不面向WinCE。也许你会注意到,现在做嵌入式的人中,做linux研究的人远比做WinCE的人多,很多产家提供的资料也是以linux为主。我一 ...… 查看全部问答> |
|
我现在有套系统,FPGA 驱动AD采样,采样结果想通过VGA来显示出波形,我的做法是将ad结果存入fpga内部DPRAM中(注:没有外扩sdram)。然后让vga从DPRAM中读出数据显示。ad是12位的,我每次采样420个点,想在800*600中间的420*400区域中来显示。我的想 ...… 查看全部问答> |
|
我的想法是,先将0~9十个数和时,分,秒分别录到芯片内,然后取的这些数所在的地址,然后将他们组合,播报出来。但问题是分开都很好,组合在一起有的就播放不出来,老是漏掉一些,是不是忙不过来了,加延时也没用。求解! 还有如 ...… 查看全部问答> |




