搜索
bottom↓
回复: 580

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

  [复制链接]

出0入0汤圆

发表于 2013-7-17 18:56:42 | 显示全部楼层 |阅读模式
本帖最后由 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中编写好了该函数:
  1. #define KEY_1                1
  2. #define KEY_2                2
  3. /*************************************************************************
  4. * Function Name: get_key_scan_value
  5. * Parameters: void
  6. * Return: return key value
  7. *
  8. * Description:
  9. *
  10. *************************************************************************/
  11. uint8_t get_key_scan_value(void)
  12. {
  13.     if (IS_KEY1_DOWN()) {   //该宏在平台搭建中有说明
  14.         return KEY_1;
  15.     }
  16.        
  17.     if (IS_KEY2_DOWN()) {   //该宏在平台搭建中有说明
  18.         return KEY_2;
  19.     }
  20.        
  21.     return KEY_NULL;
  22. }
复制代码
这里只是使用两个简单的独立按键。在实际工程应用中,可以根据你的情况来调整。需要
注意的是返回的键值不能为0 (它已经被KEY_NULL使用了)。

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

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

  5. #include "oopc.h

  6. #define KEY_QUEUE_SIZE                 10
  7. #define KEY_COUNT                         100
  8. #define KEY_LONG_TIME                 30000
  9. #define KEY_REPEAT_TIME                20000

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

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

  3. #include ".\app_cfg.h"

  4. #include "key_interface.h"

  5. #define KEY_NULL        0

  6. extern void init_key_task(void);
  7. extern bool key_task(void);
  8. extern bool get_key(key_event_t* ptKey);

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

key_interface.h

  1. typedef struct{
  2.     uint8_t chKeyValue;
  3.     key_status_t tEvent;
  4. }key_event_t;
复制代码
简单实用范例:

  1. do {
  2.     key_event_t tKey;
  3.     if  (!get_key(&tKey)) {
  4.         break;
  5.     }
  6.     if ((KEY_1 == tKey.chKeyValue) && (KEY_LONG_PRESSED == tKey.tEvent)) {
  7.     //! 识别KEY_1的长按键事件
  8.     …
  9.     }
  10. } while(false)
复制代码
说了那么多,还没有上代码呢,请看下面的DEMO:

  1. #include “key.h”

  2. /*************************************************************************
  3. * Function Name: main
  4. * Parameters: none
  5. *
  6. * Return: none
  7. *
  8. * Description: main
  9. *
  10. *************************************************************************/
  11. int main(void)
  12. {
  13.     …
  14.     // init_key_task ()初始化时调用一次即可
  15.     init_key_task ();
  16.     …
  17.     while(1) {      
  18.         // key_task()需要在超级循环或者定时器中断处理程序中被周期性的调用      
  19.         key_task();
  20.         //在这里添加你的按键应用代码
  21.         key_app();
  22.         …
  23.     }
  24. }
  25.        

  26. /*************************************************************************
  27. * Function Name: key_app
  28. * Parameters: void
  29. * Return: return FSM state
  30. *
  31. * Description:
  32. *
  33. *************************************************************************/
  34. static bool key_app(void)
  35. {
  36.     static uint8_t s_chState = KEY_APP_START;
  37.     static key_event_t s_tKey = {KEY_NULL, KEY_UP};
  38.     switch (s_chState) {
  39.         case KEY_APP_START:
  40.             s_chState = KEY_APP_GET;
  41.             //break;
  42.                        
  43.         case KEY_APP_GET:
  44.             if (get_key(&s_tKey)) {     //调用获取按键,根据按键键值和事件类型不同做不同的处理
  45.                 if (KEY_1 == s_tKey.chKeyValue) {                                       
  46.                     if (KEY_DOWN == s_tKey.tEvent) {
  47.                         s_chState = KEY_APP_DOWN;
  48.                     } else if (KEY_UP == s_tKey.tEvent) {
  49.                         s_chState = KEY_APP_UP;
  50.                     } else if (KEY_PRESSED == s_tKey.tEvent) {
  51.                         s_chState = KEY_APP_PRESSED;
  52.                    } else if (KEY_LONG_PRESSED == s_tKey.tEvent) {
  53.                        s_chState = KEY_APP_LONG_PRESSED;
  54.                    } else if (KEY_REPEAT == s_tKey.tEvent) {
  55.                        s_chState = KEY_APP_REPEAT;
  56.                    }
  57.                 } else if (KEY_2 == s_tKey.chKeyValue) {                                       
  58.                     if (KEY_DOWN == s_tKey.tEvent) {
  59.                         s_chState = KEY_APP_DOWN2;
  60.                     } else if (KEY_UP == s_tKey.tEvent) {
  61.                         s_chState = KEY_APP_UP2;
  62.                     } else if (KEY_PRESSED == s_tKey.tEvent) {
  63.                         s_chState = KEY_APP_PRESSED2;
  64.                     } else if (KEY_LONG_PRESSED == s_tKey.tEvent) {
  65.                         s_chState = KEY_APP_LONG_PRESSED2;
  66.                     } else if (KEY_REPEAT == s_tKey.tEvent) {
  67.                         s_chState = KEY_APP_REPEAT2;
  68.                     }
  69.                 }
  70.             }
  71.             break;
  72.                        
  73.         case KEY_APP_DOWN:
  74.             if (!print_key1_down()) {       //这是一个通过串口打印字符串"KEY1 DOWN\r\n"的状态机
  75.                 KEY_APP_RESET_FSM();
  76.                 return false;
  77.             }
  78.             break;
  79.                        
  80.         case KEY_APP_UP:
  81.             if (!print_key1_up()) {         //这是一个通过串口打印字符串"KEY1 UP\r\n"的状态机
  82.                 KEY_APP_RESET_FSM();
  83.                 return false;
  84.             }
  85.             break;
  86.                 …
  87.                 //省略一部分代码
  88. }
  89. }
