y574924080 发表于 2013-7-17 18:56:42

[分享][交流]发一个通用按键模块,简单易用 [2014-3-24 Update]

本帖最后由 Gorgon_Meducer 于 2014-3-24 22:51 编辑

傻孩子工作室作品
这是一个通用的按键模块,使用简单!支持最多255个按键,每个按键都支持包括按下检测、
松手检测、长按、连按的效果。内置去抖滤波处理,内置按键队列。而且是平台无关,全状
态开发的!

更新日志
    - 2014-3-24
      a. 修改key_queue接口:增加中断保护修改注释风格
      b. 更新Demo工程,并将key_task放入到system tick 异常处理程序中



下面我们开始进入正题:

0、        准备工作:
你现在需要一个有串口、有两个独立按键、有独立LED指示灯的单片机系统。为了体现平台无
关,请参考文档搭建平台,该平台提供了串口收发函数、LED控制
接口函数、独立按键读取函数。这样我们就拥有一个共同讨论的基础。

我现在使用的是lpc1227的板子,提供了一个完整基于lpc1227的范例,但是基于之前搭建的平
台,代码移植起来是非常容易的。

在平台搭建完成的基础上,你仅仅需要提供一个获取按键键值函数就可以使用按键模块了。

1、        解压模块

将按键模块源代码下载下来,你可以看到里面有一个app_cfg.h文件,一个oopc.h文件,一个
key文件夹,将其解压到和工程同级的目录中,同时在你的工程中包含源文件key.c(key文件内)
和key_queue.c(key的子文件夹key_queue内)。

2、编写按键获取键值函数

你需要编写自己的按键键值获取函数。例如我在main.c中编写好了该函数:#define KEY_1                1
#define KEY_2                2
/*************************************************************************
* Function Name: get_key_scan_value
* Parameters: void
* Return: return key value
*
* Description:
*
*************************************************************************/
uint8_t get_key_scan_value(void)
{
    if (IS_KEY1_DOWN()) {   //该宏在平台搭建中有说明
      return KEY_1;
    }
       
    if (IS_KEY2_DOWN()) {   //该宏在平台搭建中有说明
      return KEY_2;
    }
       
    return KEY_NULL;
}
这里只是使用两个简单的独立按键。在实际工程应用中,可以根据你的情况来调整。需要
注意的是返回的键值不能为0 (它已经被KEY_NULL使用了)。

3、注册按键获取键值函数
打开主目录下的app_cfg.h,添加代码,注意宏GET_KEY_SCAN_VALUE(),示例如下:#ifndef __APP_CFG_H__
#define __APP_CFG_H__

#include <stdbool.h>
#include <stddef.h>

#include "oopc.h

#define KEY_QUEUE_SIZE                 10
#define KEY_COUNT                         100
#define KEY_LONG_TIME                 30000
#define KEY_REPEAT_TIME                20000

//在这里声明自己编写的按键键值获取函数
extern uint8_t get_key_scan_value(void);
//用宏来注册
#define GET_KEY_SCAN_VALUE()   get_key_scan_value()

#endif /* __APP_CFG_H__ */
4、接口使用说明
经过以上的步骤,按键模块已经移植完成了。使用时,在main.c函数中包含头文件key.h:#include ".\key\key.h"然后调用接口函数即可。接口函数是什么?有哪些?
嗯,我们先来看看接口头文件”key.h”:#ifndef __KEY_H__
#define __KEY_H__

#include ".\app_cfg.h"

#include "key_interface.h"

#define KEY_NULL        0

extern void init_key_task(void);
extern bool key_task(void);
extern bool get_key(key_event_t* ptKey);

#endif /* __KEY_H__ */
可以看到,该模块提供了三个函数,这就是接口函数!介绍如下:
void init_key_task(void)为初始化按键模块函数,只需要在初始化时调用一次即可。
bool key_task(void)为按键任务函数,在超级循环或者定时器中断处理程序中被周期性的调用int main(void)
{
    …
    init_key_task();
    …
    while(1) {   
    …
    //需要在超级循环或者定时器中断处理程序中被周期性的调用      
    key_task();
    …
    }
}
bool get_key(key_event_t* ptKey) 用来获取按键:
    当返回false时,表示没有获取到有效按键;
    当返回true时,表示获取到有效按键,通过传入的参数读取按键信息。
