9278|46

389

帖子

0

TA的资源

纯净的硅(高级)

楼主
 

51单片机按键之思考 [复制链接]

按键在编码显示时大都加了延时,去抖动,还有松手检测;
但是关于松手检测我好像有点纠结的地方
既然按键没有松那么程序势必就停在松手检测处;
或者说一直在while循环当中,那么换句话说就是当我一直按着
被检测的按键时其他的显示或者数据传输都应该停止了才对啊!
可事实却不尽相同:
1.首先看实际开发板的调试:
在矩阵键盘扫描电路中:
测试方法1:一直按着其中的某个键;
测试结果1:数码管上仅显示一个数值,就是该键所代表的数字个位;
测试方法2:在按着A键的同时按下B键,先松开A然后松开B;
测试结果2:显示B;
测试方法3:在按着A键的同时按下B键,先松开B然后松开A
测试结果3:显示A;
2.Proteus软件52单片机的直流电机调速:
每当按下按键DB8输出的都是高电平,按着不动也是一样;
请问这要作何解释呢?

Image00017.jpg (52.01 KB, 下载次数: 0)

电路原理图

电路原理图

Image00018.jpg (32.94 KB, 下载次数: 0)

PWM波形1

PWM波形1

Image00019.jpg (33.02 KB, 下载次数: 1)

PWM波形2

PWM波形2

Image00020.jpg (34.22 KB, 下载次数: 0)

PWM波形3

PWM波形3

Image00021.jpg (32.89 KB, 下载次数: 0)

PWM波形4

PWM波形4
此帖出自51单片机论坛

最新回复

不客气,慢慢玩吧~ 写完后,把代码贴出来,大家一起瞧瞧,我就偷偷懒,不用整理程序……  详情 回复 发表于 2013-4-5 15:45

点评

DB8在哪里?  详情 回复 发表于 2013-4-1 19:52
按键时你不该占尽所有的cpu. 应该把按键功能独立的设计成一个模块,调用函数完成全部功能.否则程序很容易混乱. 具体的按下抬起哪个键是状态的问题,能区分复合的按键功能可以更强大而且也并不难,然后怎么处理就不  详情 回复 发表于 2013-3-30 20:08
点赞 关注
 

回复
举报

4008

帖子

0

TA的资源

版主

沙发
 
原帖由 yaoyong 于 2013-3-29 12:56 发表
按键在编码显示时大都加了延时,去抖动,还有松手检测;
但是关于松手检测我好像有点纠结的地方
既然按键没有松那么程序势必就停在松手检测处;
或者说一直在while循环当中,那么换句话说就是当我一直按着
被检测 ...

按键时你不该占尽所有的cpu.
应该把按键功能独立的设计成一个模块,调用函数完成全部功能.否则程序很容易混乱.
具体的按下抬起哪个键是状态的问题,能区分复合的按键功能可以更强大而且也并不难,然后怎么处理就不再是按键的问题了.
此帖出自51单片机论坛

点评

你所说的不会占尽CPU,那么程序在执行时难道还有一部分 CPU在执行主程序其余的部分,只分出一部分执行子程序 里面的东西?这不是跟程序里面的分支结构,还有控制语句 冲突了吗?  详情 回复 发表于 2013-3-31 00:06
 
 
 

回复

11

帖子

0

TA的资源

一粒金砂(中级)

板凳
 

不该占尽所有的cpu

按键时你不该占尽所有的cpu
此帖出自51单片机论坛
 
 
 

回复

389

帖子

0

TA的资源

纯净的硅(高级)

4
 

回复 沙发 huo_hu 的帖子

你所说的不会占尽CPU,那么程序在执行时难道还有一部分
CPU在执行主程序其余的部分,只分出一部分执行子程序
里面的东西?这不是跟程序里面的分支结构,还有控制语句
冲突了吗?
此帖出自51单片机论坛

点评

既然按键没有松那么程序势必就停在松手检测处; 是这句话感觉你的程序不够合理 定时察看io状态,按键抬起和按下只是状态有分别,不用特别处理.  详情 回复 发表于 2013-3-31 17:48
 
 
 