复制代码
完整的范例,可以点这里下载:
效果图:


4、参数调整
        经过上面的几个步骤,按键模块已经可以使用了,当然不同MCU的速度不同,所以提供
了以下宏来调整参数,使之更符合你的情况。

  1. //内置队列大小
  2. #define KEY_QUEUE_SIZE                 10
  3. //按键连续检测次数
  4. #define CHECK_KEY_COUNT                 20
  5. //长按计数
  6. #define KEY_LONG_TIME                 30000
  7. //连击计数
  8. #define KEY_REPEAT_TIME                20000
复制代码
5、注意事项:
        A.本模块是基于全状态开发的,占用处理器时间及少,同时key_task()函数也需要在超
级循环或者定时器中断处理程序中被周期性的调用。
        B.有效键值不能为0 (KYE_NULL已经占用了键值0)

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



数据流图



状态图



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

阿莫论坛才是最爱国的,关心国家的经济、社会的发展、担心国家被别国牵连卷入战争、知道珍惜来之不易的和平发展,知道师夷之长,关注世界的先进文化与技术,也探讨中国文化的博大精深,也懂得警惕民粹主义的祸国殃民等等等等,无不是爱国忧民的表现。(坛友:tianxian)

出0入0汤圆

发表于 2013-7-17 19:02:14 | 显示全部楼层
高手,真的是高手,果然是精华帖,先MARK一下,下次再来看

出0入0汤圆

发表于 2013-7-17 19:17:51 | 显示全部楼层
好贴,顶起

出0入264汤圆

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

调用方式:

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2013-7-17 19:39:14 | 显示全部楼层
没有矩阵的吗?单按键口IO耗费比较大呀

出0入0汤圆

 楼主| 发表于 2013-7-17 20:06:29 来自手机 | 显示全部楼层
mcu_lover 发表于 2013-7-17 19:38
呵呵,不错。我已经用了好几年了。和你的方式一模一样,调用接口也一致,不同的是我把键值和按键状态封装在 ...

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

出0入4汤圆

发表于 2013-7-17 20:06:49 | 显示全部楼层
mark,学习

出0入0汤圆

 楼主| 发表于 2013-7-17 20:09:44 来自手机 | 显示全部楼层
bbsview 发表于 2013-7-17 19:39
没有矩阵的吗?单按键口IO耗费比较大呀

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

出0入0汤圆

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

这代码写得好漂亮啊。

按键状态3个位不够用吗

出0入0汤圆

发表于 2013-7-17 20:28:48 | 显示全部楼层
本帖最后由 zhanghuhhhhh 于 2013-7-17 20:36 编辑

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



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

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

出0入0汤圆

发表于 2013-7-17 20:35:13 | 显示全部楼层
学习了,楼主和mcu_lover的方法都不错,话说很期待mcu_lover博文更新。

出0入264汤圆

发表于 2013-7-17 20:43:37 | 显示全部楼层
SNOOKER 发表于 2013-7-17 20:22
这代码写得好漂亮啊。

按键状态3个位不够用吗

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