结构体key_event_t定义在key_interface.h中,该结构体包含一个按键的全部信息:键值和按键事件类型。

key_interface.h
typedef struct{
    uint8_t chKeyValue;
    key_status_t tEvent;
}key_event_t;
简单实用范例:
do {
    key_event_t tKey;
    if(!get_key(&tKey)) {
      break;
    }
    if ((KEY_1 == tKey.chKeyValue) && (KEY_LONG_PRESSED == tKey.tEvent)) {
    //! 识别KEY_1的长按键事件
    …
    }
} while(false)
说了那么多,还没有上代码呢,请看下面的DEMO:
#include “key.h”

/*************************************************************************
* Function Name: main
* Parameters: none
*
* Return: none
*
* Description: main
*
*************************************************************************/
int main(void)
{
    …
    // init_key_task ()初始化时调用一次即可
    init_key_task ();
    …
    while(1) {      
      // key_task()需要在超级循环或者定时器中断处理程序中被周期性的调用      
      key_task();
      //在这里添加你的按键应用代码
      key_app();
      …
    }
}
       

/*************************************************************************
* Function Name: key_app
* Parameters: void
* Return: return FSM state
*
* Description:
*
*************************************************************************/
static bool key_app(void)
{
    static uint8_t s_chState = KEY_APP_START;
    static key_event_t s_tKey = {KEY_NULL, KEY_UP};
    switch (s_chState) {
        case KEY_APP_START:
          s_chState = KEY_APP_GET;
          //break;
                       
        case KEY_APP_GET:
          if (get_key(&s_tKey)) {   //调用获取按键,根据按键键值和事件类型不同做不同的处理
                if (KEY_1 == s_tKey.chKeyValue) {                                       
                  if (KEY_DOWN == s_tKey.tEvent) {
                        s_chState = KEY_APP_DOWN;
                  } else if (KEY_UP == s_tKey.tEvent) {
                        s_chState = KEY_APP_UP;
                  } else if (KEY_PRESSED == s_tKey.tEvent) {
                        s_chState = KEY_APP_PRESSED;
                   } else if (KEY_LONG_PRESSED == s_tKey.tEvent) {
                     s_chState = KEY_APP_LONG_PRESSED;
                   } else if (KEY_REPEAT == s_tKey.tEvent) {
                     s_chState = KEY_APP_REPEAT;
                   }
                } else if (KEY_2 == s_tKey.chKeyValue) {                                       
                  if (KEY_DOWN == s_tKey.tEvent) {
                        s_chState = KEY_APP_DOWN2;
                  } else if (KEY_UP == s_tKey.tEvent) {
                        s_chState = KEY_APP_UP2;
                  } else if (KEY_PRESSED == s_tKey.tEvent) {
                        s_chState = KEY_APP_PRESSED2;
                  } else if (KEY_LONG_PRESSED == s_tKey.tEvent) {
                        s_chState = KEY_APP_LONG_PRESSED2;
                  } else if (KEY_REPEAT == s_tKey.tEvent) {
                        s_chState = KEY_APP_REPEAT2;
                  }
                }
          }
          break;
                       
        case KEY_APP_DOWN:
          if (!print_key1_down()) {       //这是一个通过串口打印字符串"KEY1 DOWN\r\n"的状态机
                KEY_APP_RESET_FSM();
                return false;
          }
          break;
                       
        case KEY_APP_UP:
          if (!print_key1_up()) {         //这是一个通过串口打印字符串"KEY1 UP\r\n"的状态机
                KEY_APP_RESET_FSM();
                return false;
          }
          break;
                …
                //省略一部分代码
}
}
完整的范例,可以点这里下载:
效果图:


4、参数调整
        经过上面的几个步骤,按键模块已经可以使用了,当然不同MCU的速度不同,所以提供
