第二十二节:独立按键控制跑马灯的方向。(上)

开场白:
上一节讲了多任务并行处理两路跑马灯的程序。这一节要教会大家一个知识点:如何通过一个中间变量把按键跟跑马灯的任务有效的关联起来。
具体内容,请看源代码讲解。

(1)硬件平台:基于朱兆祺51单片机学习板。用矩阵键盘中的S1键作为改变方向的独立按键,记得把输出线P0.4一直输出低电平,模拟独立按键的触发地GND。

(2)实现功能:
第1个至第8个LED灯一直不亮。在第9个至第16个LED灯,依次逐个亮灯并且每次只能亮一个灯。按一次独立按键S1,将会更改跑马灯的运动方向。

(3)源代码讲解如下: 

  1. #include "REG52.H"  
  2.   
  3. #define const_time_level_09_16  300  //第9个至第16个LED跑马灯的速度延时时间  
  4.   
  5. #define const_voice_short  40   //蜂鸣器短叫的持续时间  
  6.   
  7. #define const_key_time1  20    //按键去抖动延时的时间  
  8.   
  9.   
  10. void initial_myself();      
  11. void initial_peripheral();  
  12. void delay_short(unsigned int uiDelayShort);   
  13. void delay_long(unsigned int uiDelaylong);  
  14.   
  15. void led_flicker_09_16(); //第9个至第16个LED的跑马灯程序,逐个亮并且每次只能亮一个.  
  16. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);  
  17. void led_update();  //LED更新函数  
  18. void T0_time();  //定时中断函数  
  19.   
  20. void key_service(); //按键服务的应用程序  
  21. void key_scan(); //按键扫描函数 放在定时中断里  
  22.   
  23. sbit hc595_sh_dr=P2^3;      
  24. sbit hc595_st_dr=P2^4;    
  25. sbit hc595_ds_dr=P2^5;    
  26.   
  27. sbit beep_dr=P2^7; //蜂鸣器的驱动IO口  
  28. sbit key_sr1=P0^0; //对应朱兆祺学习板的S1键  
  29. sbit key_gnd_dr=P0^4; //模拟独立按键的地GND,因此必须一直输出低电平  
  30.   
  31. unsigned char ucKeySec=0;   //被触发的按键编号  
  32.   
  33. unsigned int  uiKeyTimeCnt1=0; //按键去抖动延时计数器  
  34. unsigned char ucKeyLock1=0; //按键触发后自锁的变量标志  
  35.   
  36. unsigned int  uiVoiceCnt=0;  //蜂鸣器鸣叫的持续时间计数器  
  37.   
  38. unsigned char ucLed_dr1=0;   //代表16个灯的亮灭状态,0代表灭,1代表亮  
  39. unsigned char ucLed_dr2=0;  
  40. unsigned char ucLed_dr3=0;  
  41. unsigned char ucLed_dr4=0;  
  42. unsigned char ucLed_dr5=0;  
  43. unsigned char ucLed_dr6=0;  
  44. unsigned char ucLed_dr7=0;  
  45. unsigned char ucLed_dr8=0;  
  46. unsigned char ucLed_dr9=0;  
  47. unsigned char ucLed_dr10=0;  
  48. unsigned char ucLed_dr11=0;  
  49. unsigned char ucLed_dr12=0;  
  50. unsigned char ucLed_dr13=0;  
  51. unsigned char ucLed_dr14=0;  
  52. unsigned char ucLed_dr15=0;  
  53. unsigned char ucLed_dr16=0;  
  54.   
  55. unsigned char ucLed_update=0;  //刷新变量。每次更改LED灯的状态都要更新一次。  
  56.   
  57.   
  58. unsigned char ucLedStep_09_16=0; //第9个至第16个LED跑马灯的步骤变量  
  59. unsigned int  uiTimeCnt_09_16=0; //第9个至第16个LED跑马灯的统计定时中断次数的延时计数器  
  60.   
  61. unsigned char ucLedStatus16_09=0;   //代表底层74HC595输出状态的中间变量  
  62. unsigned char ucLedStatus08_01=0;   //代表底层74HC595输出状态的中间变量  
  63.   
  64. unsigned char ucLedDirFlag=0;   //方向变量,把按键与跑马灯关联起来的核心变量,0代表正方向,1代表反方向  
  65.   
  66. void main()   
  67.   {  
  68.    initial_myself();    
  69.    delay_long(100);     
  70.    initial_peripheral();   
  71.    while(1)     
  72.    {  
  73.       led_flicker_09_16(); //第9个至第16个LED的跑马灯程序,逐个亮并且每次只能亮一个.  
  74.           led_update();  //LED更新函数  
  75.       key_service(); //按键服务的应用程序  
  76.    }  
  77.   
  78. }  
  79.   
  80.   
  81. void key_scan()//按键扫描函数 放在定时中断里  
  82. {    
  83.   
  84.   if(key_sr1==1)//IO是高电平,说明按键没有被按下,这时要及时清零一些标志位  
  85.   {  
  86.      ucKeyLock1=0; //按键自锁标志清零  
  87.      uiKeyTimeCnt1=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。        
  88.   }  
  89.   else if(ucKeyLock1==0)//有按键按下,且是第一次被按下  
  90.   {  
  91.      uiKeyTimeCnt1++; //累加定时中断次数  
  92.      if(uiKeyTimeCnt1>const_key_time1)  
  93.      {  
  94.         uiKeyTimeCnt1=0;   
  95.         ucKeyLock1=1;  //自锁按键置位,避免一直触发  
  96.         ucKeySec=1;    //触发1号键  
  97.      }  
  98.   }  
  99.   
  100.   
  101.   
  102. }  
  103.   
  104.   
  105. void key_service() //按键服务的应用程序  
  106. {  
  107.   switch(ucKeySec) //按键服务状态切换  
  108.   {  
  109.     case 1:// 改变跑马灯方向的按键 对应朱兆祺学习板的S1键   
  110.   
  111.           if(ucLedDirFlag==0) //通过中间变量改变跑马灯的方向  
  112.                   {  
  113.                      ucLedDirFlag=1;  
  114.                   }  
  115.                   else  
  116.                   {  
  117.                            ucLedDirFlag=0;  
  118.                   }  
  119.   
  120.           uiVoiceCnt=const_voice_short; //按键声音触发,滴一声就停。  
  121.           ucKeySec=0;  //响应按键服务处理程序后,按键编号清零,避免一致触发  
  122.           break;          
  123.                    
  124.   }                  
  125. }  
  126.   
  127.   
  128.   
  129.   
  130. void led_update()  //LED更新函数  
  131. {  
  132.   
  133.    if(ucLed_update==1)  
  134.    {  
  135.        ucLed_update=0;   //及时清零,让它产生只更新一次的效果,避免一直更新。  
  136.   
  137.        if(ucLed_dr1==1)  
  138.            {  
  139.               ucLedStatus08_01=ucLedStatus08_01|0x01;  
  140.            }  
  141.            else  
  142.            {  
  143.               ucLedStatus08_01=ucLedStatus08_01&0xfe;  
  144.            }  
  145.   
  146.        if(ucLed_dr2==1)  
  147.            {  
  148.               ucLedStatus08_01=ucLedStatus08_01|0x02;  
  149.            }  
  150.            else  
  151.            {  
  152.               ucLedStatus08_01=ucLedStatus08_01&0xfd;  
  153.            }  
  154.   
  155.        if(ucLed_dr3==1)  
  156.            {  
  157.               ucLedStatus08_01=ucLedStatus08_01|0x04;  
  158.            }  
  159.            else  
  160.            {  
  161.               ucLedStatus08_01=ucLedStatus08_01&0xfb;  
  162.            }  
  163.   
  164.        if(ucLed_dr4==1)  
  165.            {  
  166.               ucLedStatus08_01=ucLedStatus08_01|0x08;  
  167.            }  
  168.            else  
  169.            {  
  170.               ucLedStatus08_01=ucLedStatus08_01&0xf7;  
  171.            }  
  172.   
  173.   
  174.        if(ucLed_dr5==1)  
  175.            {  
  176.               ucLedStatus08_01=ucLedStatus08_01|0x10;  
  177.            }  
  178.            else  
  179.            {  
  180.               ucLedStatus08_01=ucLedStatus08_01&0xef;  
  181.            }  
  182.   
  183.   
  184.        if(ucLed_dr6==1)  
  185.            {  
  186.               ucLedStatus08_01=ucLedStatus08_01|0x20;  
  187.            }  
  188.            else  
  189.            {  
  190.               ucLedStatus08_01=ucLedStatus08_01&0xdf;  
  191.            }  
  192.   
  193.   
  194.        if(ucLed_dr7==1)  
  195.            {  
  196.               ucLedStatus08_01=ucLedStatus08_01|0x40;  
  197.            }  
  198.            else  
  199.            {  
  200.               ucLedStatus08_01=ucLedStatus08_01&0xbf;  
  201.            }  
  202.   
  203.   
  204.        if(ucLed_dr8==1)  
  205.            {  
  206.               ucLedStatus08_01=ucLedStatus08_01|0x80;  
  207.            }  
  208.            else  
  209.            {  
  210.               ucLedStatus08_01=ucLedStatus08_01&0x7f;  
  211.            }  
  212.   
  213.        if(ucLed_dr9==1)  
  214.            {  
  215.               ucLedStatus16_09=ucLedStatus16_09|0x01;  
  216.            }  
  217.            else  
  218.            {  
  219.               ucLedStatus16_09=ucLedStatus16_09&0xfe;  
  220.            }  
  221.   
  222.        if(ucLed_dr10==1)  
  223.            {  
  224.               ucLedStatus16_09=ucLedStatus16_09|0x02;  
  225.            }  
  226.            else  
  227.            {  
  228.               ucLedStatus16_09=ucLedStatus16_09&0xfd;  
  229.            }  
  230.   
  231.        if(ucLed_dr11==1)  
  232.            {  
  233.               ucLedStatus16_09=ucLedStatus16_09|0x04;  
  234.            }  
  235.            else  
  236.            {  
  237.               ucLedStatus16_09=ucLedStatus16_09&0xfb;  
  238.            }  
  239.   
  240.        if(ucLed_dr12==1)  
  241.            {  
  242.               ucLedStatus16_09=ucLedStatus16_09|0x08;  
  243.            }  
  244.            else  
  245.            {  
  246.               ucLedStatus16_09=ucLedStatus16_09&0xf7;  
  247.            }  
  248.   
  249.   
  250.        if(ucLed_dr13==1)  
  251.            {  
  252.               ucLedStatus16_09=ucLedStatus16_09|0x10;  
  253.            }  
  254.            else  
  255.            {  
  256.               ucLedStatus16_09=ucLedStatus16_09&0xef;  
  257.            }  
  258.   
  259.   
  260.        if(ucLed_dr14==1)  
  261.            {  
  262.               ucLedStatus16_09=ucLedStatus16_09|0x20;  
  263.            }  
  264.            else  
  265.            {  
  266.               ucLedStatus16_09=ucLedStatus16_09&0xdf;  
  267.            }  
  268.   
  269.   
  270.        if(ucLed_dr15==1)  
  271.            {  
  272.               ucLedStatus16_09=ucLedStatus16_09|0x40;  
  273.            }  
  274.            else  
  275.            {  
  276.               ucLedStatus16_09=ucLedStatus16_09&0xbf;  
  277.            }  
  278.   
  279.   
  280.        if(ucLed_dr16==1)  
  281.            {  
  282.               ucLedStatus16_09=ucLedStatus16_09|0x80;  
  283.            }  
  284.            else  
  285.            {  
  286.               ucLedStatus16_09=ucLedStatus16_09&0x7f;  
  287.            }  
  288.   
  289.        hc595_drive(ucLedStatus16_09,ucLedStatus08_01);  //74HC595底层驱动函数  
  290.   
  291.    }  
  292. }  
  293.   

(下半部分http://www.eeskill.com/group/topic_scan/id/507

永不止步步 发表于11-20 15:27 浏览65535次
分享到:

已有0条评论

暂时还没有回复哟,快来抢沙发吧

添加一条新评论

只有登录用户才能评论,请先登录注册哦!

话题作者

永不止步步
金币:67410个|学分:308217个
立即注册
畅学电子网,带你进入电子开发学习世界
专业电子工程技术学习交流社区,加入畅学一起充电加油吧!

x

畅学电子网订阅号