搜索
bottom↓
楼主: y574924080

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

  [复制链接]

出425入0汤圆

发表于 2014-3-31 16:20:52 | 显示全部楼层
本帖最后由 guolun 于 2014-3-31 16:24 编辑
foxpro2005 发表于 2014-3-9 23:13
今天有时间看了一下代码,感觉还可以做如下优化:
(声明,本人是小白菜,说错了还望包涵... )
...


我喜欢把注释调成很淡的颜色。这样的话,突出代码,注释淡化。(利用摄影中的背景虚化的想法。)

本帖子中包含更多资源

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

x

出0入296汤圆

发表于 2014-4-1 10:43:22 | 显示全部楼层
guolun 发表于 2014-3-31 16:20
我喜欢把注释调成很淡的颜色。这样的话,突出代码,注释淡化。(利用摄影中的背景虚化的想法。)
...

这个想法不错

出0入0汤圆

发表于 2014-4-1 13:59:02 | 显示全部楼层
收藏,学习!

出0入0汤圆

发表于 2014-4-2 11:07:13 | 显示全部楼层
请问楼主END_DEF_CLASS中:
sizeof(uint_fast8_t) - 1
要加这个是什么意思,不就是0么?难道有的mcuuint_fast8_t不是1字节?

出0入0汤圆

发表于 2014-4-2 11:11:38 | 显示全部楼层
另外,为什么要定义struct+union?union有特殊用途?
感觉还是《UML+OOPC嵌入式C语言开发精讲》书中讲述的CLASS定义简单明了。

出0入0汤圆

发表于 2014-4-2 11:18:22 | 显示全部楼层
好有前途的说!

出0入0汤圆

 楼主| 发表于 2014-4-2 11:18:49 | 显示全部楼层
bondxie3 发表于 2014-4-2 11:07
请问楼主END_DEF_CLASS中:
sizeof(uint_fast8_t) - 1
要加这个是什么意思,不就是0么?难道有的mcuuint_f ...

uint_fast8_t 还真不一定是8位的,请看这里:

C_data_types(wiki)

出200入0汤圆

发表于 2014-4-2 11:19:20 来自手机 | 显示全部楼层
收藏一个,赞一个。

出0入0汤圆

 楼主| 发表于 2014-4-2 11:21:31 | 显示全部楼层
bondxie3 发表于 2014-4-2 11:11
另外,为什么要定义struct+union?union有特殊用途?
感觉还是《UML+OOPC嵌入式C语言开发精讲》书中讲述的C ...

这是一个封装技巧

具体请看 [交流][微知识]模块的封装(一):C语言类的封装

出0入0汤圆

发表于 2014-4-2 11:24:50 | 显示全部楼层
高高手。。

出0入0汤圆

发表于 2014-4-2 13:03:53 | 显示全部楼层
y574924080 发表于 2014-4-2 11:21
这是一个封装技巧

具体请看 [交流][微知识]模块的封装(一):C语言类的封装 ...

谢谢楼主,http://www.cnblogs.com/dylan2011/archive/2012/09/18/2690580.html  供大家参考抽象数据类型的介绍。

出10入0汤圆

发表于 2014-4-2 14:14:35 | 显示全部楼层

这些肯定会用到,稍后慢慢仔细阅读

出0入0汤圆

发表于 2014-4-8 18:07:15 | 显示全部楼层
在QUEUE操作中关中断还是存在问题,什么情况?

出0入0汤圆

发表于 2014-4-8 22:06:29 | 显示全部楼层
写过矩阵的吗?

出0入0汤圆

 楼主| 发表于 2014-4-8 22:16:16 | 显示全部楼层
wxty 发表于 2014-4-8 18:07
在QUEUE操作中关中断还是存在问题,什么情况?

有什么问题?能具体描述一下么?

我这边进行过简单的测试,没有发现问题

出0入0汤圆

发表于 2014-4-9 07:31:26 | 显示全部楼层
谢谢分享

出0入8汤圆

发表于 2014-4-9 08:42:30 | 显示全部楼层
写的很好

出0入0汤圆

发表于 2014-4-9 11:19:14 | 显示全部楼层
y574924080 发表于 2014-4-8 22:16
有什么问题?能具体描述一下么?

我这边进行过简单的测试,没有发现问题

现象是,从队列中取出消息时,会多取,如图:


消息入队列没问题,短按一次,共3个消息: KEY_DONW / KEY_UP / KEY_PRESSED 共三个消息,取了4次才取完。
随机的,一个消息可能会取多次,直到队列为空,楼主可以用串口测试下,每取一次发送一次看看。

本帖子中包含更多资源

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

x

出0入0汤圆

发表于 2014-4-9 11:29:53 | 显示全部楼层
果断收藏!

出0入0汤圆