了以下宏来调整参数,使之更符合你的情况。
//内置队列大小
#define KEY_QUEUE_SIZE                 10
//按键连续检测次数
#define CHECK_KEY_COUNT                 20
//长按计数
#define KEY_LONG_TIME                 30000
//连击计数
#define KEY_REPEAT_TIME                20000
5、注意事项:
        A.本模块是基于全状态开发的,占用处理器时间及少,同时key_task()函数也需要在超
级循环或者定时器中断处理程序中被周期性的调用。
        B.有效键值不能为0 (KYE_NULL已经占用了键值0)

个人水平有限,欢迎拍砖!


数据流图

状态图


qufuta 发表于 2013-7-17 19:02:14

高手,真的是高手,果然是精华帖,先MARK一下,下次再来看{:smile:}

hyghyg1234 发表于 2013-7-17 19:17:51

好贴,顶起

mcu_lover 发表于 2013-7-17 19:38:55

呵呵,不错。我已经用了好几年了。和你的方式一模一样,调用接口也一致,不同的是我把键值和按键状态封装在一个字节里。这样实际按键数量只支持16个(4bits for key value , 4 bits for key event)
如果和你那样,分开两个字节,也就和你一样,可以支持255键了。
接口:

调用方式:

方式和楼主位基本一致,就不传源码了。

bbsview 发表于 2013-7-17 19:39:14

没有矩阵的吗?单按键口IO耗费比较大呀

y574924080 发表于 2013-7-17 20:06:29

mcu_lover 发表于 2013-7-17 19:38
呵呵,不错。我已经用了好几年了。和你的方式一模一样,调用接口也一致,不同的是我把键值和按键状态封装在 ...

这都是傻孩子老师教的,算是培训的阶段总结吧

D.lovers 发表于 2013-7-17 20:06:49

mark,学习

y574924080 发表于 2013-7-17 20:09:44

bbsview 发表于 2013-7-17 19:39
没有矩阵的吗?单按键口IO耗费比较大呀

无论是独立按键还是矩阵按键,都可以使用这个模块,它们只有获取键值函数不一样,这是由用户自己编写的

SNOOKER 发表于 2013-7-17 20:22:33

mcu_lover 发表于 2013-7-17 19:38 static/image/common/back.gif
呵呵,不错。我已经用了好几年了。和你的方式一模一样,调用接口也一致,不同的是我把键值和按键状态封装在 ...

这代码写得好漂亮啊。

按键状态3个位不够用吗

zhanghuhhhhh 发表于 2013-7-17 20:28:48

本帖最后由 zhanghuhhhhh 于 2013-7-17 20:36 编辑

买了傻孩子的书。发现函数和变量名,没有楼上的mcu_lover   写的好。有可能是写大的工程多了,养成的习惯,希望傻孩子,以后写书,学学杜洋或其它作者,代码写的争取小孩都明白,变量名中有的下划线,没有必要让初学者看啊。大工程有可能是必要的。



这个通用模块很好,只是如果函数名,变量名,短点,易懂点。

结构体尽量不用就更好了。
名子短,用于工程中出问题,移植者会再加长的。

一路向南 发表于 2013-7-17 20:35:13

学习了,楼主和mcu_lover的方法都不错,话说很期待mcu_lover博文更新。

mcu_lover 发表于 2013-7-17 20:43:37

SNOOKER 发表于 2013-7-17 20:22 static/image/common/back.gif
这代码写得好漂亮啊。

按键状态3个位不够用吗

按键识别如下几种状态,每种状态分别有一位标志对应:
按键按下
按键弹起
按键长按
按键连按
共需要4 bits。

y574924080 发表于 2013-7-17 21:26:23

zhanghuhhhhh 发表于 2013-7-17 20:28 static/image/common/back.gif
买了傻孩子的书。发现函数和变量名,没有楼上的mcu_lover   写的好。有可能是写大的工程多了,养成的习惯, ...

额,不知道如何表述,所以翻了翻代码大全

