历史上的今天
返回首页

历史上的今天

今天是:2025年03月28日(星期五)

正在发生

2019年03月28日 | stm32按键 长按 短按 函数

2019-03-28 来源:eefocus

在stm32工程中,长按和短按的代码书写, 调用的读取按键状态的底层函数。封装成的按键函数代码。下面是函数的头文件,和.c文件的代码。使用定时器来扫描按键。


#define KEY_ON 1

#define KEY_OFF 0

#define KEY_NULL 0

#define KEY_SHORT 1

#define KEY_LONG  10

#define SHORT_TIME 200

uint8_t Key_state(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)

{

static uint8_t key_value = KEY_NULL;

static uint16_t longtime;

if( (longtime == 0) && (key_value != KEY_NULL))  //当按键状态为长按或者短按时,而longtime 不为零,则按键状态清零

     key_value = KEY_NULL;

}

if ( time == 5 ) /* 5 * 1 ms = 5ms 定时时间到 */

     {

        time = 0;

if(KEY_PRESS(GPIOx,GPIO_Pin))  //按键按下

    {

         longtime++;

        }

        else  //按键松开

{

    if((longtime >= 3) && (longtime <= SHORT_TIME))  //短按

{

key_value = KEY_SHORT;

}

else if( longtime > SHORT_TIME ) //长按

{

    key_value = KEY_LONG;

}

else  //去抖动

{

    key_value = KEY_NULL;

}

longtime = 0; //清零

}

     }  

 return key_value;

}

上面的代码,是按键松开才能判断按键的状态,是长按还是短按。在实际项目中我需要,按键按下一段时间后,判断为按键长按,不用松开,返回按键长按。参考网上的代码,使用状态机写了如下代码


#define    KEY_PRESS(GPIOx,GPIO_Pin)      GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)

#define KEY_INPUT           KEY_PRESS(GPIOx,GPIO_Pin)    //读取按键状态

 

#define KEY_STATE_0         0       // 按键状态位

#define KEY_STATE_1         1

#define KEY_STATE_2         2

#define KEY_STATE_3         3

 

#define LONG_KEY_TIME       300     //长按的3秒时间

#define SINGLE_KEY_TIME     3       // 短按的消抖时间

 

#define N_KEY    0                  // 无状态

#define S_KEY    1                  // 单击

#define L_KEY    10                 // 长按

函数的主体部分,代码中按下按键读取到高电平。


unsigned char key_driver(void) 