出0入0汤圆

 楼主| 发表于 2013-7-17 21:26:23 | 显示全部楼层
zhanghuhhhhh 发表于 2013-7-17 20:28
买了傻孩子的书。发现函数和变量名,没有楼上的mcu_lover   写的好。有可能是写大的工程多了,养成的习惯, ...

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

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

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

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

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

出0入0汤圆

发表于 2013-7-17 21:38:49 | 显示全部楼层
zhanghuhhhhh 发表于 2013-7-17 20:28
买了傻孩子的书。发现函数和变量名,没有楼上的mcu_lover   写的好。有可能是写大的工程多了,养成的习惯, ...

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

出0入296汤圆

发表于 2013-7-17 21:40:42 | 显示全部楼层
zhanghuhhhhh 发表于 2013-7-17 20:28
买了傻孩子的书。发现函数和变量名,没有楼上的mcu_lover   写的好。有可能是写大的工程多了,养成的习惯, ...

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

出0入0汤圆

发表于 2013-7-17 21:47:31 | 显示全部楼层
各人面向的价层不一样吧。

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

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

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

出0入0汤圆

发表于 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;
}
void  WhichKeyIsShortPress(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;
}

void  WhichKeyIsLongPress(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();
}

出0入0汤圆

发表于 2013-7-17 21:52:19 | 显示全部楼层
不错,很工整!

出0入296汤圆

发表于 2013-7-17 21:52:59 | 显示全部楼层
zhanghuhhhhh 发表于 2013-7-17 21:51
发一下我的按键程序吧。

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

多谢分享

出0入0汤圆

发表于 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;
         */
}

出0入0汤圆

发表于 2013-7-17 23:39:40 | 显示全部楼层
标记下,以后能用到!谢谢分享!

出0入0汤圆

发表于 2013-7-18 00:29:20 | 显示全部楼层
标记一下,备用

出0入0汤圆

发表于 2013-7-18 00:31:57 | 显示全部楼层
学习,mark,谢谢

出0入0汤圆

发表于 2013-7-18 06:28:08 | 显示全部楼层
好东西,,,

出0入0汤圆

发表于 2013-7-18 07:47:24 | 显示全部楼层
阅读完了代码,很标准的状态机按键程序,初学者可以学习一下。

出0入0汤圆

发表于 2013-7-18 10:01:26 | 显示全部楼层
很工整,以后能用上的。

出0入0汤圆

发表于 2013-7-18 12:44:36 | 显示全部楼层
不错不错。好好学习下。

出0入0汤圆

发表于 2013-7-18 12:52:59 | 显示全部楼层
不错。mark

出0入0汤圆

发表于 2013-7-18 13:11:22 | 显示全部楼层
学习,mark

出0入0汤圆

发表于 2013-7-18 14:58:36 | 显示全部楼层
mark下回去好好研读下

出0入0汤圆

发表于 2013-7-18 16:50:34 | 显示全部楼层
不错学习了

出0入0汤圆

发表于 2013-7-18 17:04:47 | 显示全部楼层
不错  收藏!~

出0入0汤圆

发表于 2013-7-18 17:08:21 | 显示全部楼层
不错

出0入0汤圆

发表于 2013-7-23 13:22:55 | 显示全部楼层
mark 值得好好学习

出0入0汤圆

发表于 2013-7-23 15:55:14 来自手机 | 显示全部楼层
mark      收藏了

出0入76汤圆

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

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

出0入0汤圆

发表于 2013-7-29 14:01:19 | 显示全部楼层
这个按键方式好用

出0入0汤圆

发表于 2013-7-30 11:42:29 | 显示全部楼层
lz能否从顶层讲解一下,整体的流程。
这样对于看code也是有效的。
传递的更多是思想。

出0入0汤圆

发表于 2013-8-1 14:16:25 | 显示全部楼层
收藏了哈..俺是初学者..正需要这些呢.会一定加把劲好好学些的..~~~~

出0入0汤圆

发表于 2013-8-4 20:43:11 | 显示全部楼层
恩恩   学习了

出0入0汤圆

发表于 2013-8-4 21:38:34 | 显示全部楼层
cool,绑定

出0入0汤圆

发表于 2013-8-4 21:53:41 | 显示全部楼层
mark一下

出0入0汤圆

发表于 2013-8-5 17:43:50 | 显示全部楼层
mark 发一个通用按键模块,简单易用

出0入0汤圆

发表于 2013-8-5 18:07:44 | 显示全部楼层
好贴,很强大.

