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-16 23:16

STM32:STM32学习记录3:按键输入
1:IO配置:。上拉输入模式:区别在于没有输入信号的时候默认输入高电平(因为 有弱上拉)。下拉输入模式:区别在于没有输入信号的时候默认输入低电平(因为有弱下拉)。对于浮空输入模式顾名思义也就是输入什么信号才是什么信号,对于浮空输入要保证有明确的输入信号。 2:stm32的GPIO既可以设置为输出也可以设置为输入,当设置为输入时,输出还是可以有效的,当设为上拉时,可以把输出设为高电平,而设为下拉输入时,把输出设为低电平,这样就有了上拉和下拉。 3:STM32 支持 JTAG 和 SWD 两种仿真接口,他们和普通的 IO 口共用,当需要使用普通 IO口的时候,则必须先禁止 JTAG/SWD。STM32 在默认状态下是开启 JT
[单片机]
STM8S单片机入门1(开发环境搭建)
STM8S单片机开发环境由三大部分组成,包括PC机上的开发软件(集成开发软件、驱动程序等)、调试&编程器ST-LINK、目标单片机电路板。如下图所示: 1、PC机上开发软件 PC机上的软件包括:ST-LINK驱动程序、IAR集成开发环境、STM8S标准函数库、STVP烧录工具。 ST-LINK调试&编程器需要驱动程序 这个驱动程序不需要单独安装,安装STVP时会一起安装。 IAR集成开发环境 IAR集成开发环境是集程序编辑、编译、程序下载、调试等功能为一体的集成开发工具,它可以通过 ST-LINK调试&编程器向目标STM8S单片机下载程序,并进行在线调试(包括设置断点、单步执行、查看内单片机存数
[单片机]
<font color='red'>STM8S</font>单片机入门1(开发环境搭建)
STM8S单片机串口调试
最近在STM8S单片机上调试遇到些问题,共享出来! 问题:STM8S在用IAR编译器调试过程中,中途暂停下,发现程序不能正常运行了,一直死在串口接收中断函数中。 分析:怀疑是串口接收中断函数未清标志位,但函数确实有相应的清中断语句,语句如下: uint8_t tmp; UART3_ClearFlag(UART1_FLAG_RXNE); tmp = UART3_ReceiveData8(); 进入UART3_ClearFlag(UART1_FLAG_RXNE)函数中查看代码: void UART3_ClearFlag(UART3_Flag_TypeDef UART3_FLAG) { /* Che
[单片机]
判断STM32 GPIO输入口的输入状态(高电平或低电平)
在学习STM32中的过程中,经常会遇到“高电平有效”,“低电平有效”等字眼,初看时很多时候就会从字面上理解,认为高电平有效的意思就是有效电平是高电平,低电平有效的意思就是有效电平是低电平的意思。而实际上,这样的理解是有误的。下面咱们以STM32的定时器中输出比较通道为例: 这幅图实际上就是一个pwm波产生的过程,对定时器不了解的可以去查阅相关手册,现在我们先看图中标号1的输出模式控制器,这里模式是指pwm模式,他的意思就是可以通过配置寄存器TIMx_CCMR1的OC1M两位,来选择pwm的模式,但是关于模式选择,手册中有这样一句话:在向下计数时,一旦TIMx_CNT TIMx_CCR1时通道1为无效电平(OC1REF=0),
[单片机]
判断STM32 <font color='red'>GPIO</font><font color='red'>输入</font>口的<font color='red'>输入</font>状态(高电平或低电平)
STM8S按地址增量的烧写方法
1 打开STVP 2 PROJECT/NEW,乱取个名来建立项目 3 PROJECT EDITION,首先在Configuration选好芯片,最重要的就是在SerialNumbering中来设置了 勾住 Enable Serial Number,输入你要选中的地址,及字节数 起始值及步进值  4 设置好了以后,选择“Properties”标签,配置编程动作。 4  设置好以后,导入Memory区、EEPROM区、option Byte区的内容,选择工具栏“Program all tab”
[单片机]
<font color='red'>STM8S</font>按地址增量的烧写方法
使用普通I/O口实现电容触摸感应的解决方案
   技术背景   现在电子产品中,触摸感应技术日益受到更多关注和应用,不仅美观耐用,而且较传统机械按键具有更大的灵敏度、稳定性、可靠性,同时可以大幅提高产品的品质。触摸感应解决方案受到越来越多的IC设计厂家的关注,不断有新的技术和IC面世,国内的公司也纷纷上马类似方案。Cpress公司的CapSense™技术可以说是感应技术的先驱,走在了这一领域的前列,在高端产品中有广泛应用,MCP推出了mTouch™,AT也推出了QTouch™技术,FSL推出的电场感应技术与MCP的电感触摸也别具特色,甚至ST也有QST产品。   但是目前所有的触摸解决方案都使用专用IC,因而开发成本高,难度大,而本文介绍的基于RC充电检测(RC
[单片机]
STM8s(4) 外部中断EXTI初始化
其中中断 0,1,2,3,4 分别 对应端口 A,B,C,D,E // 中断初始化 void EXIT_Init(void) { PD_DDR &= 0 4; // 1 -- 输出;0 -- 输入 PD_CR1 |= 1 4; // 1 -- 上拉;0 -- 浮空 PD_CR2 |= 1 4; // 1 -- 外部中断开;0 -- 外部中断关 EXTI_CR1 |= 0x00; // 触发方式 EXTI_CR2 |= 0x00; // 触发方式 } asm( rim ); // 开总中断 // 中断服务函数 #pragma vector = EXTI3_vector __interrupt void
[单片机]
stm8s 时钟库函数选择内部RC初始化
//本文选择16M内部RC震荡,分频为1 即系统时钟为16M void CLK_HSICmd(FunctionalState NewState) { /* Check the parameters */ assert_param(IS_FUNCTIONALSTATE_OK(NewState)); if (NewState != DISABLE) { /* Set HSIEN bit */ CLK- ICKR |= CLK_ICKR_HSIEN; } else { /* Reset HSIEN bit */
[单片机]

推荐帖子

[国民技术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 单片机
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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