我很同意这句话:为变量命名最重要的考虑事项是,该名字要完全,准确地描述出该变量所代表的事物。

所以变量名我倒是不觉得长,倒是不易懂这的确是不够好,希望指出,我好改进

作为模块我觉得避免和以后命名冲突是很重要的,一个模块写好后就不应该随便修改

结构体我倒是觉得是一个很好的东西。。。

yiming988 发表于 2013-7-17 21:38:49

zhanghuhhhhh 发表于 2013-7-17 20:28 static/image/common/back.gif
买了傻孩子的书。发现函数和变量名,没有楼上的mcu_lover   写的好。有可能是写大的工程多了,养成的习惯, ...

结构体和指针是C的精华,不用的话很多东西没办法实现,只能拳打脚踢单打独斗了 呵呵。我感觉学了一点入门了以后,那些看似复杂了点的代码实际帮了我们很大的忙,看起来复杂,用起来很方便。 围观学习。。。

Gorgon_Meducer 发表于 2013-7-17 21:40:42

zhanghuhhhhh 发表于 2013-7-17 20:28 static/image/common/back.gif
买了傻孩子的书。发现函数和变量名,没有楼上的mcu_lover   写的好。有可能是写大的工程多了,养成的习惯, ...

谢谢你的建议,我书中的编码风格已经是五年前的东西了,现在已经完全不同了。
萝卜青菜各有所爱吧。我还是比较喜欢长命名风格。另外,所谓模块,就是写好了
原则上不会修改的,这次的模块正是我培训学员如何进行模块化封装的一个结果。
需要发生变化的部分比如按键扫瞄,各类参数的宏配置输入等等都处理好了。使用
的时候是绝对不允许修改模块中的代码。坚持这一点,你才能体会出模块化的好处,
也才能自己也进行面向接口开发的实践。

zhanghuhhhhh 发表于 2013-7-17 21:47:31

各人面向的价层不一样吧。

杜洋的书里的代码,不用宏,不用指针,不用结构体。小学生也跟着学。淘宝双皇冠。

初学者,看你的书有点难度,估计水平高了。就好点了。

新书什么时候出来啊。
我再买来学习一下。

zhanghuhhhhh 发表于 2013-7-17 21:51:08

发一下我的按键程序吧。

是用本坛的“三行按键”基础上改的,阿莫论坛,就是神!

互相学习,提高吧。
#include "../hfile/config.h"
uint16 GCountLongPressTime;
uint8 GTrigger=0;
uint8 GHold=0;
uint8 g_KeyValue=0x00;
uint8 g_LongPressKeyValue=0x00;
/**********************************************************************
//this routine maybe put in the mainlop.no need decrease counter.
//it take the loop as a delay!
**********************************************************************/
uint8 GetPinValue(void )
{
uint8 KeyPort=0xff;
uint8 Key0value=0x00;
uint8 Key1value=0x00;
uint8 Key2value=0x00;
uint8 Key3value=0x00;
//if(0==PIN(B,3))   #define PIN(m,n)
if(
   0==(
         !(uint8)(GET_BIT(DDRB).bit3=0)&&\
         (GET_BIT(PORTB).bit3=1)&&\
             GET_BIT(PINB).bit3
               //(uint8)( GET_BIT(PORTB).bit3=1)&&\//
               )
       )
   
    Key0value=0x01;
if(0==PIN(D,4))
    Key1value=0x02;
if(0==PIN(D,3))
    Key2value=0x04;
if(0==PIN(B,2))
    Key3value=0x08;
KeyPort=KeyPort&(~Key0value)&(~Key1value)&(~Key2value)&(~Key3value);
return KeyPort;
}
void ThreeLineKeyRead(void)//读按键
{
uint8 virtualPinValue=GetPinValue();
uint8 ReadData=0;
ReadData=virtualPinValue^0xff;
GTrigger=ReadData&(ReadData^GHold);
GHold=ReadData;
}
voidWhichKeyIsShortPress(void)//短按键
{
if(GTrigger&0x01)
{
    g_KeyValue=KEYCH;//左数第1个按键
}

if(GTrigger&0x02)
{
    g_KeyValue=KEYADD;//左数第2个按键
}
if(GTrigger&0x04)
{
    g_KeyValue=KEYDEC;//左数第3个按键
}
if(GTrigger&0x08)
{
    g_KeyValue=KEYSET;//左数第4个按键
}
if(g_KeyValue!=0)g_SystemTime60s=0;
}