回复

954

帖子

0

TA的资源

纯净的硅(初级)

5
 
可以根据程序单个语句仿真试试
此帖出自51单片机论坛

点评

你好,能具体说说吗?  详情 回复 发表于 2013-4-1 09:59
 
 
 

回复

389

帖子

0

TA的资源

纯净的硅(高级)

6
 
  1. #include

  2. typedef unsigned char uchar;
  3. typedef unsigned int uint;

  4. sbit dula=P2^6;
  5. sbit wela=P2^7;

  6. uchar Num;

  7. uchar code table[]={
  8. 0x3f,0x06,0x5b,0x4f,
  9. 0x66,0x6d,0x7d,0x07,
  10. 0x7f,0x6f,0x77,0x7c,
  11. 0x39,0x5e,0x79,0x71};


  12. void delay(uint z)
  13. {
  14.         uint x,y;
  15.         for(x=z;x>0;x--)
  16.                 for(y=110;y>0;y--);
  17. }

  18. void
  19. DigitalDisplay(uchar );
  20. void
  21. KeyBoardScan();

  22. void
  23. main()
  24. {
  25.         while(1)
  26.         {
  27.                 DigitalDisplay(Num);
  28.                 KeyBoardScan();
  29.         }
  30. }
  31. void
  32. keyBoardScan()
  33. {
  34.         uchar temp;
  35.         P3=0xfe;
  36.         temp=P3;
  37.         temp=temp&0xf0;
  38.         while(temp!=0xf0)
  39.         {
  40.                 delay(5);
  41.                 temp=P3;
  42.                 temp=temp&0xf0;
  43.                 while(temp!=0xf0)
  44.                 {
  45.                         temp=P3;                           //千万记得在此读回来判断的是P3端口的值而不是temp&0xf0的值
  46.                         switch (temp)
  47.                         {
  48.                         case 0xee:
  49.                                 Num=1;
  50.                                 break;

  51.                         case 0xde:
  52.                                 Num=2;
  53.                                 break;

  54.                         case 0xbe:
  55.                                 Num=3;
  56.                                 break;

  57.                         case 0x7e:
  58.                                 Num=4;
  59.                                 break;
  60.                         }
  61.                         temp=temp&0xf0;
  62.                         while(temp!=0xf0)                         //松手检测,
  63.                         {
  64.                                 temp=P3;
  65.                                 temp=temp&0xf0;
  66.                         }
  67.                 }
  68.         }

  69.         P3=0xfd;
  70.         temp=P3;
  71.         temp=temp&0xf0;
  72.         while(temp!=0xf0)
  73.         {
  74.                 delay(5);
  75.                 temp=P3;
  76.                 temp=temp&0xf0;
  77.                 while(temp!=0xf0)
  78.                 {
  79.                         temp=P3;
  80.                         switch(temp)
  81.                         {
  82.                         case 0xed:
  83.                                 Num=5;
  84.                                 break;

  85.                         case 0xdd:
  86.                                 Num=6;
  87.                                 break;

  88.                         case 0xbd:
  89.                                 Num=7;
  90.                                 break;

  91.                         case 0x7d:
  92.                                 Num=8;
  93.                                 break;
  94.                         }
  95.                           temp=temp&0xf0;

  96.                         while(temp!=0xf0)
  97.                         {
  98.                                 temp=P3;
  99.                                 temp=temp&0xf0;
  100.                         }
  101.                 }
  102.         }

  103.         P3=0xfb;
  104.         temp=P3;
  105.         temp=temp&0xf0;
  106.         while(temp!=0xf0)
  107.         {
  108.                 delay(5);
  109.                 temp=P3;
  110.                 temp=temp&0xf0;
  111.                 while(temp!=0xf0)
  112.                 {
  113.                         temp=P3;
  114.                         switch(temp)
  115.                         {
  116.                         case 0xeb:
  117.                                 Num=9;
  118.                                 break;

  119.                         case 0xdb:
  120.                                 Num=10;
  121.                                 break;

  122.                         case 0xbb:
  123.                                 Num=11;
  124.                                 break;

  125.                         case 0x7b:
  126.                                 Num=12;
  127.                                 break;
  128.                         }
  129.                         temp=temp&0xf0;
  130.                         while(temp!=0xf0)
  131.                         {
  132.                                 temp=P3;
  133.                                 temp=temp&0xf0;
  134.                         }
  135.                 }
  136.         }

  137.         P3=0xf7;
  138.         temp=P3;
  139.         temp=temp&0xf0;
  140.         while(temp!=0xf0)
  141.         {
  142.                 delay(5);
  143.                 temp=P3;
  144.                 temp=temp&0xf0;
  145.                 while(temp!=0xf0)
  146.                 {
  147.                         temp=P3;
  148.                         switch(temp)
  149.                         {
  150.                         case 0xe7:
  151.                                 Num=13;
  152.                                 break;

  153.                         case 0xd7:
  154.                                 Num=14;
  155.                                 break;

  156.                         case 0xb7:
  157.                                 Num=15;
  158.                                 break;

  159.                         case 0x77:
  160.                                 Num=16;
  161.                                 break;
  162.                         }
  163.                         temp=temp&0xf0;
  164.                         while(temp!=0xf0)
  165.                         {
  166.                                 temp=P3;
  167.                                 temp=temp&0xf0;
  168.                         }
  169.                 }
  170.         }
  171. }

  172. void
  173. DigitalDisplay(uchar DisplayNum)
  174. {
  175.         uchar Shi,Ge;
  176.         Shi=DisplayNum/10;
  177.         Ge=DisplayNum%10;

  178.         P0=table[Shi];
  179.         dula=1;
  180.         dula=0;
  181.         P0=0xef;
  182.         wela=1;
  183.         wela=0;
  184.         delay(1);

  185.         P0=table[Ge];
  186.         dula=1;
  187.     dula=0;
  188.         P0=0xdf;
  189.         wela=1;
  190.         wela=0;
  191.         delay(1);     
  192. }
