STM8S自学笔记-006 GPIO输入:按键输入 与 按键滤波

发布者:Delightful789最新更新时间:2022-01-10 来源: eefocus关键字:STM8S  GPIO输入  按键输入 手机看文章 扫描二维码
随时随地手机看文章

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];

[1] [2]
关键字:STM8S  GPIO输入  按键输入 引用地址:STM8S自学笔记-006 GPIO输入:按键输入 与 按键滤波

上一篇:STM8S自学笔记-005 精准延时
下一篇:STM8的线中断和端口中断

推荐阅读最新更新时间:2024-11-11 10:19

stm8 GPIO按键输入
第一步:配置GPIO 在点亮第一个LED章节已经讲解了GPIO口的操作,下面我们再来看一个寄存器: 这个寄存器只能读。越看越像msp430的操作了。 下面之间看按键初始化和按键读取函数: void Key_Init(void) { PD_DDR &= 0x7F; //PD7 输入 PD_DDP第7位置0 PD_CR1 |= 0x80; //带上拉输入 PD_CR1第7位置1 PD_CR2 &= 0x7F; //禁止外部中断 PD_CR2第7位置0 } void Key_Scan(void) { if(PD_IDR_IDR7==0) { delay_ms(20); //延时消抖 i
[单片机]
stm8 <font color='red'>GPIO</font><font color='red'>按键</font><font color='red'>输入</font>
STVD 调试STM8S所遇到的问题
环境为主控芯片: STM8SF103F3,编译器 COSMIC8,IDE环境为STVD。 大概代码如下: u8 ret; ret=rf_get_addr_len(); ret=rf_get_trint_level(); ret=rf_get_drssi_level(); ret=rf_get_dest_provider(); ret=rf_get_addr_len(); 使用STLINK进行调试时发现,ret的值根本就不是正确的,我跟踪到具体的函数里面去,检测值是正确的,但为什么赋值给ret后,这个值就不对了呢? 后来google搜后发现一个贴上有说明,内容如下: 一段很简单的代码,跑在ST-DISCOV
[单片机]
STM32的GPIO输入输出的理解
最近在看数据手册的时候,发现在Cortex-M3里,对于GPIO的配置种类有8种之多: (1)GPIO_Mode_AIN 模拟输入 (2)GPIO_Mode_IN_FLOATING浮空输入 (3)GPIO_Mode_IPD 下拉输入 (4)GPIO_Mode_IPU 上拉输入 (5)GPIO_Mode_Out_OD开漏输出 (6)GPIO_Mode_Out_PP推挽输出 (7)GPIO_Mode_AF_OD 复用开漏输出 (8)GPIO_Mode_AF_PP 复用推挽输出 对于刚入门的新手,我想这几个概念是必须得搞清楚的,平时接触的最多的也就是推挽输出、开漏输出、上拉输入这三种,但一直未曾对这些做过归纳。因此,在这里做一个总结:
[单片机]
STM32的<font color='red'>GPIO</font><font color='red'>输入</font>输出的理解
STM8S各个模块初始化
/***************可选择的内部或者外部时钟*******************/ #ifdef HSE_EXT void ClkInit(void) { CLK_ICKR = 0X00; //禁止高速内部时钟,从停机(Halt) 或活跃停机(Active Halt) 模式快速唤醒禁止 CLK_ECKR |= 0X01; //使能外部时钟 while(!(CLK_ECKR & 0x02)); //看外部晶振是否启动 CLK_ECKR |= 0X01; //使能外部时钟 CLK_CKDIVR = 0Xf9; //外部12M HZ晶振作为CPU时钟 //入选2
[单片机]
STM32GPIO的八种输入输出模式
上拉电阻:把不确定的信号通过电阻连接到高电平,电信号初始化为高电平。 下拉电阻:把不确定的信号通过电阻连接到低电平,电信号初始化为低电平。 输入 1.上拉输入:输入信号通过上拉电阻被初始化为高电平,再通过TTL施密特触发器从模拟信号9V、3.3V、1.9V转为数字信号0、1后存入输入寄存器中。 2.下拉输入:同上拉输入一样,区别只在通过下拉电阻初始化为低电平。 3.浮空输入:即信号输入既不连接上拉也不连接下拉,输入信号电压值不确定,通过TTL施密特触发器从模拟信号9V、3.3V、1.9V转为数字信号0、1后存入输入寄存器中。通常用于IIC、串口USART中。 4.模拟输入:不通过上下拉电阻,也不通过TTL施密特
[单片机]
STM8S_007_片内FLASH和EEPROM编程
Ⅰ、写在前面 我们都知道FLASH和EEPROM这两种存储器,但是大部分人了解的都是专门的FLASH和EEPROM芯片,如:W25Q16和ATAT24C08(外部)储存芯片。   外部存储芯片和本文说的内部FLASH和EEPROM最大的区别就是在于:内部FLASH和EEPROM是不需要SPI、I2C等进行操作,也就是说同等情况下,内部FLASH和EEPROM的读写要快一点。   STM8的FLASH除了储存程序代码之外,就是用于用户编程(存储数据),不像之前的51芯片不能利用内部储存代码的FLASH。   为方便大家阅读,本文内容已经整理成PDF文件: http://pan.baidu.com/s/1i5uWhJR 作者
[单片机]
STM8S低功耗电源管理
1STM8S功耗来源 STM8S功耗分静态功耗和动态功耗。 静态功耗:主要由晶体管的偏置电流和漏电流产生。 动态功耗:取决于电源电压和工作时钟频率。 在CMOS逻辑电路以一定时钟频率运行时,静态功耗与动态功耗相比是可以忽略的。但在一些低功耗模式下,时钟不再运行,此时静态功耗是主要的功耗源。 因此,功耗主要取决于: 1.微控制器单元(MCU)的芯片面积:所采用的工艺,晶体管的数量,片上集成和使用的模拟功能/外设。 2.MCU电源电压: CMOS逻辑电路中消耗的电流与电源电压的平方成正比。因此,可以通过降低供电电压来降低功耗。 3.时钟频率:在不要求进行高速处理的应用中,降低时钟频率可以降低功耗。
[单片机]
使用STM8S自带BootLoader_2
仔细读ST支持文档 UM0560,按步骤操作。 程序准备工作: 1.开串口接收中断,发送。 /* ******************************************** UART2 configured as follow: - BaudRate = 115200 baud - Word Length = 8 Bits - One Stop Bit - No parity - Receive and transmit enabled - Receive interrupt - UART2 Clock disabled ***********************************
[单片机]

推荐帖子

初次使用必看!S5pv210系列:E8卡片电脑系统烧写或者更换
在启动卡制作完成后,使用下面步骤更新或者更换系统。烧写/更新Android/ubuntu/Linux系统1、选中SecureCRT软件,选择数字键“1”,从TQBoardDNW下载烧写镜像uboot文件双击烧写。如:u-boot_E8_20130826.bin(对应VGA:1024*768)2、选择“h”进行关机,选中SecureCRT软件,按住空格键开机,进入uboot下载界面。3、选中SecureCRT软件,选择数字键“9”进入区间分区菜单,若准备下载Ubuntu系,选中“1”分两个
小小宇宙 ARM技术
2012年9月份北京举办的一些重要行业展会和研讨会
IHS行业分析亚太峰会展会场馆:北京国家会议中心举办时间:2012年9月20日8:30–17:30第十七届中国国际医药(工业)展览会暨技术交流会展会场馆:北京国家会议中心展会日期:2012年9月24日~2012年9月27日第21届中国国际信息通信展览会展会场馆:北京朝阳区三环东路六号中国国际展览中心举办时间:2012年9月18日~2012年9月22日第十四届国际电力设备及技术展览会展会场馆:北京朝阳区三环东路六号中国国际展览中心举办时间:2012年9
jameswangsynnex 安防电子
软件测试经典资料大推荐(五)---google软件测试之道
软件测试经典资料大推荐(五)---google软件测试之道程序员之间流传着这样一句顺口溜:有人喜欢创造世界,他们做了开发者;有的人喜欢开发者,他们做了测试员。什么是软件测试?软件测试就是一场本该在用户面前发生的灾难提前在自己面前发生了,这会让他们生出一种救世主的感觉,拯救了用户,也就拯救者这个软件,避免了他们被卸载的命运。近年来,软件测试一直呈现出火爆的发展势头。为什么软件测试最近这么火。在这背后是有一定的深层次原因的。在中国的很多软件企业存
tiankai001 下载中心专版
stm32f测试小程序
希望对新手有用!使用内部晶振,PC口进行闪灯! stm32f.JPG(51.25KB)下载次数:132010-9-2816:41stm32f测试小程序还不错很简洁但很实用的一段程序好像太简洁了,有空去楼主的博客逛逛有用就好!感觉还不错,应该有应用的场合
86846642996 stm32/stm8
太阳能热水器控制仪的水位传感器是什么原理
测量了传感器的电阻,在不同的的水位,电阻值都会缓慢的上升,最终都是60k或接近,请问这是什么原理,或者是测量方法不对.现在设计一个电路,可以测温度,也可以测水位。测温度,就是用测量电阻,然后转换为频率,单片机检测接收。测量水位,看到传感器里面是几根线,从传感器引出是两根线。里面似乎没有芯片或是液位传感器,它是通过不同的水位变化输出不同的阻值,我看了一些资料,都是这样说的,可是为什么阻值总是会上升到60K,在不同的水位情况下都是这样?太阳能热水器控制仪的水位传感器是什么原理是不是你的传感器坏
djf876 嵌入式系统
【2024 DigiKey 创意大赛】带健康提醒的86盒桌面助手
**一、作品简介**设计名称:带健康提醒的86盒桌面助手项目用到的板卡:使用ESP32-S3-LCD-Ev-Board开发板,采用的是ESP32-S3这款MCU,板卡板载了4寸的电容触摸屏,功能强悍,做HMI应用十分合适。作品功能介绍:借此次得捷大赛的机会,制作了一款带健康提醒的86盒桌面助手,86盒可以摆在桌子上,实时地检测前方的温度,也就是监测使用者的体表温度,并显示在屏幕上面,并可通过网络来获取时间、天气等显示在屏幕上,给使用者提供出行建议等,软件采用LVGL开源GUI界面
pomin DigiKey得捷技术专区
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved