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];
上一篇:STM8S自学笔记-005 精准延时
下一篇:STM8的线中断和端口中断
推荐阅读最新更新时间:2024-11-16 23:16
推荐帖子
- [国民技术N32WB452测评]_开箱及RT-Thread例程运行
- #一、开箱前几日收到了国民技术公司从北京寄过来的开发板,今日终于有空来做一个开发板的分享。拆开快递后,是一个印有国民技术商标的白色纸盒,内附国民技术的开发板N32WB452一枚及配件USB-A转USBMINIUSB连接线。包裹的红色泡沫棉我已经去掉啦,开发板到手很开心,开箱图如下:可以看到开发板已经板载了NS-LINK调试器(在左下角),左侧中部区域则是开发板的主控,N32WB452LEQ6,QFN88脚封装。板子上还自带蓝牙天线、触摸按键、多路LED灯、蜂鸣器、SPI-FL
- yang8555u RF/无线
- MXCHIP+收到OPEN1081套件
- 这个EEWORLD很给力,我才交计划才几天啊。今天我就收到OPEN1081套件了。我接过包裹觉得沉甸甸地。先上个带包装的照片:这是正面:这张是反面:总之外包不错地,没有任何划擦。开包看看吧:内包装正面:内包装反面:也不错,开箱:里边东东真不少唉:我突然发现模块的一个脚弯了,把下边的包装给穿透了。还好揸到了可调的黑色塑料钮上。谢天谢地。弯曲的一角,这个明显是摔地,一次具列地碰撞所致。8大件:完好无损主板:在主板内包装袋发现第九大件:18D20显示屏:包装特
- ddllxxrr RF/无线
- 蓝牙4.0兼容BLE模式无线模块
- 支持最新的蓝牙4.0标准,低功耗模式工作电流只有0.4uA,而且模块还与ZigBee2.4GHz频段,还有433Mhz频段模块保持引脚兼容。这样只有做一次电路板,就可以出3款产品了哦蓝牙4.0兼容BLE模式无线模块自己顶一下,感兴趣的朋友可以讨论啊有集成wifi,BT4.0,BLE,ANT,FM的产品否?有集成wifi,BT4.0,BLE,ANT,FM的产品否?请问有没有这个模块的更详细的资料?看看好像有集成有集成wifi,蓝牙的芯片路过,看看先谢
- michael200800 RF/无线
- 在ccs中调试程序时打断点失败
- 在单步调试程序时,在设置第8个断点的时候,出现insufficentresoureces提示,然后断点就打不上,不管我在那句话,只要是打第八个断点的时候就是这样的,退出调试,再重新编译单步调试,发现就直接进入boot_specia.cpre_init.cautoinit.c这三个程序里了。在ccs里最多只能打7个断点吗?这个问题在仿真是出现的,编译的时候断点也可以打上,但是在仿真是走到第八个断点就不能走了,不管在那条语句都是一样的,这个是什么意思啊,怎么才能解决呀??!!!!!!!!在
- 下雨天不洗澡 微控制器 MCU
- 求大佬分享5G基础原理
- 各位大神,qiu分享5G基本原理求大佬分享5G基础原理8分钟讲解关于5G的一切下载中心资源分类网络及通信技术射频下一代无线通信(5G)技术集锦我空了来给你传一些,找到的东西。现在最多也就能在市面上看到一些皮毛吧,如果真的技术都流传出来的话,你以为华为干饭吃的呀,投入那么多的时间跟资金研发出来的
- 美丽的天气 无线连接
- 简单实用的调频话筒制作
- 下面的就是调频无线话筒的电路图,电路非常简洁,没有多余的器件。高频三极管V1和电容C3、C5、C6组成一个电容三点式的振荡器,对于初学者我们暂时不要去琢磨电容三点式的具体工作原理,我们只要知道这种电路结构就是一个高频振荡器就可以。三极管集电极的负载C4、L组成一个谐振器,谐振频率就是调频话筒的发射频率,根据图中元件的参数发射频率可以在88~108MHZ之间,正好覆盖调频收音机的接收频率,通过调整L的数值(拉伸或者压缩线圈L)可以方便地改变发射频率,避开调频电台。发射信号通过C4耦合到天线上再发
- maker 单片机
设计资源 培训 开发板 精华推荐
- 具有改进瞬态响应的 LT1120IS8 稳压器的典型应用电路
- LTC3642IMS8E-5 高效 5V 降压型稳压器的典型应用电路
- 用于数据采集系统的 12 位、188KSPS、8 通道 ADC
- LF33ABDT-TR 3.3V 多路低压降稳压器电源的典型应用,带 ON/OFF 拨动开关
- 低成本带双路电子电位器的电压电流表(个人修改版本)
- 使用 ON Semiconductor 的 KA7806E 的参考设计
- EVAL-INAMP-ICF-RMZ,用于评估 AD8237 微功耗、零漂移、真正轨到轨仪表放大器的评估板
- 双路输出 150/300mA 低压差稳压器的典型应用
- AD5318 八通道、10 位数模转换器的典型应用
- 典型应用 - RE46C162 CMOS 电离烟雾探测器 ASIC 的时间喇叭模式,具有互连、定时器模式和警报存储器