voidWhichKeyIsLongPress(void) //长按键
{
if(GHold){GCountLongPressTime++;}
else {
    GCountLongPressTime=0;
    g_LongPressKeyValue=0;
}
if(GCountLongPressTime>500)//65500
{
    if(GHold&0x02)
    {
      g_LongPressKeyValue=longKEYADD;//左数第2个按键
    }
    if(GHold&0x04)
    {
      g_LongPressKeyValue=longKEYDEC;//左数第3个按键
    }
    if(GHold&0x08)
    {
      g_LongPressKeyValue=longKEYSET;//左数第4个按键
    }
}
}

void KeyRead(void)
{
ThreeLineKeyRead();//读按键
WhichKeyIsShortPress();
WhichKeyIsLongPress();
}

liangws201 发表于 2013-7-17 21:52:19

不错,很工整!

Gorgon_Meducer 发表于 2013-7-17 21:52:59

zhanghuhhhhh 发表于 2013-7-17 21:51 static/image/common/back.gif
发一下我的按键程序吧。

是用本坛的“三行按键”基础上改的,阿莫论坛,就是神!


多谢分享

zhanghuhhhhh 发表于 2013-7-17 21:54:48

原作者的程序


void KeyRead( void )
{
   unsigned char ReadData = P1^0xff;   // 1// 当前I/O状态(“真”或“假”)
   Trg = ReadData & (ReadData ^ Hold);      // 2   // 如果 当前状态为“真”,且当和“上次状态”不一致,则Trg为“真”
       //第二句的意思是:如果当前检测到按键按下且上次未按下,则是一次有效的触发;如果连续按下,则只视为一次有效触发。
       Up = (~ReadData) & (ReadData ^ Hold);
       //Up= Hold&(ReadData^Hold);
   Hold = ReadData;                          // 3 // 当前状态过时,即成为“上次状态”。
       /*
       unsigned char ReadData = PINB^0xff;   // 1
   Trg = ReadData & (ReadData ^ Cont);      // 2
   Up= Cont&(ReadData^Cont);
   Cont = ReadData;                              // 3
       
       
       ReadData= P0 & 0X1C;
       ReadData ^= 0X1C;
       */
}

tuowai 发表于 2013-7-17 23:39:40

标记下,以后能用到!谢谢分享!

chengpiaopiao 发表于 2013-7-18 00:29:20

标记一下,备用

wcm_e 发表于 2013-7-18 00:31:57

学习,mark,谢谢

GNMXD 发表于 2013-7-18 06:28:08

好东西,,,

Etual 发表于 2013-7-18 07:47:24

阅读完了代码,很标准的状态机按键程序,初学者可以学习一下。

kuki0702 发表于 2013-7-18 10:01:26

很工整,以后能用上的。

Robin_King 发表于 2013-7-18 12:44:36

不错不错。好好学习下。

powermeter 发表于 2013-7-18 12:52:59

不错。mark

411412 发表于 2013-7-18 13:11:22

学习,mark

yklstudent 发表于 2013-7-18 14:58:36

mark下回去好好研读下

sync765 发表于 2013-7-18 16:50:34

不错学习了

ljt80158015 发表于 2013-7-18 17:04:47

不错收藏!~

lsy5110 发表于 2013-7-18 17:08:21

不错 {:smile:}

weimas 发表于 2013-7-23 13:22:55

mark 值得好好学习

guer 发表于 2013-7-23 15:55:14

mark      收藏了

foxpro2005 发表于 2013-7-28 21:32:44

mcu_lover 发表于 2013-7-17 19:38 static/image/common/back.gif
呵呵,不错。我已经用了好几年了。和你的方式一模一样,调用接口也一致,不同的是我把键值和按键状态封装在 ...

