Chinaunix首页 | 论坛 | 博客
  • 博客访问: 19469
  • 博文数量: 7
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 100
  • 用 户 组: 普通用户
  • 注册时间: 2013-05-08 15:56
文章分类

全部博文(7)

文章存档

2013年(7)

我的朋友

分类: C/C++

2013-05-10 11:55:27

在现在程序设计中,到处都可以看到“缓冲区”这个词。那么在程序中使用了缓冲区有什么效果呢?

我们用一个例子来说明缓冲区到底是怎么回事,当电脑卡的时候打字,那么打的字会延后才能打出来。这就是典型的缓冲区,在键盘中存在一个小芯片,设置了一段空间大小的(先进先出)队列,当有按键按下,那么就会触发中断,判断到按键按下,把键值写入到队列中,电脑CPU只须要从这个队列中读出数据就才,电脑不会算键盘是如何获取到键值的。

我们在设计单片机程序的时候,也可以用这个思想,当按键触发了后将数据写入到一个队列中,须要获取键值的时候就直接从队列中取出,这样写有一个好处就是将按键到获取键值的分为了独立两个部分,我们可以将这两部分称为前后台程序。这里有必要说下在单片机中前后台程序是怎么回事。

前台程序:在主程序中while(1)无限循环的部分。

后台程序:在中断中的程序。

状态机的设计思想和传统的流程图的思想是不太一样的,用状态机的一个例子和流程图的例子来说明状态机的优点吧。

假设在一个系统中两个按键代表两种分枝情况,假如用流程图方式表达出来的话,到第2次按下就是要设计出4种可能情况,第3次按下设计出8种可能情况,依次下去将是一个非常庞大的数据。而用状态机的话,只判系统现在是什么状态,当一个按键按下,转为什么状态就行。以图是一个电机转动的状态图。


    我的按键状态机程序如下:

点击(此处)折叠或打开

  1. #define NOKEY 0x00

  2. #define KEY_DOWN 0xA0
  3. #define KEY_LONG 0xB0
  4. #define KEY_UP 0xC0


  5. #define KEY0_CHOICE 0x01
  6. #define KEY1_CHOICE 0x02
  7. #define KEY2_CHOICE 0x03
  8. #define KEY3_CHOICE 0x04
  9. #define KEY4_CHOICE 0x05
  10. #define KEY5_CHOICE 0x06

  11. #define KEY0_DOWN (KEY_DOWN |KEY0_CHOICE)
  12. #define KEY1_DOWN (KEY_DOWN |KEY1_CHOICE)
  13. #define KEY2_DOWN (KEY_DOWN |KEY2_CHOICE)
  14. #define KEY3_DOWN (KEY_DOWN |KEY3_CHOICE)
  15. #define KEY4_DOWN (KEY_DOWN |KEY4_CHOICE)
  16. #define KEY5_DOWN (KEY_DOWN |KEY5_CHOICE)

  17. #define KEY0_DLONG (KEY_LONG |KEY0_CHOICE)
  18. #define KEY1_DLONG (KEY_LONG |KEY1_CHOICE)
  19. #define KEY2_DLONG (KEY_LONG |KEY2_CHOICE)
  20. #define KEY3_DLONG (KEY_LONG |KEY3_CHOICE)
  21. #define KEY4_DLONG (KEY_LONG |KEY4_CHOICE)
  22. #define KEY5_DLONG (KEY_LONG |KEY5_CHOICE)

  23. #define KEYBUFF_SIZE 2
  24. #define LONGTIME 50
  25. #define SERIESTIME 10


  26. u8 KEYDealFlag=0; //按键处理标志
  27. u8 KEYScanFlag=0;         //按键扫描标志

  28. u8 KEYDealCnt=0;     //记数 系统按键处理时间
  29. u8 KEYScanCnt=0;         //记数 系统按键扫描时间

  30. u8 KeyTimerCnt = 0;         //记数 从按下到长按键时间
  31. u8 KeyTimerCntL = 0;     //记数 长按键连发时间

  32. u8 KEY_State = 0;            //按键状态 无按键 、短按键 、长按键
  33. u8 KEY_Press = 0;             //本次按键    KEY0-KEY5
  34. u8 KEY_Pre =0;                //上次按键    KEY0-KEY5
  35. u8 KEY_SeriesFlag = FALSE; //连发状态

  36. u8 KeyBuff[KEYBUFF_SIZE]; //按键缓冲区
  37. u8 Key_IndexW=0;     //缓冲区尾
  38. u8 Key_IndexR=0;         //缓冲区首
  39. u8 Key_Count =0;         //缓冲区个数


  40. /********************************************************************
  41. * 名称 : KEY_InBuff()
  42. * 功能 : 将按键状态写入缓冲区
  43. * 输入 : key
  44. * 输出 :

  45. ***********************************************************************/
  46. void KEY_InBuff(u8 key)
  47. {
  48.     if(Key_Count >= KEYBUFF_SIZE) return;
  49.     
  50. //    CPSID i;             //关中断,保护数据
  51.     Key_Count++;
  52.     KeyBuff[Key_IndexW] = key;
  53.     if(++Key_IndexW >KEYBUFF_SIZE)
  54.     {
  55.         Key_IndexW = 0;
  56.     }
  57. //    CPSIE i;
  58. }    
  59. /********************************************************************
  60. * 名称 : KEY_GetKeyValue()
  61. * 功能 : 从缓冲区读出将按键状态    .此函数在中断里使用
  62. * 输入 :
  63. * 输出 : key
  64. ***********************************************************************/
  65. u8 KEY_GetKeyBuffValue()
  66. {
  67.     u8 key_return;
  68.     if(Key_Count ==0) return 0 ;
  69.     
  70.     Key_Count--;
  71.     key_return = KeyBuff[Key_IndexR];
  72.     if(++Key_IndexR > KEYBUFF_SIZE)
  73.     {
  74.         Key_IndexR = 0;
  75.     }
  76.     return key_return;
  77. }

  78. /********************************************************************
  79. * 名称 : KEY_GetKey()
  80. * 功能 : 获取按下的按键
  81. * 输入 :
  82. * 输出 : key
  83. ***********************************************************************/
  84. u8 KEY_GetKey(void)
  85. {
  86.     if(KEY0 == 0)
  87.         return KEY0_CHOICE;
  88.     if(KEY1 == 0)
  89.         return KEY1_CHOICE;
  90.      if(KEY2 == 0)
  91.         return KEY2_CHOICE;
  92.     if(KEY3 == 0)
  93.         return KEY3_CHOICE;
  94.     if(KEY4 == 0)
  95.         return KEY4_CHOICE;
  96.     if(KEY5 == 0)
  97.         return KEY5_CHOICE;

  98.     return NOKEY;
  99. }


  100. /********************************************************************
  101. * 名称 : KEY_Deal()
  102. * 功能 : 按键处理
  103. * 输入 :
  104. * 输出 :
  105. ***********************************************************************/
  106. void KEY_Deal(void)    
  107. {    

  108.     //----按键处理使能后将状态设置为失能
  109.     if(KEYDealFlag != ABLE) return ;
  110.     else KEYDealFlag = DISABLE ;

  111.     //获取已按下的键
  112.     KEY_Press=KEY_GetKey();
  113.     
  114.     switch(KEY_State)
  115.     {
  116.         case NOKEY :
  117.         {    
  118.             if(KEY_Press != NOKEY )    
  119.             {
  120.                 KEY_State = KEY_DOWN;     //无按键->短按键
  121.                 KEY_Pre = KEY_Press;
  122.             }
  123.             break;
  124.         }
  125.         case KEY_DOWN :
  126.         {
  127.             if(KEY_Press !=KEY_Pre)    KEY_State = NOKEY; //和上次按键不致,是抖动
  128.             else
  129.                 KEY_State = KEY_LONG;        //短按键->长按键
  130.                     
  131.             break;
  132.         }
  133.         case KEY_LONG :
  134.         {
  135.             if(KEY_Press == NOKEY )     //按键弹起 即释放按键     
  136.             {    
  137.                  KeyTimerCnt=0;
  138.                  KEY_State= NOKEY;            //     短按键->无按键
  139.                  if(KEY_SeriesFlag==FALSE)
  140.                  {
  141.                      KEY_InBuff( KEY_DOWN|KEY_Pre );
  142.                  }
  143.                   KEY_SeriesFlag=FALSE;
  144.             }            
  145.             if(KEY_Press ==KEY_Pre )
  146.             {        
  147.                 KeyTimerCnt ++;    
  148.                 if(KEY_SeriesFlag==TRUE && KeyTimerCnt>LONGTIME)     // 确定是长按键
  149.                 {
  150.                     KeyTimerCnt=0;
  151.                     KEY_Pre = KEY_Press;
  152.                      KEY_InBuff( KEY_LONG|KEY_Pre );
  153.                 }
  154.                 if(KeyTimerCnt>SERIESTIME)         //进入长按键 连发状态
  155.                 {
  156.                     KEY_SeriesFlag=TRUE;
  157.                     KeyTimerCntL=0;        
  158.                 }
  159.             }
  160.             break;
  161.         }
  162.     }
  163. }


阅读(1298) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~