复制代码
以上是我的源程序,键盘扫描确实是封装在子程序里,KeyboardScan();
而数码管的显示也在函数DigitalDisplay()当中;主函数一直调用这两个函数
根据全局变量Num的变化改变显示的数据;

[ 本帖最后由 yaoyong 于 2013-4-1 09:39 编辑 ]
此帖出自51单片机论坛
 
 
 

回复

4008

帖子

0

TA的资源

版主

7
 

回复 4楼 yaoyong 的帖子

既然按键没有松那么程序势必就停在松手检测处;

是这句话感觉你的程序不够合理
定时察看io状态,按键抬起和按下只是状态有分别,不用特别处理.
此帖出自51单片机论坛

点评

没有特别处理啊!都是最基本的环节,只是在重新再看的时候有些不一样的想法  详情 回复 发表于 2013-4-1 09:58
 
 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

8
 
先不纠结楼主用的死循环方式检查按键,这当然完全不合理,理由,正是楼主怀疑的地方,那岂不是独占了 cpu
关键是楼主却没观察到独占。

我只想确定,你的这个死循环检查松手的动作 和 显示的扫描函数是不是在同一个线程里

这里解释一下线程,
单单一个主函数这叫一个线程,开了一个中断就多了一个线程。
线程的存在就是一种并行处理机制
我怀疑你的显示扫描不在主循环里,而死循环检测则在,所以看到有显示很正常
此帖出自51单片机论坛

点评

辛昕,请问一下,关于你说的线程的知识是在哪学的?  详情 回复 发表于 2013-4-1 22:21
关于线程和进程记得以前翻操作系统的时候有过一面之缘,表示不懂 不过辛哥用在这里用它解释程序的执行过程还是第一次听到,这又让我有了新的理解: 1.中断是独立于主程序而执行的,定时器在计数时,主程序依然在执  详情 回复 发表于 2013-4-1 09:56
 
 
 

回复

389

帖子

0

TA的资源

纯净的硅(高级)

9
 

回复 8楼 辛昕 的帖子