有当年 农民讲习所 思想风格的程序...

3.3v 发表于 2013-7-29 14:01:19

这个按键方式好用

zzjjhh250 发表于 2013-7-30 11:42:29

lz能否从顶层讲解一下,整体的流程。
这样对于看code也是有效的。
传递的更多是思想。

tom_flag 发表于 2013-8-1 14:16:25

收藏了哈..俺是初学者..正需要这些呢.会一定加把劲好好学些的..~~~~

liubuwai 发表于 2013-8-4 20:43:11

恩恩   学习了

一匹狼 发表于 2013-8-4 21:38:34

cool,绑定

davidd 发表于 2013-8-4 21:53:41

mark一下

yat 发表于 2013-8-5 17:43:50

mark 发一个通用按键模块,简单易用

kevinchen026 发表于 2013-8-5 18:07:44

好贴,很强大.

lihq97 发表于 2013-8-12 20:56:03

mark,学习了!

adalim 发表于 2013-8-13 14:04:24

标记下,以后能用到!谢谢分享!

jlian168 发表于 2013-8-14 09:05:42

y574924080 发表于 2013-7-17 20:09 static/image/common/back.gif
无论是独立按键还是矩阵按键,都可以使用这个模块,它们只有获取键值函数不一样,这是由用户自己编写的 ...

Sir:
没有矩阵的吗?
Thank you.

y574924080 发表于 2013-8-14 21:09:45

jlian168 发表于 2013-8-14 09:05 static/image/common/back.gif
Sir:
没有矩阵的吗?
Thank you.

这个由用户自己实现来的

y574924080 发表于 2013-8-14 21:10:33

zzjjhh250 发表于 2013-7-30 11:42 static/image/common/back.gif
lz能否从顶层讲解一下,整体的流程。
这样对于看code也是有效的。
传递的更多是思想。 ...

迟些时候哈,最近有点忙。。

一夕nandy 发表于 2013-8-18 22:18:37

mark一记

zlutian 发表于 2013-8-18 22:41:20

谢谢,学习了.

lgnq 发表于 2013-8-18 22:52:48

学习一下,以后可能会用到

zyw19987 发表于 2013-8-19 07:00:56

不知道配置一个按键需要多少字节RAM?

ljmdzyx 发表于 2013-8-19 08:04:36

按键程序,继续收藏!

404710520 发表于 2013-8-19 08:07:53

mark                        

anvy178 发表于 2013-8-31 13:34:58

void breath_led(void)
{
    static uint16_t s_hwCounter = 0;
    static int16_t s_nGray = 0xFF;
   
    s_hwCounter++;
    if (!(s_hwCounter & (_BV(9)-1))) {
      s_nGray++;
      if (s_nGray == 0x1FF) {
            s_nGray = 0;
      }
    }
   
    set_led_gradation(ABS(s_nGray - 0xFF));
}

看了下你呼吸灯的程序段里静态局部变量 s_hwCounter 就随便它一直加,不加任何措施 ?这也行?

catwill 发表于 2013-8-31 13:58:59