发表于 2014-4-9 11:37:18 | 显示全部楼层

本帖子中包含更多资源

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

x

出0入0汤圆

 楼主| 发表于 2014-4-9 12:33:05 | 显示全部楼层
wxty 发表于 2014-4-9 11:19
现象是,从队列中取出消息时,会多取,如图:

我这边验证过这个,确实没有问题

另外有个想确认一下,你的开关全局中断的函数能保证原子性么?

出0入0汤圆

 楼主| 发表于 2014-4-9 12:34:55 | 显示全部楼层

不好意思,我这边没办法复现这个问题

能问一下开关中断函数是怎么实现的么?

这里的开关中断函数需要保证原子的

出0入0汤圆

发表于 2014-4-9 12:40:56 | 显示全部楼层
y574924080 发表于 2014-4-9 12:34
不好意思,我这边没办法复现这个问题

能问一下开关中断函数是怎么实现的么?

  1. #include <intrins.h>
  2. //提供
  3. enable_interrupt();
  4. disable_interrupt();
复制代码

编译器头文件自带的,应该能保证吧。

出0入0汤圆

 楼主| 发表于 2014-4-9 14:18:23 | 显示全部楼层
本帖最后由 y574924080 于 2014-4-9 14:25 编辑

不好意思,看错了

出0入0汤圆

 楼主| 发表于 2014-4-9 15:05:13 | 显示全部楼层
wxty 发表于 2014-4-9 12:40
编译器头文件自带的,应该能保证吧。

我这边怎么也无法重现这个问题。

如果能提供一个范例,重现这个问题的话,我可以尝试找是哪里出现bug

出0入0汤圆

发表于 2014-4-9 15:37:11 | 显示全部楼层
好贴,谢谢分享

出0入0汤圆

发表于 2014-4-9 16:46:27 | 显示全部楼层
本帖最后由 wxty 于 2014-4-9 16:51 编辑
y574924080 发表于 2014-4-9 15:05
我这边怎么也无法重现这个问题。