关于线程和进程记得以前翻操作系统的时候有过一面之缘,表示不懂
不过辛哥用在这里用它解释程序的执行过程还是第一次听到,这又让我有了新的理解:
1.中断是独立于主程序而执行的,定时器在计数时,主程序依然在执行,这里的所说的中断
应该有硬件支持;
2.这里的键盘是靠程序来实现的,不是编码键盘,键盘的松按也不像电脑一样会启用中断
所以不会产生新的线程。
3.死循环在子函数中,显示扫描程序也在子函数中,调用子函数应该是不会增加线程的;
这样说来程序还是会停在按键未松处。
此帖出自51单片机论坛
 
 
 

回复

389

帖子

0

TA的资源

纯净的硅(高级)

10
 

回复 7楼 huo_hu 的帖子

没有特别处理啊!都是最基本的环节,只是在重新再看的时候有些不一样的想法
此帖出自51单片机论坛
 
 
 

回复

389

帖子

0

TA的资源

纯净的硅(高级)

11
 

回复 5楼 247153481 的帖子

你好,能具体说说吗?
此帖出自51单片机论坛
 
 
 

回复

4008

帖子

0

TA的资源

版主

12
 
void Task_Run(void) {
        if (SF_AD1RES_FLAG|SF_AD2RES_FLAG) {
                StoreADData();                               
        }
        if (SF_TASKRUN_FLAG==0) return;
        SF_TASKRUN_FLAG=0;        //300hz
        TimeBase16++;
                //分时
        switch ((uint8)TimeBase16 & 0x3) {//75hz
                case 0:
                        WarmCtrl();
                break;
                case 1:
                        Key_Scan();
                        if (++Second>=75) {
                                Second=0;
                                Sound_Ctrl();
                        }                       
                break;
                case 2:
                        if (SF_DISABLE_DISPLAY_FLAG==0) Display();
                break;
                case 3:
                        AD_START;
                break;
        }//end switch

}

int main(void) {
        AD_Init();
        PCA_Init();
        Com_Init();
        TimerInit();
        LCD1602_Init(0x0c);
        EA=1;
        DispScreen();
        while (TimeBase16 <1500) Task_Run(); //上电延时5秒
        Clear_Memory();
        while (1) {
               
                Task_Run();
                switch (Key_Get()) {
                        case KEY_LEFT:
                                PWM_OpenBit^=0x0f;         //OPEN or CLOSE        PWM
                        break;
                        case KEY_RIGHT:
                                PWM_OpenBit^=0xf0;        //加热辅助开关
                        break;
                        case KEY_UP:
                                C1Temp_Setting+=1;
                        break;
                        case KEY_DOWN:
                                C1Temp_Setting-=1;
                        break;
                        case PRESS_KEY_LONGTIME_FLAG|KEY_UP:        //长按温度设置快加
                                C1Temp_Setting+=10;
                        break;
                        case PRESS_KEY_LONGTIME_FLAG|KEY_DOWN:        //长按温度设置快-
                                C1Temp_Setting-=10;
                        break;
                        case KEY_SHIFT:
                               
                        break;
                        case KEY_ENTER:                               
                                SF_SOUND_FLAG^=1;                                   //短按关闭声音
                                Sound_Bit=1;                                           //关闭
                        break;
                        case PRESS_KEY_LONGTIME_FLAG|KEY_ENTER:                               
                                SF_DISPLAY0_FLAG^=1;                                //长按显示第二屏
                                DispScreen();
                        break;

                        case KEY_SHIFT|KEY_LEFT:        //组合键置温度设置
                                LCD_Display_String(0,   "Input Tempature");
                                LCD_Display_String(0x40,"Setting:       ");
                                LCD_Display_Pretend_Float(0x49,Chg_Tempature(C1Temp_Setting),1);
                                C1Temp_Setting=UnChg_Tempature(Key_Input(0x49,5,2));//5-mask
                                DispScreen();                               
                        break;
                        case KEY_SHIFT|KEY_RIGHT:        //组合键置温度报警范围
                                LCD_Display_String(0,   "InputAlarmRange");
                                LCD_Display_String(0x40,"Setting:       ");
                                LCD_Display_DEC_uint8(0x49,Temp_Alarm_Range,1);
                                Temp_Alarm_Range=(uint8)Key_Input(0x49,2,1);//5-mask                               
                                DispScreen();                               
                        break;
                        case KEY_SHIFT|KEY_UP:                //组合键置延时
                               
                        break;
                        case KEY_SHIFT|KEY_DOWN:        //组合键置
                               
                        break;
                }//end switch       
       
        }//end while
        return 0;
}