{     

    static unsigned char key_state = 0;         // 按键状态变量

    static unsigned int key_time = 0;           // 按键计时变量

    unsigned char key_press, key_return; 

 

    key_return = N_KEY;                         // 清除 返回按键值

 

    key_press = KEY_INPUT;                      // 读取当前键值

 

    switch (key_state)     

    {       

        case KEY_STATE_0:                       // 按键状态0:判断有无按键按下

            if (key_press == KEY_ON)                     // 有按键按下

            {

                key_time = 0;                   // 清零时间间隔计数

                key_state = KEY_STATE_1;        // 然后进入 按键状态1

            }        

            break;

 

        case KEY_STATE_1:                       // 按键状态1:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。

            if (key_press == KEY_ON)                     

            {

                key_time++;                     // 一次10ms

                if(key_time>=SINGLE_KEY_TIME)   // 消抖时间为:SINGLE_KEY_TIME*10ms = 30ms;

                {

                    key_state = KEY_STATE_2;    // 如果按键时间超过 消抖时间,即判定为按下的按键有效。按键有效包括两种:单击或者长按,进入 按键状态2, 继续判定到底是那种有效按键

                }

            }         

            else key_state = KEY_STATE_0;       // 如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键

            break; 

 

        case KEY_STATE_2:                       // 按键状态2:判定按键有效的种类:是单击,还是长按

            if(key_press == KEY_OFF)                       // 如果按键在 设定的长按时间 内释放,则判定为单击

            { 

                 key_return = S_KEY;            // 返回 有效按键值:单击

                 key_state = KEY_STATE_0;       // 返回 按键状态0,继续等待按键

            } 

            else

            {

                key_time++;                     

 

                if(key_time >= LONG_KEY_TIME)   // 如果按键时间超过 设定的长按时间(LONG_KEY_TIME*10ms=200*10ms=2000ms), 则判定为 长按

                {

                    key_return = L_KEY;         // 返回 有效键值值:长按

                    key_state = KEY_STATE_3;    // 去状态3,等待按键释放

                }

            }

            break;

 

      case KEY_STATE_3:                         // 等待按键释放

          if (key_press == KEY_OFF) 

          {

              key_state = KEY_STATE_0;          // 按键释放后,进入 按键状态0 ,进行下一次按键的判定

          }         

          break; 

 

        default:                                // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候

            key_state = KEY_STATE_0;

            break;

    }

 

    return key_return;                          // 返回 按键值

unsigned char key_handle(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)

{

unsigned char key_value;

  if ( time == 10 ) /* 10 * 1 ms = 10ms 定时器 */

   {

        time = 0;

    key_value = key_driver(GPIOx,GPIO_Pin); 

}

return key_value;

}

 在main.c中调用


int main(void)

{

int8_t key_value;

/* led 初始化*/ 

LED_GPIO_Config();


BASIC_TIM_Init();


Key_GPIO_Config();


  while(1)

  {

 

// key_value = Key_state(KEY1_GPIO_PORT,KEY1_GPIO_PIN);

key_value = key_handle(KEY1_GPIO_PORT,KEY1_GPIO_PIN);

 

if(key_value == KEY_SHORT)

{

  

    LED1_TOGGLE;

}

else if(key_value == KEY_LONG)

{

    LED2_TOGGLE; 

}


  }

}

这样可以实现长按不松手,执行长按的代码。以后遇到好的思想会继续学习,总结下来。

推荐阅读

史海拾趣

Excelight Communications Inc公司的发展小趣事

随着5G技术的兴起,光通信行业迎来了新的发展机遇。Excelight紧跟时代步伐,投入大量资源进行技术研发。在李明和团队的共同努力下,公司成功研发出了一款具有自主知识产权的高速光通信芯片,这一成果不仅填补了国内空白,还使Excelight在国际市场上占据了有利地位。

技术突破后,Excelight的产品性能得到了显著提升,同时也带动了整个产业链的升级。公司开始与更多的国内外企业建立合作关系,共同推动光通信行业的发展。

GainSpan ( Telit)公司的发展小趣事

风华的故事始于1984年,当时广东肇庆风华电子厂成立,最初业务聚焦于收录机装配。一年后,即1985年,国内首条从美国引进的年产1亿只片式多层陶瓷电容器生产线落户风华,标志着公司正式踏入高新技术产业领域。这一举措不仅提升了公司的技术实力,也为后续的发展奠定了坚实基础。

EXCELTA公司的发展小趣事

随着公司规模的扩大,产品质量的稳定性成为制约Excelta进一步发展的瓶颈。为了解决这一问题,公司决定引入先进的质量管理体系,并投入大量资源进行培训和改造。经过不懈的努力,Excelta的产品质量得到了显著提升,客户满意度也大幅提高。这一转变不仅为公司赢得了更多的订单,还奠定了公司在行业中的领先地位。

Engineered Components Co公司的发展小趣事

在稳固了国内市场后,ECC开始积极拓展国际市场。他们参加了多个国际电子展会,展示了公司的技术和产品。通过与国际客户的交流与合作,ECC逐渐打开了国际市场的大门。同时,ECC还与国际知名电子企业建立了长期合作关系,共同研发新产品、开拓市场。这些举措使得ECC在国际市场上的知名度不断提升。

德崧电子(D-SWITCH)公司的发展小趣事

在电子开关行业,防水性能一直是重要的技术指标。德崧电子(D-SWITCH)公司在成立初期就意识到了这一点,并投入大量资源进行研发。经过数年的努力,公司成功研发出了具有TUV IP67/IP68防水等级认证的防水型开关。这一突破性的技术不仅解决了市场上防水开关性能不稳定的问题,还大大提高了产品的可靠性和使用寿命。凭借这一技术优势,德崧电子在市场上迅速崭露头角,赢得了客户的广泛认可。

台湾丰宾(CapXon)公司的发展小趣事

面对日益激烈的市场竞争,CapXon公司始终坚持以技术创新为驱动,不断推动产业升级。公司投入大量资金用于研发新的技术和产品,以满足市场对高品质、高性能电容器的需求。通过不断的努力,CapXon成功研发出了一系列具有自主知识产权的高性能电容器产品,这些产品不仅具有更高的稳定性和可靠性,而且能够满足更广泛的应用场景需求。

问答坊 | AI 解惑

焊接

本帖最后由 paulhyde 于 2014-9-15 09:01 编辑  …

查看全部问答>

混合动力电动汽车中电力电子技术应用综述

摘要:文章综述了混合动力电动汽车的发展和基本结构,在此基础上,结合丰田汽车公司的最新一代混合动力电动汽车Prius THS Ⅱ,介绍了电力电子技术在混合动力电动汽车上的具体应用情况。最后,结合混合动力电动汽车的实际情况,提出了需要重点解决的 ...…

查看全部问答>

WinCE下的TCP问题

非常奇怪的问题: 均使用socket编程 XP服务器和一台WinCE客户,没有问题。 两个WinCE客户的话,早Connect的机器就收不到Server的数据,但Server发送成功。客户端向服务器端发送的话,两台机器却都可以。…

查看全部问答>

MMU---cp15中c0控制寄存器疑问

如题,在CP15 控制寄存器 c0中 31bit Asynchronous clock 30bit notFastBus select c0的高两位是什么意思,貌似在datasheet中没有找到说明啊??? 现在在调试MMU中遇到很奇怪的问题 在开启MMU后,我专门弄了一个对寄存器的赋值操作,来验证 ...…

查看全部问答>

请问电抗率怎么计算的?

请问电抗率怎么计算的?比如电容是20KVAR的配7%的电抗,这个电抗的电抗值该怎么计算呢?…

查看全部问答>

为什么在办公室工作重要

雅虎已经禁止员工远程办公,称远程办公妨碍合作,降低工作效率。     由于现在有多种电子沟通方式,远程办公能够节省成本;当公司预算紧张时,尤其如此。     然而,从心理学的角度来看,远程办公有很多潜在的缺点。   ...…

查看全部问答>

【转载】Android系统和linux内核的关系详解

Android系统和linux内核的关系详解 大家都知道Android是基于Linux内核的操作系统,也曾经和Linux基金会因为内核问题产生过分歧( 可以参考本文 后面的“参考阅读”)。这里主要对android和linux的关系进行分析,参 考http://www.itbenet.net/Ar ...…

查看全部问答>

[LPC54102]详述FFT以及M4上使用DSP FFT库

本帖最后由 weizhongc 于 2015-4-28 01:28 编辑               前几天弄了个频谱显示,本来真的想送给女友的,然后花了好几个晚上做出来了,想想还是算了,好像没什么用。    &nbs ...…

查看全部问答>

ENC28J60+UIP 组播和广播无法接收问题

采用UIP进行组播和广播时遇到两个问题,一是无法接收组播数据;二是广播数据大于18字节时无法接收 检查组播数据接收时发现EPKTCNT寄存器显示是有数据的,但是UIP_UDP_APPCALL里面uip_newdata()为零表示无数据;因此猜测是uip把数据包丢弃了; 顺 ...…

查看全部问答>