anvy178 发表于 2013-8-31 13:34
void breath_led(void)
{
    static uint16_t s_hwCounter = 0;


会溢出,这里利用了这点

anvy178 发表于 2013-8-31 14:12:00

catwill 发表于 2013-8-31 13:58 static/image/common/back.gif
会溢出,这里利用了这点

溢出的 结果是 0还行 不是的话 就惨了

catwill 发表于 2013-8-31 15:06:26

anvy178 发表于 2013-8-31 14:12
溢出的 结果是 0还行 不是的话 就惨了

无符号数,溢出的结果是0

anvy178 发表于 2013-8-31 15:53:40

本帖最后由 anvy178 于 2013-8-31 15:55 编辑

catwill 发表于 2013-8-31 15:06 static/image/common/back.gif
无符号数,溢出的结果是0

找到了

bondxie3 发表于 2013-9-3 08:17:26

标记学习,按键经典程序.

ZYBing 发表于 2013-9-11 20:07:36

感谢分享!

jz701209李 发表于 2013-9-14 21:34:38

学习学习,谢谢

GZZXB 发表于 2013-9-17 22:56:12

不错名师出高徒

sunshulin 发表于 2013-9-29 19:33:22

{:victory:}

Jach_cc 发表于 2013-9-29 21:25:47

模块化的程序便于重复移植使用。其他人如果想用,那就必须体会到这个程序的优点。

amnumber 发表于 2013-9-29 21:30:42

初学者..正需要这些呢

wtliu 发表于 2013-9-30 09:15:44

可以有按键连击吗?
许多情况下按键需要有按住一个键不松手,一定时间后按键会自动按一个固定时间连续输出。这个键一般用在数据的加减设置中。希望楼主能增加这个功能。

y574924080 发表于 2013-9-30 09:23:23

wtliu 发表于 2013-9-30 09:15
可以有按键连击吗?
许多情况下按键需要有按住一个键不松手,一定时间后按键会自动按一个固定时间连续输出 ...

已经支持这个功能啊

JESTER9 发表于 2013-9-30 09:31:54

谢谢分享

caoxinkafei 发表于 2013-9-30 14:42:47

好贴,Mark

bin060117 发表于 2013-10-1 16:32:57

{:smile:}不错,收藏了

262619890 发表于 2013-10-6 13:59:22

mark               

滴答滴答下雨啦 发表于 2013-10-6 23:28:13

学习啊学习……

zy0818 发表于 2013-10-9 01:44:11

谢谢分享~~~

fenger32600 发表于 2013-10-9 08:08:28

收藏一个,赞一个。

gmajvfhpa 发表于 2013-10-9 08:29:47

mark 这个肯定会用到

tacbo2012 发表于 2013-10-10 18:21:32

怎么弄得和系统一样,如果写简单的程序 没必要这么复杂吧

Gorgon_Meducer 发表于 2013-10-10 18:37:03

tacbo2012 发表于 2013-10-10 18:21 static/image/common/back.gif
怎么弄得和系统一样,如果写简单的程序 没必要这么复杂吧

不复杂……只是个简单的模块……

enovo2468 发表于 2013-10-10 19:11:38

谢谢,看看{:smile:}

BigWolf 发表于 2013-10-10 20:01:23

标记学习。               

32MCU 发表于 2013-10-10 20:33:33

标记一下,备用.

四轴飞行器 发表于 2013-10-10 20:44:47

看的很纠结看不懂的说

Gorgon_Meducer 发表于 2013-10-11 11:03:41

四轴飞行器 发表于 2013-10-10 20:44 static/image/common/back.gif
看的很纠结看不懂的说

罗马都不是一日建成的,不必纠结。首先从会用开始,你觉得如何呢?

四轴飞行器 发表于 2013-10-11 11:06:05

Gorgon_Meducer 发表于 2013-10-11 11:03 static/image/common/back.gif
罗马都不是一日建成的,不必纠结。首先从会用开始,你觉得如何呢?

罗马是二日建成的?

最近搞定了按一下蜂鸣器响一下的难题,就是引用论坛里新的按键程序

想在弄个连按和长按功能,可惜你的看的很纠结啊

JESTER9 发表于 2013-10-11 11:14:40

好东西,学习了

Gorgon_Meducer 发表于 2013-10-11 13:00:33

四轴飞行器 发表于 2013-10-11 11:06 static/image/common/back.gif
罗马是二日建成的?

最近搞定了按一下蜂鸣器响一下的难题,就是引用论坛里新的按键程序


这是一个无需修改代码就可以使用的模块,你应该先根据帖子的内容学会使用,然后以后再考虑看
具体的实现。

kalo425 发表于 2013-10-11 16:40:09

Gorgon_Meducer 发表于 2013-10-11 13:00 static/image/common/back.gif
这是一个无需修改代码就可以使用的模块,你应该先根据帖子的内容学会使用,然后以后再考虑看
具体的实现 ...

key 和gpio 口 初始化的·····在哪里{:sweat:}key 值要是放在 枚举里面好不···

Gorgon_Meducer 发表于 2013-10-11 18:11:42

kalo425 发表于 2013-10-11 16:40 static/image/common/back.gif
key 和gpio 口 初始化的·····在哪里    key 值要是放在 枚举里面好不··· ...

Key和GPIO的初始化是用户自己处理,用户需要的是提供一个 键盘扫描函数(我们叫做前端处理),
这个函数的作用就是根据你的实际电路完成键盘扫描,并将扫描到的按键值作为函数返回值返回。
如果你已经完成了这样一个函数,那么具体如何将其注册到模块里面,就看楼主位了。

注意,键盘扫描函数是不需要作任何去抖操作的,直接返回键值即可。

这个模块的作用是提供中期和后期处理,包括去抖,识别按键,长按,重复按键,并将检测到的
按键放到一个模块自带的键盘缓冲区里面(对用户透明),同时还能提供诸如KEY_DOWN和KEY_UP
这样的信息。

justSaar 发表于 2013-10-11 18:31:30

不错的按键法

kalo425 发表于 2013-10-11 19:48:51

Gorgon_Meducer 发表于 2013-10-11 18:11 static/image/common/back.gif
Key和GPIO的初始化是用户自己处理,用户需要的是提供一个 键盘扫描函数(我们叫做前端处理),
这个函数 ...

谢谢你耐心的解答·····我看到fsm关键字了···还有个例子···参考下····你们好强···

Gorgon_Meducer 发表于 2013-10-11 19:53:55

kalo425 发表于 2013-10-11 19:48 static/image/common/back.gif
谢谢你耐心的解答·····我看到fsm关键字了···还有个例子···参考下····你们好强··· ...

期待你的使用感想和改进意见。

ZBLAMDZ 发表于 2013-10-15 20:56:22

不错,学习中

vpntest 发表于 2013-10-21 21:51:51

很想知道,那个呼吸灯是怎么实现的说

ltmooner 发表于 2013-10-22 11:44:56

不错,很工整!

vpntest 发表于 2013-10-28 21:43:08

请问傻子LED模块中,
static void set_led_gradation(uint16_t hwLevel)
{
    static uint16_t s_hwCounter = 0;
   
    if (hwLevel >= s_hwCounter) {
      LED2_ON();
    } else {
      LED2_OFF();
    }
   
    s_hwCounter++;
    s_hwCounter &= 0x1FF;
}

#define ABS(__N)    ((__N) < 0 ? -(__N) : (__N))
#define _BV(bit) (1<<(bit))

void breath_led(void)
{
    static uint16_t s_hwCounter = 0;
    static int16_t s_nGray = 0xFF;
   
    s_hwCounter++;
    if (!(s_hwCounter & (_BV(9)-1))) {
      s_nGray++;
      if (s_nGray == 0x1FF) {
            s_nGray = 0;
      }
    }
   
    set_led_gradation(ABS(s_nGray - 0xFF));
}



set_led_gradation(ABS(s_nGray - 0xFF));
这句应该如何理解呢,为什么?为什么要取绝对值呢,能讲解下原理吗??

y574924080 发表于 2013-10-28 23:01:20

vpntest 发表于 2013-10-28 21:43 static/image/common/back.gif
请问傻子LED模块中,
static void set_led_gradation(uint16_t hwLevel)
{


set_led_gradation()的参数表示的就是亮度,

取绝对值就是为了实现由小到大,再由大到小,

该实现的功能是:LED由明到暗,再由暗到明,如此循环往复

Gorgon_Meducer 发表于 2013-11-6 17:33:38

更新数据流图到楼主位,流程图也将尽快更新

tlsmf 发表于 2013-11-7 13:07:50

学习            

xyz2008 发表于 2013-11-22 10:39:26

虽然没有,完全看懂,但应该是可以用了,很好,很强大
页: [1] 2 3 4 5 6
查看完整版本: [分享][交流]发一个通用按键模块,简单易用 [2014-3-24 Update]