这个是以前做的温控,按键部分包含两部分,定时的扫描置状态在taskrun里key_scan()函数完成这部分功能.另外一部分是对案件的处理在switch(key_get()){...}中,key_Get返回按键已经消抖处理过的有效按键状态,对返回值分别处理就行了.
任何时候都不应该while...来等一个很长时间才会发生的事件,1ms以上都应该算长的.
此帖出自51单片机论坛
 
 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

13
 
线程和进程的概念只是看使用的空间资源的关系。
这里,中断计数和主程序执行同时,和线程无关。
我说的线程是指主程序和中断后切入中断服务程序,重点在于,它其实还是cpu的时间,这个和主程序实际上不是并行的,两者是互相抢占,只是,由于执行速度极快,使得一些宏观动作如同并行一般。

这里被我不小心扯远了,回正题,我只想问一下,你的显示扫描函数和读键这个等待死循环分别放在哪里调用?主程序里还是中断里?
此帖出自51单片机论坛

点评

辛哥,我今天想了很久,你看我这样理解行不: 既然显示程序和扫描程序在主程序的While(1)中,那么如果是 按照我的写法,while(1) { DigitalDisplay(); KeyBoardScan(); }那么,如果程序停在扫描  详情 回复 发表于 2013-4-2 15:21
程序我在六楼已经给出 我没有采用中断的方法,而实用软件检测什么时候按下, 显示程序和扫描程序都作为子程序被主函数调用  详情 回复 发表于 2013-4-1 18:01
 
 
 

回复

389

帖子

0

TA的资源

纯净的硅(高级)

14
 

回复 13楼 辛昕 的帖子

程序我在六楼已经给出
我没有采用中断的方法,而实用软件检测什么时候按下,
显示程序和扫描程序都作为子程序被主函数调用
此帖出自51单片机论坛
 
 
 

回复

4008

帖子

0

TA的资源

版主

15
 

回复 楼主 yaoyong 的帖子

DB8在哪里?
此帖出自51单片机论坛

点评

不好意思写错了,因该是DB7  详情 回复 发表于 2013-4-3 09:59
 
 
 

回复

577

帖子

9

TA的资源

纯净的硅(中级)

16
 

回复 8楼 辛昕 的帖子

辛昕,请问一下,关于你说的线程的知识是在哪学的?
此帖出自51单片机论坛

点评

操作系统方面的书上都有  详情 回复 发表于 2013-4-1 22:37
 
 
 

回复

389

帖子

0

TA的资源

纯净的硅(高级)

17
 

回复 16楼 季夏木槿 的帖子

操作系统方面的书上都有
此帖出自51单片机论坛

点评

谢了  详情 回复 发表于 2013-4-2 13:33
 
 
 

回复

4008

帖子

0

TA的资源

版主

18
 
单片机里谈不上线程和进程,因为没有操作系统.即便有像uclinux,vxworks这样的操作系统也顶多是个分时系统,没有mmu也就没有地址映射,进程和线程切换是个颇麻烦的事情基本无可能.
此帖出自51单片机论坛

点评

呵呵,我没有接触这方面的东西,我是电气方面的,能把51搞好就不错了  详情 回复 发表于 2013-4-2 10:05
 
 
 

回复

389

帖子

0

TA的资源

纯净的硅(高级)

19
 

回复 18楼 huo_hu 的帖子

呵呵,我没有接触这方面的东西,我是电气方面的,能把51搞好就不错了
此帖出自51单片机论坛
 
 
 

回复

577

帖子

9

TA的资源

纯净的硅(中级)

20
 

回复 17楼 yaoyong 的帖子

谢了
此帖出自51单片机论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

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