如果能提供一个范例,重现这个问题的话,我可以尝试找是哪里出现bug {: ...


谢谢啊,分析了很久,找到了出问题的地方。
队列的入队出队部分没有问题,问题在主循环中调用
  1. GetKeyEvent(key_event_t* ptdKey)
  2. {
  3.     return KeyEventDeQueue(&stdKeyDetectQueue, ptdKey);
  4. }
复制代码

函数时,出现了问题:
当队列无消息(队列为空)时,本应返回FALSE,却返回了TRUE,所以向串口又发送了一次上次发送的数据。
仔细观察DeQueue()函数内部代码,尚不明白队列为空时如何产生的TRUE返回值。
调试时,bn值为TRUE(非零,却不为0x01)的现象。
分别增加了几个计数器用于调试:

队列操作计数器,入队次数==出队次数。

主循环获得消息次数却大于队列操作中的出队次数。说明在队列为空时,获取消息函数返回了TURE。

另外,我用的是8位单片机,KeyTask()每5ms中断中调用一次,GetKeyEvent()函数在主循环中获取消息并处理。
按键处理函数
  1. #define KEY_1  1
  2. uint8_t ScanKeyVal(void)
  3. {
  4.     if(!P0.0)
  5.     {
  6.         return KEY_1;
  7.     }
  8.     return KEY_NULL;
  9. }
复制代码


宏定义:
  1. #ifndef FALSE
  2. #define FALSE (0)
  3. #endif

  4. #ifdef TRUE
  5. #undef TRUE
  6. #endif

  7. #define TRUE (!FALSE)
复制代码

编辑:增加代码。

本帖子中包含更多资源

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

x

出0入0汤圆

发表于 2014-4-9 20:06:17 | 显示全部楼层
学习,谢谢

出0入0汤圆

 楼主| 发表于 2014-4-9 21:50:22 | 显示全部楼层
wxty 发表于 2014-4-9 16:46
谢谢啊,分析了很久,找到了出问题的地方。
队列的入队出队部分没有问题,问题在主循环中调用

具体问题在哪里我也不能确定

不过我觉得有个需要注意的是:不要和TRUE进行比较(即只和FALSE比较)

因为这会导致本来TRUE的情况变成FALSE。。。。。。

要不修复这个小问题先?

出0入0汤圆

发表于 2014-4-10 10:28:46 | 显示全部楼层
本帖最后由 wxty 于 2014-4-10 11:02 编辑
y574924080 发表于 2014-4-9 21:50
具体问题在哪里我也不能确定

不过我觉得有个需要注意的是:不要和TRUE进行比较(即只和FALSE比较)


嗯,还是按原来的方法处理,把开关中断放到出队列函数外面就OK了。
  1. BOOL GetKeyEvent(key_event_t* ptdKey) //主循环中获取消息并处理,KeyTask()还是放在5MS中断中处理的。
  2. {
  3.         BOOL bn;
  4.        
  5.         disable_interrupt(); // 外部关了中断,队列操作内部不需要再关中断

  6.         bn = KeyEventDeQueue(&stdKeyDetectQueue, ptdKey);

  7.         enable_interrupt(); //然后就一切正常了
  8.    
  9.         return bn; //KeyEventDeQueue(&stdKeyDetectQueue, ptdKey);
  10. }
复制代码

显示,AD采样,按键,消息入队出队都正常,程序应该没有跑飞。
采用在出队列操作函数内部开关中断时,不知道发生了什么,KeyEventDeQueue()函数返回的BOOL值不正确,队列为空时,不仅返回了TRUE(0X01),还有其他不为FALSE(0X00)的情况,非零的随机数。

编辑:添加注释。

出0入0汤圆

发表于 2014-4-10 10:35:17 | 显示全部楼层
附图一张。
串口接收字节:
后半字节表示键值,这里全为1;
前半字节表示按键事件0-UP,1-DOWN,2-PRESSED,3-DBL_PRESSED,4-LONG_PRESSED,5-REPEAT
入队出队计数器,主循环中获取消息次数三者保持一致。

本帖子中包含更多资源

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

x

出0入0汤圆

 楼主| 发表于 2014-4-10 14:54:03 | 显示全部楼层
wxty 发表于 2014-4-10 10:28
嗯,还是按原来的方法处理,把开关中断放到出队列函数外面就OK了。

显示,AD采样,按键,消息入队出队都 ...

      好吧,理解不能。。。。

      开关中断是为了保护共享资源的不得不做的操作,
但是开关中断的时间应该尽量短。

      能不能做这个尝试:一步一步缩小开关中断的范围,
确定最小的能工作的范围,说不定能找到问题所在

出0入0汤圆

发表于 2014-4-10 18:18:27 | 显示全部楼层
y574924080 发表于 2014-4-10 14:54
好吧,理解不能。。。。

      开关中断是为了保护共享资源的不得不做的操作,

嗯,经过确认,堆栈余量还很大。

在DeQueue()函数内部开关中断,怎么都不行;不作开关中断处理,还是一样的问题现象。
必须要在函数DeQueue()外部开关中断就正常了。
另外,如果将KeyTask()也放在主循环中,结果是正常的。

实在是不知道为什么了。

分析了一下,其实DeQueue()的重入应该不存在操作共享资源的问题。
昨晚在某16位单片机,32M频率下,KeyTask()放在中断中,DeQueue()放在主循环,没有任何开关中断处理,结果是正常的。
但是对于这款8位单片机,4M频率下运行,只要把KeyTask()放在中断中的话,就需要在DeQueue()外部开关中断,除非两者都放在主循环。

放弃继续往下分析了,按照如下处理:
  1. BOOL GetKeyEvent(key_event_t* ptdKey) //主循环调用,最终获取按键事件并处理。
  2. {
  3.         BOOL bn;
  4.        
  5.         disable_interrupt();
  6.         bn = KeyEventDeQueue(&stdKeyDetectQueue, ptdKey);
  7.         enable_interrupt();
  8.    
  9.         return bn; //KeyEventDeQueue(&stdKeyDetectQueue, ptdKey);
  10. }
复制代码

出0入0汤圆

 楼主| 发表于 2014-4-10 21:00:53 | 显示全部楼层
wxty 发表于 2014-4-10 18:18
嗯,经过确认,堆栈余量还很大。

在DeQueue()函数内部开关中断,怎么都不行;不作开关中断处理,还是一 ...

      对queue来说,enqueue和dequeue都使用了同样的静态变量,这些静态变量就是共享资源。

操作如果enqueue和dequeue不在同一任务平面,例如说enqueue在中断里,dequeue在主

循环,它们不在同一任务平面,这时候enqueue可能打断dequeue操作,出现不可预料的问

题。

      解决办法是加保护。我使用的是关中断保护,这里就要求关中断/关中断是原子的,也就是

开中断只需要一条指令,关中断也只需要一条指令。能确认你的8位MCU有相关的指令支持么?

出0入8汤圆

发表于 2014-4-11 01:07:49 来自手机 | 显示全部楼层
学习……世界有救啦……

出0入0汤圆

发表于 2014-4-11 06:11:50 | 显示全部楼层
收藏,谢谢分享

出0入0汤圆

发表于 2014-4-11 09:18:53 | 显示全部楼层
y574924080 发表于 2014-4-10 21:00
对queue来说,enqueue和dequeue都使用了同样的静态变量,这些静态变量就是共享资源。

操作如果enq ...

嗯,其他的不做评论,开关中断的原子性可以确定:

本帖子中包含更多资源

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

x

出0入0汤圆

发表于 2014-4-11 09:40:14 | 显示全部楼层
谢谢谢谢,改天试用下?!

出0入296汤圆

发表于 2014-4-11 10:26:34 | 显示全部楼层
wxty 发表于 2014-4-10 10:28
嗯,还是按原来的方法处理,把开关中断放到出队列函数外面就OK了。

显示,AD采样,按键,消息入队出队都 ...

什么编译器?什么芯片?

出0入0汤圆

发表于 2014-4-11 10:33:02 | 显示全部楼层
mark下,学习了

出0入0汤圆

发表于 2014-4-11 11:21:52 | 显示全部楼层
学习一下

出0入0汤圆

发表于 2014-4-11 11:44:07 | 显示全部楼层
果断mark啊,这么经典的东西。辛苦了,楼主!

出0入0汤圆

发表于 2014-4-11 13:41:49 | 显示全部楼层
本帖最后由 wxty 于 2014-4-11 16:44 编辑
Gorgon_Meducer 发表于 2014-4-11 10:26
什么编译器?什么芯片?


谢谢傻孩子,这颗芯片不是很常用,较老的RENESAS 740系列的,IDE是HEW,集成的ICC740编译器。
这个按键模块是健全的,其他片子测试也是正常的。应该是其他的原因,俺却无力分析出来。

编辑:修改编译器名称。

出0入296汤圆

发表于 2014-4-11 13:59:52 | 显示全部楼层
wxty 发表于 2014-4-11 13:41
谢谢傻孩子,这颗芯片不是很常用,较老的RENESAS 740系列的,IDE是HEW,集成的ICC740编译器。
这个按键模 ...

查一下编译器的栈结构,有可能不是标准的栈模型。比如IAR和ICC在AVR芯片上就不是标准的栈模型
——硬件栈(只负责PC指针)和软件栈(负责局部变量分配)就是分开的,这类情况下有可能导致,
看似程序正常执行,但是函数返回值总是出现莫名其妙的问题。

出0入0汤圆

发表于 2014-4-11 14:17:27 | 显示全部楼层
mark 一下

出0入0汤圆

发表于 2014-4-11 18:29:12 | 显示全部楼层
Gorgon_Meducer 发表于 2014-4-11 13:59
查一下编译器的栈结构,有可能不是标准的栈模型。比如IAR和ICC在AVR芯片上就不是标准的栈模型
——硬件栈 ...


偶买噶。我怀疑找到问题所在了。。。
关键代码如下:
  1. BOOL KeyEventDeQueue(key_queue_t * ptdKeyQueue, key_event_t *ptdKey)
  2. {
  3. //        BOOL bnReturn;

  4.         __key_queue_t *ptdQ;// = (__key_queue_t *)ptdKeyQueue;   //此处被中断,造成了后果。

  5. disable_interrupt();
  6.        
  7.         ptdQ = (__key_queue_t *)ptdKeyQueue; //放在这里后结果正常。
  8.        
  9.         //…………
复制代码

CSTACK地址范围0x0100~0x015f,向下增长型。如下图所示,可以看出余量还很大。

设置0X5A..0X5B等做标记,发现每次多发出的数据来栈顶地址0x0101开始的数据,每多发一次,地址往下加1。
注意,因为每次只进行了读操作,所以已使用的栈未遭到破坏,程序没有跑飞。
队列FrontQueue    开始地址0x01BC
队列DetectQueue  起始地址0X01C5
分析,不同于16/32位机,对于8位机单机来说,不能保证下面这条语句的原子性。
  1. __key_queue_t *ptdQ = (__key_queue_t *)ptdKeyQueue;
复制代码

一旦被打断,中断返回后,猜测ptdQ只得到了高字节地址(0X0100),则会得到依次从0x0101往下的数据。
只是DeQueue()的返回值(实际为uint8_t类型)不知道被存储在哪里的,也被打乱了。。。

编辑:请求傻孩子大哥解释。

本帖子中包含更多资源

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

x

出0入0汤圆

 楼主| 发表于 2014-4-11 19:34:07 来自手机 | 显示全部楼层
wxty 发表于 2014-4-11 18:29
偶买噶。我怀疑找到问题所在了。。。
关键代码如下:


我记得这句代码只是逻辑的转换,不应该生成代码的

出0入296汤圆

发表于 2014-4-13 23:07:01 | 显示全部楼层
y574924080 发表于 2014-4-11 19:34
我记得这句代码只是逻辑的转换,不应该生成代码的

取决于编译器了,有的编译器比较SB。还有,你看看队列类型是否加了volatile。

出0入296汤圆

发表于 2014-4-13 23:14:43 | 显示全部楼层
本帖最后由 Gorgon_Meducer 于 2014-4-14 00:39 编辑
wxty 发表于 2014-4-11 18:29
偶买噶。我怀疑找到问题所在了。。。
关键代码如下:


把代码恢复成肯定会出错的形式,然后把ptdQ变量的值(也就是指针的数值)打印出来。
理论上应该是个常熟。出错的时候应该可以打印出不同的数值出来。我大体知道怎么回事了。

出0入0汤圆

发表于 2014-4-14 08:43:08 | 显示全部楼层
顶一下,回头仔细看

出0入0汤圆

发表于 2014-4-14 09:00:02 | 显示全部楼层
简单易用啊!!

出0入0汤圆

发表于 2014-4-14 09:32:04 | 显示全部楼层
Gorgon_Meducer 发表于 2014-4-13 23:14
把代码恢复成肯定会出错的形式,然后把ptdQ变量的值(也就是指针的数值)打印出来。
理论上应该是个常熟 ...

看来可以确认了,如图RAM地址0X0101亮了。
串口打印出一次DeQueue的pBuff值为01 01,而打印的(A8 01)为FrontQueue的正确值,(B2 01)为DeQueue的正确值。


另外:

这条语句为一个先定义后赋值的语句,有不产生代码的编译器吗?

本帖子中包含更多资源

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

x

出0入0汤圆

 楼主| 发表于 2014-4-14 11:34:59 | 显示全部楼层
Gorgon_Meducer 发表于 2014-4-13 23:07
取决于编译器了,有的编译器比较SB。还有,你看看队列类型是否加了volatile。
...

没有加。。。。我用的是 DEF_CLASS

出0入0汤圆

 楼主| 发表于 2014-4-14 11:40:27 | 显示全部楼层
wxty 发表于 2014-4-14 09:32
看来可以确认了,如图RAM地址0X0101亮了。
串口打印出一次DeQueue的pBuff值为01 01,而打印的(A8 01)为 ...

因为是直接把形参进行类型转换,这只是逻辑上的转换而已,不应该生成代码的

出0入296汤圆

发表于 2014-4-14 16:38:22 | 显示全部楼层
wxty 发表于 2014-4-14 09:32
看来可以确认了,如图RAM地址0X0101亮了。
串口打印出一次DeQueue的pBuff值为01 01,而打印的(A8 01)为 ...

从汇编代码上看,好像只有一个通用寄存器啊……你确认是只有一个通用寄存器么?这个通用寄存器难道被中断
打断的时候不会被PUSH到栈里面,从中断退出以后再POP出来么?

感觉有点奇葩啊。你能沿着这个线索再去看看数据手册么?主要是看看通用寄存器,然后就是中断的出入栈。

出0入0汤圆

发表于 2014-4-29 10:53:10 | 显示全部楼层
没弄明白 两个app_cfg.h的包含关系

出0入296汤圆

发表于 2014-4-29 11:07:23 | 显示全部楼层
hongjie0216 发表于 2014-4-29 10:53
没弄明白 两个app_cfg.h的包含关系

每个app_cfg.h都自动引用上一级目录下的app_cfg.h,如此往复,直到顶层。

本帖子中包含更多资源

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

x

出0入0汤圆

发表于 2014-4-29 14:50:24 | 显示全部楼层
这个实在是太强大的!

出0入0汤圆

发表于 2014-4-29 15:47:56 | 显示全部楼层
本帖最后由 yutianku 于 2014-4-29 15:50 编辑

有在51上移植成功的大侠吗?一步一步来的,keil编译老是不过,求指教
keil中似乎找不到stdint.h stdbool.h这几个头文件……

本帖子中包含更多资源

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

x

出0入0汤圆

发表于 2014-4-29 16:46:15 | 显示全部楼层
本帖最后由 Gorgon_Meducer 于 2014-4-29 16:59 编辑

51上可以自己写这两个文件~
但是不要用这个名字就好了——如果以后keilc51编写了这两个文件,你的文件就和系统文件重名了。
只是定义了常用的类型
文件的内容可以类似这样:


  1. /* 定义数据类型 ------------------------------------------------------------- */
  2. typedef unsigned char        uint8_t;
  3. typedef signed char                int8_t;
  4. typedef unsigned int        uint16_t;
  5. typedef signed int                int16_t;
  6. typedef unsigned long        uint32_t;
  7. typedef signed long                int32_t;

  8. typedef uint8_t                        bool;
  9. #define false        0
  10. #define true        (!false)
复制代码

写在一个文件里也可以~

出0入0汤圆

发表于 2014-4-29 17:07:18 | 显示全部楼层
catwill 发表于 2014-4-29 16:46
51上可以自己写这两个文件~
但是不要用这个名字就好了——如果以后keilc51编写了这两个文件,你的文件就和 ...

多谢指点!
OOPC.h文件,没整明白,编译还是报错!

union是否需要定义一下呢?

本帖子中包含更多资源

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

x

出0入296汤圆

发表于 2014-4-29 18:36:00 | 显示全部楼层
本帖最后由 Gorgon_Meducer 于 2014-4-29 18:40 编辑
yutianku 发表于 2014-4-29 17:07
多谢指点!
OOPC.h文件,没整明白,编译还是报错!


你的编译器不支持C99,你找一个支持C99的Keil版本看看。

实在不行,可能要改写部分宏。你先试试看,是否能找到支持C99的Keil。


你也可以先尝试将那一行里面的“...”删除掉,然后把第二行 __VA_ARGS__ 整行删除掉,务必确保宏续航符“\”后面没有任何字符(包括空格)
也就是用下面的内容来替换


  1. #define EXTERN_CLASS(__NAME)    \
  2.     typedef union __NAME __NAME;\
  3.     union __NAME {\
  4.         uint_fast8_t chMask[(sizeof(struct{
复制代码


后面还有类似问题,尝试相同的方法处理。

出0入0汤圆

发表于 2014-4-29 20:51:57 | 显示全部楼层
mark 11111

出0入8汤圆

发表于 2014-4-29 21:28:14 | 显示全部楼层
高手        

出0入0汤圆

发表于 2014-4-30 23:15:55 | 显示全部楼层
Gorgon_Meducer 发表于 2014-4-29 18:36
你的编译器不支持C99,你找一个支持C99的Keil版本看看。

实在不行,可能要改写部分宏。你先试试看,是否 ...

感谢大师的指点!
按照您的指点修改相关宏之后再编译,keil不再报以上错误;又折腾了一下午移植到51单片机基本成功!小结一下:
1、模块中宏定义变量较多,keil编译后生成的hex较大,flash较小的单片机如STC12C2052(2KB),可能不能下载,​提​示​“​件​大​小​超​出​范​围​,​超​出​部​分​已​被​自​动​截​取,换成STC12C5410(10K)后下载成功,此问题也可能是keil和谐的缘故造成……
2、keil2和keil4均不支持C99,不清楚其他版本keil是否支持…?  模块中用到的stdint.h stdbool.h这几个头文件所包含的数据类型定义需要手动添加,如大侠“catwill”所述:
/* 定义数据类型 ------------------------------------------------------------- */
typedef unsigned char        uint8_t;
typedef signed char                int8_t;
typedef unsigned int        uint16_t;
typedef signed int                int16_t;
typedef unsigned long        uint32_t;
typedef signed long                int32_t;

/** Fast types.  */
/** Signed.  */
typedef signed char                int_fast8_t;
/** Unsigned.  */
typedef unsigned char                uint_fast8_t;
typedef uint8_t                        bool;
#define false        0
#define true        (!false)
#define NULL ((void *)0)    //定义空指针变量

另外,oopc.H部分按照”傻孩子“大师指点修改。
3、模型文件有少许错误,需要修改
,key_interface.h文件中的枚举定义最后一个量不应该有标点符号,这个问题比较难发现,找了很久才找到,汗……,不过奇怪的是keil4中居然不报错!
,bool print_key1_down(void)相关函数的串口函数需要修改;
4、                key_task();
                key_app();貌似只有在超级循环中才有用,在定时器中断处理程序中被周期性的调用 不正常,不知何故……
5、目前还存在一些问题,多次按键程序易卡死,长按与连按还不能很好区分……
总之,经实测试此通用按键模块功能很强大,架构很巧妙,其中很多地方值得反复推敲学习,不过,实际应用还得灵活处理,以上仅小白个人所得,浅陋之处还望高手斧正!

本帖子中包含更多资源

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

x

出0入296汤圆

发表于 2014-5-1 02:10:22 | 显示全部楼层
本帖最后由 Gorgon_Meducer 于 2014-5-1 02:11 编辑
yutianku 发表于 2014-4-30 23:15
感谢大师的指点!
按照您的指点修改相关宏之后再编译,keil不再报以上错误;又折腾了一下午移植到51单片 ...


宏没有变量的概念,也不会实际占用空间,他们在编译阶段就已经不存在了。
代码尺寸较大与宏无关。放在超级循环里面才可以用,而放中断不可用的情况
请检查是否做了中断的临界区保护。这个叙述请看前面的帖子。至于你说的
容易卡死的情况应该不简单是代码逻辑的问题,代码逻辑本身是没有问题的。
需要认真考虑编译环境对结果的影响,我也有点怀疑你的存储器资源太小,而
库默认的队列相对51又太大了。不知道你能不能找到百分百卡死的情况?然后
在这个基础上再分析下?

关于逗号的问题,不是bug,而是C标准不同导致的。C99没有这个限制。

出0入0汤圆

发表于 2014-5-2 12:27:37 | 显示全部楼层
我想到了一个问题,组合按键怎么办呢?

出0入0汤圆

发表于 2014-5-2 19:48:54 | 显示全部楼层
yutianku 发表于 2014-4-30 23:15
感谢大师的指点!
按照您的指点修改相关宏之后再编译,keil不再报以上错误;又折腾了一下午移植到51单片 ...

搞了一下午,不知哪里出问题了
能把你改的传上来看下吗?

本帖子中包含更多资源

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

x

出0入0汤圆

发表于 2014-5-2 21:46:08 | 显示全部楼层
test 2F.rar 找不到..\..\device.h
Fatal Error[Pe1696]: cannot open source file "..\..\device.h" H:\test 2F\test 2F\systick\systick.c 3

出0入0汤圆

发表于 2014-5-3 17:04:16 | 显示全部楼层
终于好了,要把IAR的弄掉

本帖子中包含更多资源

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

x

出0入0汤圆

发表于 2014-5-3 18:27:01 | 显示全部楼层
当KEY2长按时,KEY1可以打断KEY2
当KEY1长按时,KEY2不可以打断KEY1

出0入0汤圆

发表于 2014-5-3 18:28:53 来自手机 | 显示全部楼层
mark一下子,这个给好好学学

出0入0汤圆

发表于 2014-5-4 13:17:09 | 显示全部楼层
Gorgon_Meducer 发表于 2014-5-1 02:10
宏没有变量的概念,也不会实际占用空间,他们在编译阶段就已经不存在了。
代码尺寸较大与宏无关。放在超 ...

受教了,多谢指点!

出0入0汤圆

发表于 2014-5-6 10:48:42 | 显示全部楼层
没有矩阵的吗?单按键口IO耗费比较大呀

出0入0汤圆

发表于 2014-5-6 11:30:32 | 显示全部楼层
例子是单键的,不代表不支持矩阵按键

出0入296汤圆

发表于 2014-5-7 13:19:46 | 显示全部楼层
enovo2468 发表于 2014-5-3 18:27
当KEY2长按时,KEY1可以打断KEY2
当KEY1长按时,KEY2不可以打断KEY1

这是KeyScan函数返回值的优先级导致的。组合按键只要KeyScan函数给其一个
编码就可以了,不难。

出0入0汤圆

发表于 2014-5-7 19:14:11 | 显示全部楼层
标记一下,有空回来看

出0入0汤圆

发表于 2014-5-16 17:42:39 | 显示全部楼层
标记一下

出0入10汤圆

发表于 2014-5-16 21:02:31 | 显示全部楼层
先收藏着先

出0入10汤圆

发表于 2014-5-17 11:03:14 | 显示全部楼层
好像很牛逼的样子,看不懂,也不懂怎么移植,能不能搞大众点?可能研究起来要花费点功夫

出0入296汤圆

发表于 2014-5-17 12:07:27 | 显示全部楼层
本帖最后由 Gorgon_Meducer 于 2014-5-17 12:12 编辑
10xjzheng 发表于 2014-5-17 11:03
好像很牛逼的样子,看不懂,也不懂怎么移植,能不能搞大众点?可能研究起来要花费点功夫 ...


模块做出来不是给人看的,是给人用的。如果不好用,欢迎提意见。
本来就不是拿来看的,为什么要“大众一点”?因为大众都用肩扛,我有
车轮却故意不用来博取什么东西么?应该首先推广车轮,然后和少数
有能力发明轮子的人讨论才对吧?人人都发明轮子?实际不可能是这样,
实际也做不到。

移植看一楼,有手把手教程,具体哪一步不懂,提出来,给你解释。只飘了一眼
就这么评论了,你说的话我们也爱莫能助——根本没提出具体问题,怎么给你解释?

我这次说话很冲,针对的是这件事的态度,我觉得不是好苗头。不针对你个人。

出0入10汤圆

发表于 2014-5-17 12:44:31 | 显示全部楼层
Gorgon_Meducer 发表于 2014-5-17 12:07
模块做出来不是给人看的,是给人用的。如果不好用,欢迎提意见。
本来就不是拿来看的,为什么要“大众一 ...

楼主激动了,因为目前项目比较紧,所以移植的话还是要好好看。我懂你说的大众那些,问题是现在你是要写给大众用啊,我说的是移植,可能你用得多,所以就简单。以后有空再看看。

出0入296汤圆

发表于 2014-5-17 12:56:16 | 显示全部楼层
10xjzheng 发表于 2014-5-17 12:44
楼主激动了,因为目前项目比较紧,所以移植的话还是要好好看。我懂你说的大众那些,问题是现在你是要写给 ...

期待你的回复。是否好移植,你们说了算。

出0入0汤圆

发表于 2014-5-27 23:03:02 | 显示全部楼层
本帖最后由 DevLabs 于 2014-5-27 23:20 编辑
Gorgon_Meducer 发表于 2014-5-17 12:56
期待你的回复。是否好移植,你们说了算。


发现一点问题, 但不知道是不是有意为之.



当在一个键按下的状态, 再按另一个键:
此时, s_chLastKeyValue != KEY_NULL, 所以会产生一个KEY_UP事件,
同时因为 s_chNowKeyValue != KEY_NULL 亦成立, 所以还会产生一个KEY_DOWN事件.
而实际上此时没有键放开, 按道理KEY_UP事件不应该存在.

我移植了这个模块试了一下, 确实如此:


上图是先按住KEY2不放, 再按下KEY1, 再松开KEY1, 最后松开KEY2这个过程产生的所有事件, 虽然与实际不符, 但是却能在按下一个键的情况下正常识别另一个按键.

本帖子中包含更多资源

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

x

出0入0汤圆

 楼主| 发表于 2014-5-28 10:21:27 | 显示全部楼层
DevLabs 发表于 2014-5-27 23:03
发现一点问题, 但不知道是不是有意为之.

的确是有意为之~





出0入296汤圆

发表于 2014-5-28 10:30:25 | 显示全部楼层
DevLabs 发表于 2014-5-27 23:03
发现一点问题, 但不知道是不是有意为之.

有意为之,这主要是增加模块的强壮性。其实这里存在一个按键优先级的问题,而这个优先级是用户的
扫描函数决定的,如果用户扫描函数在某个键按下的时候,其它按键即便被按下也不会返回值,则说明
被按下的键优先级最高。比如,你先按下KEY1保持不动再按KEY2就不会出现你描述的情况。

总结:按键优先级客观存在且不受key模块控制,由用户扫描程序确定,因此,我们只能增加对这类情况
的支持,以提高服务的鲁棒性。

出0入0汤圆

发表于 2014-5-29 10:44:08 | 显示全部楼层
楼主第一个状态图明显和程序不对应


对应的状态图:

本帖子中包含更多资源

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

x

出0入0汤圆

发表于 2014-5-29 13:07:06 | 显示全部楼层
mark..........

出0入0汤圆

发表于 2014-6-10 16:09:18 | 显示全部楼层
果断收了,学习下。

出0入0汤圆

发表于 2014-6-10 17:45:50 | 显示全部楼层
按键设计 MARK 学习一下

出0入0汤圆

发表于 2014-6-17 14:27:42 | 显示全部楼层
标记一下,备用.

出0入0汤圆

发表于 2014-6-17 14:42:29 | 显示全部楼层
好东西不是说出来的,时做出来的!!

出0入0汤圆

发表于 2014-6-17 17:20:07 | 显示全部楼层
mark,标记。。。

出0入0汤圆

发表于 2014-6-17 20:40:03 | 显示全部楼层
按键代码写的比我写的好很多啊 我写的只能说 能用

出0入0汤圆

发表于 2014-7-16 10:33:02 | 显示全部楼层
KEY Detector 状态图中长按计时的两个迁移条件false分别指的什么,不看代码很难看懂

出0入296汤圆

发表于 2014-7-16 12:25:09 | 显示全部楼层
lizhaoxx 发表于 2014-7-16 10:33
KEY Detector 状态图中长按计时的两个迁移条件false分别指的什么,不看代码很难看懂 ...

状态的名字叫做“获取按键事件”,则true表示成功的获得了按键事件,false表示没有获得按键事件

出0入0汤圆

发表于 2014-7-16 12:31:31 | 显示全部楼层
学习      

出0入0汤圆

发表于 2014-7-16 13:14:33 | 显示全部楼层
马克一下,非常实用啊

出0入0汤圆

发表于 2014-7-16 15:25:31 | 显示全部楼层
static bool key_frontend(void)
{
        static uint8_t s_chState = KEY_FRONTEND_START;
        static uint8_t s_chNowKeyValue = KEY_NULL;
        static uint8_t s_chLastKeyValue = KEY_NULL;
        key_event_t tKey = {KEY_NULL, KEY_UP};

return fsm_rt_on_going;


函数返回bool,你的return  fsm_rt_on_going

出0入296汤圆

发表于 2014-7-17 10:18:15 | 显示全部楼层
lizhaoxx 发表于 2014-7-16 15:25
static bool key_frontend(void)
{
        static uint8_t s_chState = KEY_FRONTEND_START;

bug,不多说,就是bug
正确的原型应该是

  1. static fsm_rt_t key_frontend(void);
复制代码

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

本版积分规则

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

GMT+8, 2024-6-18 10:23

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

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