标题: 51单片机如何实现 按下按键执行某函数或语句,松开后停止执行这个函数或语句 [打印本页]

作者: macboa    时间: 2021-11-16 12:14
标题: 51单片机如何实现 按下按键执行某函数或语句,松开后停止执行这个函数或语句
本帖最后由 macboa 于 2021-11-16 12:25 编辑

在做一个51小车,用定时器扫描按键状态。来控制加速和减速。
想实现的功能是,按住加速按键,执行加速函数,同时LED亮,松开就不再加速,灯灭,跳出。
  1. LED1=P1^0;
  2. LED2=P1^1;
  3. void main(void)
  4. {
  5.   unsigned char Key_Value=0;
  6.   Timer0_Init();
  7.   while(1)
  8.   {
  9.     Key_Value=getKey_Value();
  10.     switch(Key_Value)
  11.     {
  12.       case 1:LED1=1;Speed_UP();break;
  13.       case 2:LED2=1;Speed_Down();break;
  14.     }
  15.   }
复制代码

我把case:改成
  1. case 1:
  2. {
  3.       while(Key_Value==1)
  4.       {
  5.           Speed_UP();
  6.           LED1=1;
复制代码

可是还是一直在执行。应该如何修改呢?
下面是中断函数:
  1. void Timer0_ISR(void) interrupt 1
  2. {
  3.     static unsigned int Timer0_Count=0;
  4.     TL0=0x18;
  5.     TH0=0xFC;                                
  6.     Timer0_Count++;
  7.     if(Timer0_Count>=20)
  8.     {
  9.         Timer0_Count=0;
  10.         Key_Scan_Loop();
  11.     }
  12. }
复制代码

这里是Key.c里的
  1. unsigned char getKey_State(void)
  2. {
  3.     unsigned char Key_Num=0;
  4.    
  5.     if(Key_OpenHeadLights==0){Key_Num=1;}
  6.     if(Key_BrakeMotor==0){Key_Num=2;}
  7.     if(Key_SpeedUpMotor==0){Key_Num=3;}
  8.     if(Key_BackMotor==0){Key_Num=4;}
  9.    
  10.     return Key_Num;
  11. }
  12. void Key_Scan_Loop(void)
  13. {
  14.     static unsigned char Key_NowState=0;    //按键现在状态
  15.     static unsigned char Key_LastState=0;        //按键上次状态
  16.    
  17.     Key_LastState=Key_NowState;
  18.     Key_NowState=getKey_State();
  19.    
  20.     if(Key_LastState==0&&Key_NowState==1)
  21.     {
  22.         Key_Number=1;
  23.     }
  24.     if(Key_LastState==0&&Key_NowState==2)
  25.     {
  26.         Key_Number=2;
  27.     }
  28.     if(Key_LastState==0&&Key_NowState==3)
  29.     {
  30.         Key_Number=3;
  31.     }
  32.     if(Key_LastState==0&&Key_NowState==4)
  33.     {
  34.         Key_Number=4;
  35.     }
  36. }
  37. unsigned char getKey_Value(void)
  38. {
  39.     unsigned char Key_Temp=0;
  40.    
  41.     Key_Temp=Key_Number;
  42.     Key_Number=0;
  43.    
  44.     return Key_Temp;
  45. }
复制代码




作者: man1234567    时间: 2021-11-16 14:46
void Key_Scan_Loop(void)
{
    static unsigned char Key_NowState=0;    //按键现在状态
    static unsigned char Key_LastState=0;        //按键上次状态
......
每进一次 Key_Scan_Loop 都将按键现在的状态和上次的状态清零 ?
作者: 18701931930    时间: 2021-11-16 15:29

sbit Key=P1^0;

void Key_scan()
{
    static u8 i=0;

    if(Key==0)
    {
        if(i==0)
       {
            if(Key==0)
            {
                 i=1;
                //执行按下函数
            }
        }
    }
  else
  {
      if(i==1)
     {
         //执行释放函数
     }
      i=0;
   }
}

作者: macboa    时间: 2021-11-16 18:10
man1234567 发表于 2021-11-16 14:46
void Key_Scan_Loop(void)
{
    static unsigned char Key_NowState=0;    //按键现在状态

不是static了么?
作者: macboa    时间: 2021-11-16 18:28
18701931930 发表于 2021-11-16 15:29
sbit Key=P1^0;

void Key_scan()

试过不行,按下按键无反应- -
作者: zxian163    时间: 2021-11-16 20:15
while(Key_value==1)这里改成
作者: zxian163    时间: 2021-11-16 20:17
while(Key_Value==1)改成 while(getKey_Value()==1)试下
作者: wulin    时间: 2021-11-16 20:41
这个示例程序适合楼主要求,要按实际电路重新定义端口。
  1. #include<reg51.h>        

  2. sbit key1=P3^2;
  3. sbit key2=P3^3;
  4. sbit OUT1=P1^0;
  5. sbit OUT2=P1^1;

  6. unsigned char state=0;//按键操作状态

  7. void key_scan()//按键扫描函数
  8. {
  9.         static bit sign1=0,sign2=0;
  10.         static unsigned int count1=0,count2=0;
  11.        
  12.         if(!key1)
  13.         {
  14.                 if(++count1>=500 && sign1==0)//count1/count2消抖依主循环周期取值,估测10~20ms即可
  15.                 {
  16.                         sign1=1;
  17.                         state=1;
  18.                 }
  19.         }
  20.         else
  21.         {
  22.                 if(sign1==1)
  23.                 {
  24.                         sign1=0;
  25.                         state=2;
  26.                 }
  27.                 count1=0;
  28.         }

  29.         if(!key2)
  30.         {
  31.                 if(++count2>=500 && sign2==0)
  32.                 {
  33.                         sign2=1;
  34.                         state=3;
  35.                 }
  36.         }
  37.         else
  38.         {
  39.                 if(sign2)
  40.                 {
  41.                         sign2=0;
  42.                         state=4;
  43.                 }
  44.                 count2=0;
  45.         }
  46. }                       

  47. void key_service()//按键服务程序
  48. {
  49.         switch(state)
  50.         {
  51.                 case 1: OUT1=0; state=0; break;//任务完成state清0
  52.                 case 2: OUT1=1; state=0; break;
  53.                 case 3: OUT2=0; state=0; break;
  54.                 case 4: OUT2=1; state=0; break;
  55.         }
  56. }
  57. void main()
  58. {
  59.         while(1)
  60.         {
  61.                 key_scan();
  62.                 key_service();
  63.         }
  64. }
复制代码

作者: macboa    时间: 2021-11-17 22:48
zxian163 发表于 2021-11-16 20:15
while(Key_value==1)这里改成

试过 不行
作者: 188610329    时间: 2021-11-17 23:25
按照: 按下按键执行某函数或语句,松开后停止执行这个函数或语句
这个要求的话,不需要中断,不需要其他任何,只需要:
sbit Key = P3.2;    //假定你的按键是这个

void main()
{
    其他代码
while(1)
{
     其他代码
if(Key)
{
       松开后停止执行这个函数或语句
}
else
{
        按下按键执行某函数或语句,
}
         其他代码
}
}

按这个格式就可以了
作者: 188610329    时间: 2021-11-17 23:27
188610329 发表于 2021-11-17 23:25
按照: 按下按键执行某函数或语句,松开后停止执行这个函数或语句
这个要求的话,不需要中断,不需要其他 ...

写错了  不是: sbit Key = P3.2
是  sbit Key = P3^2;  不过,反正是假定,应该没有影响
作者: macboa    时间: 2021-11-18 00:44
188610329 发表于 2021-11-17 23:27
写错了  不是: sbit Key = P3.2
是  sbit Key = P3^2;  不过,反正是假定,应该没有影响

谢谢哈,不过还是不行。要么就的按下去不亮,要么你就是一直亮
作者: macboa    时间: 2021-11-18 00:48
本帖最后由 macboa 于 2021-11-18 01:00 编辑
wulin 发表于 2021-11-16 20:41
这个示例程序适合楼主要求,要按实际电路重新定义端口。

老哥,你这个是相当牛皮了。。。
感谢您!

但是还有一个不解之处。。。
就是我自己写的
  1. main()
  2. {
  3.     if(Key_Value==1)
  4.     {
  5.         LED=0;
  6.     }
  7.     LED=1;
  8. }
复制代码

按道理无论按下没按下,LED=1这一步都会执行啊。为啥这样写,按下之后再抬起,LED还是=0呢?也就是LED=1这一步根本没有执行,新手非常不解。。。还请大神明示!!!

最后一个不解的地方就是,为何我把扫描函数放到定时器中断里,按键就失效了呢?

作者: wulin    时间: 2021-11-18 06:37
macboa 发表于 2021-11-18 00:48
老哥,你这个是相当牛皮了。。。
感谢您!
  1. main()
  2. {
  3.     if(Key_Value==1)
  4.     {
  5.         LED=0;
  6.     }
  7.     LED=1;//此语句结束后跑飞
  8. }


  9. void main()
  10. {
  11.         while(1)
  12.         {//永远约束在{}内
  13.                 if(Key_Value==1)
  14.                 {
  15.                         LED=0;
  16.                 }
  17.                 else LED=1;
  18.         }
  19. }
复制代码


扫描函数放到定时器中断里一样用,count1/count2消抖依中断周期取值,10~20ms即可。
作者: yzwzfyz    时间: 2021-11-18 14:47
不要管按键,你能不能写出一个加速的程序。

作者: macboa    时间: 2021-11-19 11:01
wulin 发表于 2021-11-18 06:37
扫描函数放到定时器中断里一样用,count1/count2消抖依中断周期取值,10~20ms即可。

谢谢,已经做到定时器里了。。。可以运行。。。那个LED=1,不执行的,还是不明白。。。




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1