找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3388|回复: 9
收起左侧

51单片机四个按键控制四个功能,求C语言程序编写思路

[复制链接]
ID:613250 发表于 2020-10-5 10:32 来自手机 | 显示全部楼层 |阅读模式
50黑币
本帖最后由 武。。。。 于 2020-10-5 16:07 编辑

按下按键一后(短按),8个led灯全部亮(死循环);按下按键二后,8个led灯进行流水(死循环);按下按键三后,8个led灯同时做呼吸(2秒亮,4秒暗)(利用pwm占空比);按下按键四后,全部关闭。
原理图如下:
51hei图片_20201005105135.png

求大神指导程序,给个思路.
ps:下面是我自己写的代码,但是在呼吸灯那里出了点问题,按了呼吸灯就无法按其他按键,无法退出循环。请各路大神指点迷津,帮忙写出更好的代码或修改一下代码。
  1. #include<reg52.h>

  2. #define uchar unsigned char
  3. #define uint unsigned int

  4. uchar code table0[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//LED从低位往高位移
  5. unsigned char ZHOUQI_COUNT;        //记录进入中断的次数,满一个周期清零
  6. unsigned char PWM_VLAUE;        //存储当前高电平对应的定时次数
  7. unsigned int UPDATA_COUNT;        //占空比更新时间

  8. bit direc_flag;                                //占空比更新方向 0增加,1减少


  9. void timer0_init();                        //定时器0初始化
  10. void delayMS(uint x);           //延时函数
  11. void KeyProcess(uchar Key);         //按键处理函数
  12. void huxi();               //呼吸灯函数
  13. uchar GetKey();             //检测按键


  14. //延时函数
  15. void delayMS(uint x)
  16. {
  17.     uchar i;

  18. while (x--)
  19. for(i=0;i<120; i++) ;
  20. }
  21. /***************************************************
  22. *                                定时器0初始化子函数
  23. *                        工作方式2,每20us中断一次
  24. ****************************************************/
  25. void timer0_init()
  26. {
  27.         TMOD = 0x02;                //采用定时器0,工作方式2,
  28.         TH0 = 0XED;                         //定时器设置,每隔20us发起一次中断。
  29.         TL0 = 0XED;         
  30.         ET0 = 1;                        //开定时器0中断
  31.         EA = 1;                                 //开总中断
  32.         TR0 = 1;                        //打开定时器
  33. }

  34. //检测按键

  35. uchar GetKey()

  36. {

  37. uchar k;
  38. if(P1==0xFF)
  39. return 0;

  40. delayMS(10);

  41. switch (P1)

  42. {

  43. case 0xEF: k=1;break;

  44. case 0xDF: k=2;break;

  45. case 0xBF: k=3;break;

  46. case 0x7F: k=4;break;

  47. default: k=0;

  48. }
  49. while (P1 != 0xFF);//等待释放按键(释放按键时退出循环)


  50. return k;
  51. }
  52. //键盘按键处理


  53. void KeyProcess(uchar Key)

  54. {
  55. int i;

  56. switch (Key)

  57. {

  58. case 1://led灯全部点亮
  59. while(1)
  60. {
  61. P0=0x00;
  62. if (P1 == 0xDF||P1 == 0xBF||P1 == 0x7F)
  63. break;//等待释放按键(释放按键时退出循环)
  64. }

  65. break;

  66. case 2://以流水灯形式点亮
  67. while(1)
  68. {
  69. for(i=0;i<8;i++)
  70. {
  71. P0=table0[i];
  72. delayMS(100);
  73. }
  74. if (P1 == 0xEF||P1 == 0xBF||P1 == 0x7F)
  75. break;//等待释放按键(释放按键时退出循环)
  76. }

  77. break;
  78. case 3: //led灯进行闪烁
  79. if(Key==3)
  80. while(1)
  81. {
  82. huxi();
  83. if (P1 == 0xEF||P1 == 0xDF||P1 == 0x7F)
  84.       break;//等待释放按键(释放按键时退出循环)
  85. }
  86.   break;
  87. case 4://全部关闭
  88. while(1)
  89. {
  90. P0=0xff;
  91. if (P1 == 0xEF||P1 == 0xDF||P1 == 0xBF)
  92. break;//等待释放按键(释放按键时退出循环)
  93. }

  94. break;
  95. }

  96. }
  97. //呼吸灯启动函数
  98. void huxi()
  99. {
  100.         UPDATA_COUNT = 0;
  101.         ZHOUQI_COUNT = 0;
  102.         PWM_VLAUE = 50;//占空比50%,
  103.         direc_flag = 0;
  104.         P0 = 0xff;                        //默认LED熄灭       
  105.         timer0_init();                //定时器0初始化
  106.         while(1);
  107. }
  108. /***************************************************
  109. *                                中断服务子函数
  110. *                         判断何时该输出高低电平
  111. ****************************************************/
  112. void time0() interrupt 1
  113. {
  114.         ZHOUQI_COUNT++;       //周期累加
  115.         UPDATA_COUNT++;       //占空比更新时间累加
  116.         if(ZHOUQI_COUNT == PWM_VLAUE)                //判断是否到了点亮LED的时候
  117.                 P0 = 0x00;                                        //点亮LED
  118.         if(ZHOUQI_COUNT == 100)                                //当前周期结束
  119.         {
  120.                 P0 = 0xff;                                        //熄灭LED
  121.                 ZHOUQI_COUNT = 0;                                //重新计时
  122.         }
  123.         if((UPDATA_COUNT == 5000) && (direc_flag == 0))
  124.         {                                                                   //占空比增加2%
  125.                 UPDATA_COUNT = 0;
  126.                 PWM_VLAUE=PWM_VLAUE+2;
  127.                 if(PWM_VLAUE == 90)                        //占空比更改方向
  128.                         direc_flag = 1;       
  129.         }
  130.         if((UPDATA_COUNT == 5000) && (direc_flag == 1))
  131.         {                                                                //占空比减少1%
  132.                 UPDATA_COUNT = 0;
  133.                 PWM_VLAUE--;
  134.                 if(PWM_VLAUE == 50)                        //占空比更改方向
  135.                         direc_flag = 0;       
  136.         }       
  137. }

  138. //主程序

  139. //--------------------------------------------------------------------

  140. void main()

  141. {

  142. uchar Key;

  143. P0=P1=0xFF;

  144. while(1)

  145. {

  146. Key=GetKey();

  147. if(Key!=0)  KeyProcess(Key);

  148. }

  149. }
复制代码



回复

使用道具 举报

ID:275826 发表于 2020-10-6 10:10 | 显示全部楼层
#include<reg52.h> #define uchar unsigned char #define uint unsigned int #define Kport  P3 #define Ledport  P1 uchar code table0[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//LED从低位往高位移 unsigned char kscancnt;        //记录进入中断的次数,满一个周期清零  void timer0_init();                        //定时器0初始化 void delayMS(uint x);           //延时函数 void KeyProcess(uchar Key);         //按键处理函数 bit flag; uchar knum; uint F3cnt,F2cnt,Pwmcnt,T0cnt; uchar temp=0xff,temp1; uchar sh_cnt; //延时函数 void delayMS(uint x) {     uchar i;     while (x--)        for(i=0;i<120; i++) ; } /*************************************************** *                                定时器0初始化子函数 *                        工作方式2,每1000us中断一次 ****************************************************/ void timer0_init(void) {         TMOD = 0x01;                //采用定时器0,工作方式2,         TH0 = (65536-1000)/256;                         //定时器设置,每隔20us发起一次中断。         TL0 = (65536-1000)%256;                   ET0 = 1;                        //开定时器0中断         EA = 1;                                 //开总中断         TR0 = 1;                        //打开定时器 }  //检测按键  uchar GetKey(uchar kscancnt)  {      uchar ktmp;     if(kscancnt==0)          {           temp=(Kport&0xf0)>>4;           ktmp=~temp &(temp1);           if(ktmp)knum=ktmp;           temp1=temp;          }    return knum;  }  //键盘按键处理  void KeyProcess(uchar Key)   {        switch (Key)          {            case 1:Ledport=0x00;                                                 break;                             case 2:if(F2cnt==200){sh_cnt=++sh_cnt%8;F2cnt=0;}                           Ledport=table0[sh_cnt];                       break;            case 4:if(T0cnt==300)                     {F3cnt=F3cnt+10;T0cnt=0;}                           if(F3cnt==130){F3cnt=0;flag=!flag;}                   Pwmcnt=++Pwmcnt%100;                            if(flag)                             {if(Pwmcnt>F3cnt)Ledport=0x00;else Ledport=0xff;}                           else                             {if(Pwmcnt>F3cnt)Ledport=0xff;else Ledport=0x00;}                   break;             case 8:Ledport=0xff; //全部关闭                           break;          }  }  /*************************************************** *               中断服务子函数 *****************************************************/ void time0(void) interrupt 1 {     TH0 = (65536-1000)/256;                         //定时器设置,每隔20us发起一次中断。     TL0 = (65536-1000)%256;           kscancnt=++ kscancnt%10;         if(knum==2)         {F2cnt++; }     if(knum==4)         {T0cnt++; } }   //--------------------------------------------------------------------  void main(void)  {           uchar Key;         P0=P1=0xFF;         timer0_init();         while(1)                    {                  Key=GetKey(kscancnt);                  KeyProcess(Key);                                  } }
回复

使用道具 举报

ID:451718 发表于 2020-10-6 14:04 | 显示全部楼层
你的呼吸灯是通过定时器实现的,开启后,定时器会常态一直工作,当键值改变后,你有判断后去改变 “ET0 = 0; 或者 EA = 0;”操作么?
回复

使用道具 举报

ID:451718 发表于 2020-10-6 14:28 | 显示全部楼层
//***********硬件底层定义**************
#define K1                    P14
#define K2                    P15
#define K3                    P16
#define K4                    P17

//***********软件层定义*************
#define KEY1_PRES                        1        //KEY1按下
#define KEY2_PRES                        2        //KEY2按下
#define KEY3_PRES                        3        //KEY3按下
#define KEY4_PRES                        4        //KEY4按下
#define KEY5_PRES                        5        //KEY3和KEY4同时按下   扩展用


//***********按键检测函数**************

unsigned char Key_Scan(unsigned char mode)
{
        static unsigned char Key_Up = 1; //按键按松开标志

        if(mode)        //支持连按
        {
                Key_Up = 1;       
        }
        if(Key_Up && (K1==0 || K2==0 || K3==0 || K4==0))
        {
               
                Key_Up = 0;
               
                if(K1 == 0)
                        return KEY1_PRES;
                else if(K2 == 0)
                        return KEY2_PRES;
                else if(K3 == 0 && K4 == 0)
                        return KEY5_PRES;
                else if(K3 == 0)
                        return KEY3_PRES;
                else if(K4 == 0)
                        return KEY4_PRES;

        }
        else if(K1 == 1 && K2 == 1 && K3 == 1 && K4 == 1)
        {
                Key_Up = 1;
        }
               
        return 0; //无按键按下
       
}

//*************按键处理函数****************

Key_Deal()
{
      
      key = Key_Scan(1);           //key外部变量,  1:支持连按, 0:不支持连按,

      switch(key)
      {
           case 1:
                 KeyFlag = 1;      //KeyFlag 外部变量
           break;
           case 2:
                 KeyFlag = 2;
           break;
           case 3:
                 KeyFlag = 3;
           break;
           case 4:
                //关定时器,熄灯;
           break;
           default:
               
           break;
      }
}

main()
{
      Key_Deal();
      switch(KeyFlag)
      {
           case 1:
                 //关定时器
                 //全亮操作
           break;
           case 2:
                 //关定时器
                 //跑马灯操作
           break;
           case 3:
                 //呼吸灯,开定时器;
           break;
      }
}
回复

使用道具 举报

ID:613250 发表于 2020-10-7 00:46 来自手机 | 显示全部楼层
tyrl800 发表于 2020-10-6 10:10
#include #define uchar unsigned char #define uint unsigned int #define Kport  P3 #define Ledport  P1 ...

你好,请问您的呼吸灯部分是亮两秒暗四秒吗?
回复

使用道具 举报

ID:275826 发表于 2020-10-7 08:54 | 显示全部楼层
武。。。。 发表于 2020-10-7 00:46
你好,请问您的呼吸灯部分是亮两秒暗四秒吗?

上面例程是各一秒左右,修改下参数很容易实现的
回复

使用道具 举报

ID:827215 发表于 2020-10-9 18:48 | 显示全部楼层
这种情况下我就不想用定时器了,当然,用定时器延时ok的。既然是51,直接读取按键对应口,根据读取到的值执行不同的程序。所以写四个现象的函数,然后根据IO口读取条件调用
回复

使用道具 举报

ID:827243 发表于 2020-10-9 19:15 | 显示全部楼层
呼吸死在 140行            while(1);
修改如下:
1. 去掉 140行
2.  110行 case 3 如下
case 3: //led灯进行闪烁
huxi();
break;
回复

使用道具 举报

ID:798631 发表于 2020-10-9 21:51 | 显示全部楼层
呼吸比较好实现  定时器中断里面做10毫秒时基,计数延时  ,灯也加上闪烁秒计数2之前亮 到6灭灯清0  就好了   
回复

使用道具 举报

ID:613250 发表于 2020-10-13 15:09 | 显示全部楼层
daemondong 发表于 2020-10-9 19:15
呼吸死在 140行            while(1);
修改如下:
1. 去掉 140行

我试着那样去仿真,发现按了呼吸灯的按键后就无法按其他按键了,会一直停留在呼吸灯那里。
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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