出0入0汤圆

发表于 2013-8-12 20:56:03 | 显示全部楼层
mark,学习了!

出0入0汤圆

发表于 2013-8-13 14:04:24 | 显示全部楼层
标记下,以后能用到!谢谢分享!

出0入0汤圆

发表于 2013-8-14 09:05:42 | 显示全部楼层
y574924080 发表于 2013-7-17 20:09
无论是独立按键还是矩阵按键,都可以使用这个模块,它们只有获取键值函数不一样,这是由用户自己编写的 ...

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

出0入0汤圆

 楼主| 发表于 2013-8-14 21:09:45 | 显示全部楼层
jlian168 发表于 2013-8-14 09:05
Sir:
没有矩阵的吗?
Thank you.

这个由用户自己实现来的

出0入0汤圆

 楼主| 发表于 2013-8-14 21:10:33 | 显示全部楼层
zzjjhh250 发表于 2013-7-30 11:42
lz能否从顶层讲解一下,整体的流程。
这样对于看code也是有效的。
传递的更多是思想。 ...

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

出0入0汤圆

发表于 2013-8-18 22:18:37 | 显示全部楼层
mark一记

出0入0汤圆

发表于 2013-8-18 22:41:20 | 显示全部楼层
谢谢,学习了.

出0入0汤圆

发表于 2013-8-18 22:52:48 | 显示全部楼层
学习一下,以后可能会用到

出0入0汤圆

发表于 2013-8-19 07:00:56 来自手机 | 显示全部楼层
不知道配置一个按键需要多少字节RAM?

出0入0汤圆

发表于 2013-8-19 08:04:36 来自手机 | 显示全部楼层
按键程序,继续收藏!

出0入0汤圆

发表于 2013-8-19 08:07:53 | 显示全部楼层
mark                        

出0入0汤圆

发表于 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 就随便它一直加  ,不加任何措施 ?这也行?

出0入0汤圆

发表于 2013-8-31 13:58:59 来自手机 | 显示全部楼层
anvy178 发表于 2013-8-31 13:34
void breath_led(void)
{
    static uint16_t s_hwCounter = 0;

会溢出,这里利用了这点

出0入0汤圆

发表于 2013-8-31 14:12:00 | 显示全部楼层
catwill 发表于 2013-8-31 13:58
会溢出,这里利用了这点

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

出0入0汤圆

发表于 2013-8-31 15:06:26 来自手机 | 显示全部楼层
anvy178 发表于 2013-8-31 14:12
溢出的 结果是 0  还行 不是的话 就惨了

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

出0入0汤圆

发表于 2013-8-31 15:53:40 | 显示全部楼层
本帖最后由 anvy178 于 2013-8-31 15:55 编辑
catwill 发表于 2013-8-31 15:06
无符号数,溢出的结果是0


找到了

出0入0汤圆

发表于 2013-9-3 08:17:26 | 显示全部楼层
标记学习,按键经典程序.

出0入0汤圆

发表于 2013-9-11 20:07:36 | 显示全部楼层
感谢分享!

出0入0汤圆

发表于 2013-9-14 21:34:38 | 显示全部楼层
学习学习,谢谢

出0入36汤圆

发表于 2013-9-17 22:56:12 | 显示全部楼层
不错  名师出高徒

出0入0汤圆

发表于 2013-9-29 19:33:22 | 显示全部楼层

出0入0汤圆

发表于 2013-9-29 21:25:47 | 显示全部楼层
模块化的程序便于重复移植使用。其他人如果想用,那就必须体会到这个程序的优点。

出0入0汤圆

发表于 2013-9-29 21:30:42 | 显示全部楼层
初学者..正需要这些呢

出0入0汤圆

发表于 2013-9-30 09:15:44 | 显示全部楼层
可以有按键连击吗?
许多情况下按键需要有按住一个键不松手,一定时间后按键会自动按一个固定时间连续输出。这个键一般用在数据的加减设置中。希望楼主能增加这个功能。

出0入0汤圆

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

已经支持这个功能啊

出0入0汤圆

发表于 2013-9-30 09:31:54 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2013-9-30 14:42:47 | 显示全部楼层
好贴,Mark

出0入0汤圆

发表于 2013-10-1 16:32:57 | 显示全部楼层
不错,收藏了

出0入0汤圆

发表于 2013-10-6 13:59:22 | 显示全部楼层
mark               

出0入0汤圆

发表于 2013-10-6 23:28:13 | 显示全部楼层
学习啊学习……

出0入0汤圆

发表于 2013-10-9 01:44:11 来自手机 | 显示全部楼层
谢谢分享~~~

出0入0汤圆

发表于 2013-10-9 08:08:28 | 显示全部楼层
收藏一个,赞一个。

出0入0汤圆

发表于 2013-10-9 08:29:47 | 显示全部楼层
mark 这个肯定会用到

出0入0汤圆

发表于 2013-10-10 18:21:32 | 显示全部楼层
怎么弄得和系统一样,如果写简单的程序 没必要这么复杂吧

出0入296汤圆

发表于 2013-10-10 18:37:03 | 显示全部楼层
tacbo2012 发表于 2013-10-10 18:21
怎么弄得和系统一样,如果写简单的程序 没必要这么复杂吧

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

出0入0汤圆

发表于 2013-10-10 19:11:38 | 显示全部楼层
谢谢,看看

出0入0汤圆

发表于 2013-10-10 20:01:23 | 显示全部楼层
标记学习。               

出0入0汤圆

发表于 2013-10-10 20:33:33 | 显示全部楼层
标记一下,备用.

出0入0汤圆

发表于 2013-10-10 20:44:47 | 显示全部楼层
看的很纠结  看不懂的说

出0入296汤圆

发表于 2013-10-11 11:03:41 | 显示全部楼层
四轴飞行器 发表于 2013-10-10 20:44
看的很纠结  看不懂的说

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

出0入0汤圆

发表于 2013-10-11 11:06:05 | 显示全部楼层
Gorgon_Meducer 发表于 2013-10-11 11:03
罗马都不是一日建成的,不必纠结。首先从会用开始,你觉得如何呢?

罗马是二日建成的?

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

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

出0入0汤圆

发表于 2013-10-11 11:14:40 | 显示全部楼层
好东西,学习了

出0入296汤圆

发表于 2013-10-11 13:00:33 | 显示全部楼层
四轴飞行器 发表于 2013-10-11 11:06
罗马是二日建成的?

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

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

出0入0汤圆

发表于 2013-10-11 16:40:09 | 显示全部楼层
Gorgon_Meducer 发表于 2013-10-11 13:00
这是一个无需修改代码就可以使用的模块,你应该先根据帖子的内容学会使用,然后以后再考虑看
具体的实现 ...

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

出0入296汤圆

发表于 2013-10-11 18:11:42 | 显示全部楼层
kalo425 发表于 2013-10-11 16:40
key 和  gpio 口 初始化的·····在哪里    key 值要是放在 枚举里面好不··· ...

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

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

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

出0入0汤圆

发表于 2013-10-11 18:31:30 | 显示全部楼层
不错的按键法

出0入0汤圆

发表于 2013-10-11 19:48:51 | 显示全部楼层
Gorgon_Meducer 发表于 2013-10-11 18:11
Key和GPIO的初始化是用户自己处理,用户需要的是提供一个 键盘扫描函数(我们叫做前端处理),
这个函数 ...

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

出0入296汤圆

发表于 2013-10-11 19:53:55 | 显示全部楼层
kalo425 发表于 2013-10-11 19:48
谢谢你耐心的解答·····我看到fsm关键字了···还有个例子···参考下····你们好强··· ...

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

出0入0汤圆

发表于 2013-10-15 20:56:22 | 显示全部楼层
不错,学习中

出0入0汤圆

发表于 2013-10-21 21:51:51 | 显示全部楼层
很想知道,那个呼吸灯是怎么实现的说

出0入0汤圆

发表于 2013-10-22 11:44:56 | 显示全部楼层
不错,很工整!

出0入0汤圆

发表于 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));
这句应该如何理解呢,为什么?为什么要取绝对值呢,能讲解下原理吗??

出0入0汤圆

 楼主| 发表于 2013-10-28 23:01:20 | 显示全部楼层
vpntest 发表于 2013-10-28 21:43
请问傻子LED模块中,
static void set_led_gradation(uint16_t hwLevel)
{

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

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

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

出0入296汤圆

发表于 2013-11-6 17:33:38 | 显示全部楼层
更新数据流图到楼主位,流程图也将尽快更新

出0入0汤圆

发表于 2013-11-7 13:07:50 | 显示全部楼层
学习            

出0入0汤圆

发表于 2013-11-22 10:39:26 | 显示全部楼层
虽然没有,完全看懂,但应该是可以用了,很好,很强大
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-17 05:40

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表