第十八节:把74HC595驱动程序翻译成类似单片机IO口直接驱动的方式。

把74HC595驱动程序翻译成类似单片机IO口直接驱动的方式。

开场白:
上一节讲了74HC595的驱动程序。为了更加方便操作74HC595输出的每个IO状态,这节讲如何把74HC595驱动程序翻译成类似单片机IO口直接驱动的方式。要教会大家两个知识点:
第一点:如何灵活运用与和非的运算符来实现位的操作。
第二点:如何灵活运用一个更新变量来实现静态刷新输出或者静态刷新显示的功能。
具体内容,请看源代码讲解。

(1)硬件平台:基于朱兆祺51单片机学习板。

(2)实现功能:两片联级的74HC595驱动的16个LED灯交叉闪烁。比如,先是第1,3,5,7,9,11,13,15八个灯亮,其它的灯都灭。然后再反过来,原来亮的就灭,原来灭的就亮。交替闪烁。

(3)源代码讲解如下:

 
  1. #include "REG52.H"  
  2.   
  3. #define const_time_level 200    
  4.   
  5. void initial_myself();      
  6. void initial_peripheral();  
  7. void delay_short(unsigned int uiDelayShort);   
  8. void delay_long(unsigned int uiDelaylong);  
  9. void led_flicker();  
  10. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);  
  11. void led_update();  //LED更新函数  
  12. void T0_time();  //定时中断函数  
  13.   
  14.   
  15. sbit hc595_sh_dr=P2^3;      
  16. sbit hc595_st_dr=P2^4;    
  17. sbit hc595_ds_dr=P2^5;    
  18.   
  19. unsigned char ucLed_dr1=0;   //代表16个灯的亮灭状态,0代表灭,1代表亮  
  20. unsigned char ucLed_dr2=0;  
  21. unsigned char ucLed_dr3=0;  
  22. unsigned char ucLed_dr4=0;  
  23. unsigned char ucLed_dr5=0;  
  24. unsigned char ucLed_dr6=0;  
  25. unsigned char ucLed_dr7=0;  
  26. unsigned char ucLed_dr8=0;  
  27. unsigned char ucLed_dr9=0;  
  28. unsigned char ucLed_dr10=0;  
  29. unsigned char ucLed_dr11=0;  
  30. unsigned char ucLed_dr12=0;  
  31. unsigned char ucLed_dr13=0;  
  32. unsigned char ucLed_dr14=0;  
  33. unsigned char ucLed_dr15=0;  
  34. unsigned char ucLed_dr16=0;  
  35.   
  36. unsigned char ucLed_update=0;  //刷新变量。每次更改LED灯的状态都要更新一次。  
  37.   
  38. unsigned char ucLedStep=0; //步骤变量  
  39. unsigned int  uiTimeCnt=0; //统计定时中断次数的延时计数器  
  40.   
  41. unsigned char ucLedStatus16_09=0;   //代表底层74HC595输出状态的中间变量  
  42. unsigned char ucLedStatus08_01=0;   //代表底层74HC595输出状态的中间变量  
  43.   
  44. void main()   
  45.   {  
  46.    initial_myself();    
  47.    delay_long(100);     
  48.    initial_peripheral();   
  49.    while(1)     
  50.    {  
  51.       led_flicker();     
  52.           led_update();  //LED更新函数  
  53.    }  
  54.   
  55. }  
  56.   
  57.   
  58. /* 注释一: 
  59. * 把74HC595驱动程序翻译成类似单片机IO口直接驱动方式的过程。 
  60. * 每次更新LED输出,记得都要把ucLed_update置1表示更新。 
  61. */  
  62. void led_update()  //LED更新函数  
  63. {  
  64.   
  65.    if(ucLed_update==1)  
  66.    {  
  67.        ucLed_update=0;   //及时清零,让它产生只更新一次的效果,避免一直更新。  
  68.   
  69.        if(ucLed_dr1==1)  
  70.            {  
  71.               ucLedStatus08_01=ucLedStatus08_01|0x01;  
  72.            }  
  73.            else  
  74.            {  
  75.               ucLedStatus08_01=ucLedStatus08_01&0xfe;  
  76.            }  
  77.   
  78.        if(ucLed_dr2==1)  
  79.            {  
  80.               ucLedStatus08_01=ucLedStatus08_01|0x02;  
  81.            }  
  82.            else  
  83.            {  
  84.               ucLedStatus08_01=ucLedStatus08_01&0xfd;  
  85.            }  
  86.   
  87.        if(ucLed_dr3==1)  
  88.            {  
  89.               ucLedStatus08_01=ucLedStatus08_01|0x04;  
  90.            }  
  91.            else  
  92.            {  
  93.               ucLedStatus08_01=ucLedStatus08_01&0xfb;  
  94.            }  
  95.   
  96.        if(ucLed_dr4==1)  
  97.            {  
  98.               ucLedStatus08_01=ucLedStatus08_01|0x08;  
  99.            }  
  100.            else  
  101.            {  
  102.               ucLedStatus08_01=ucLedStatus08_01&0xf7;  
  103.            }  
  104.   
  105.   
  106.        if(ucLed_dr5==1)  
  107.            {  
  108.               ucLedStatus08_01=ucLedStatus08_01|0x10;  
  109.            }  
  110.            else  
  111.            {  
  112.               ucLedStatus08_01=ucLedStatus08_01&0xef;  
  113.            }  
  114.   
  115.   
  116.        if(ucLed_dr6==1)  
  117.            {  
  118.               ucLedStatus08_01=ucLedStatus08_01|0x20;  
  119.            }  
  120.            else  
  121.            {  
  122.               ucLedStatus08_01=ucLedStatus08_01&0xdf;  
  123.            }  
  124.   
  125.   
  126.        if(ucLed_dr7==1)  
  127.            {  
  128.               ucLedStatus08_01=ucLedStatus08_01|0x40;  
  129.            }  
  130.            else  
  131.            {  
  132.               ucLedStatus08_01=ucLedStatus08_01&0xbf;  
  133.            }  
  134.   
  135.   
  136.        if(ucLed_dr8==1)  
  137.            {  
  138.               ucLedStatus08_01=ucLedStatus08_01|0x80;  
  139.            }  
  140.            else  
  141.            {  
  142.               ucLedStatus08_01=ucLedStatus08_01&0x7f;  
  143.            }  
  144.   
  145.        if(ucLed_dr9==1)  
  146.            {  
  147.               ucLedStatus16_09=ucLedStatus16_09|0x01;  
  148.            }  
  149.            else  
  150.            {  
  151.               ucLedStatus16_09=ucLedStatus16_09&0xfe;  
  152.            }  
  153.   
  154.        if(ucLed_dr10==1)  
  155.            {  
  156.               ucLedStatus16_09=ucLedStatus16_09|0x02;  
  157.            }  
  158.            else  
  159.            {  
  160.               ucLedStatus16_09=ucLedStatus16_09&0xfd;  
  161.            }  
  162.   
  163.        if(ucLed_dr11==1)  
  164.            {  
  165.               ucLedStatus16_09=ucLedStatus16_09|0x04;  
  166.            }  
  167.            else  
  168.            {  
  169.               ucLedStatus16_09=ucLedStatus16_09&0xfb;  
  170.            }  
  171.   
  172.        if(ucLed_dr12==1)  
  173.            {  
  174.               ucLedStatus16_09=ucLedStatus16_09|0x08;  
  175.            }  
  176.            else  
  177.            {  
  178.               ucLedStatus16_09=ucLedStatus16_09&0xf7;  
  179.            }  
  180.   
  181.   
  182.        if(ucLed_dr13==1)  
  183.            {  
  184.               ucLedStatus16_09=ucLedStatus16_09|0x10;  
  185.            }  
  186.            else  
  187.            {  
  188.               ucLedStatus16_09=ucLedStatus16_09&0xef;  
  189.            }  
  190.   
  191.   
  192.        if(ucLed_dr14==1)  
  193.            {  
  194.               ucLedStatus16_09=ucLedStatus16_09|0x20;  
  195.            }  
  196.            else  
  197.            {  
  198.               ucLedStatus16_09=ucLedStatus16_09&0xdf;  
  199.            }  
  200.   
  201.   
  202.        if(ucLed_dr15==1)  
  203.            {  
  204.               ucLedStatus16_09=ucLedStatus16_09|0x40;  
  205.            }  
  206.            else  
  207.            {  
  208.               ucLedStatus16_09=ucLedStatus16_09&0xbf;  
  209.            }  
  210.   
  211.   
  212.        if(ucLed_dr16==1)  
  213.            {  
  214.               ucLedStatus16_09=ucLedStatus16_09|0x80;  
  215.            }  
  216.            else  
  217.            {  
  218.               ucLedStatus16_09=ucLedStatus16_09&0x7f;  
  219.            }  
  220.   
  221.        hc595_drive(ucLedStatus16_09,ucLedStatus08_01);  //74HC595底层驱动函数  
  222.   
  223.    }  
  224. }  
  225.   
  226. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)  
  227. {  
  228.    unsigned char i;  
  229.    unsigned char ucTempData;  
  230.    hc595_sh_dr=0;  
  231.    hc595_st_dr=0;  
  232.   
  233.    ucTempData=ucLedStatusTemp16_09;  //先送高8位  
  234.    for(i=0;i<8;i++)  
  235.    {   
  236.          if(ucTempData>=0x80)hc595_ds_dr=1;  
  237.          else hc595_ds_dr=0;  
  238.   
  239.          hc595_sh_dr=0;     //SH引脚的上升沿把数据送入寄存器  
  240.          delay_short(15);   
  241.          hc595_sh_dr=1;  
  242.          delay_short(15);   
  243.   
  244.          ucTempData=ucTempData<<1;  
  245.    }  
  246.   
  247.    ucTempData=ucLedStatusTemp08_01;  //再先送低8位  
  248.    for(i=0;i<8;i++)  
  249.    {   
  250.          if(ucTempData>=0x80)hc595_ds_dr=1;  
  251.          else hc595_ds_dr=0;  
  252.   
  253.          hc595_sh_dr=0;     //SH引脚的上升沿把数据送入寄存器  
  254.          delay_short(15);   
  255.          hc595_sh_dr=1;  
  256.          delay_short(15);   
  257.   
  258.          ucTempData=ucTempData<<1;  
  259.    }  
  260.   
  261.    hc595_st_dr=0;  //ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来  
  262.    delay_short(15);   
  263.    hc595_st_dr=1;  
  264.    delay_short(15);   
  265.   
  266.    hc595_sh_dr=0;    //拉低,抗干扰就增强  
  267.    hc595_st_dr=0;  
  268.    hc595_ds_dr=0;  
  269.   
  270. }  
  271.   
  272.   
  273. void led_flicker() ////第三区 LED闪烁应用程序  
  274. {  
  275.   switch(ucLedStep)  
  276.   {  
  277.      case 0:  
  278.            if(uiTimeCnt>=const_time_level) //时间到  
  279.            {  
  280.                uiTimeCnt=0; //时间计数器清零  
  281.   
  282.                ucLed_dr1=1;  //每个变量都代表一个LED灯的状态  
  283.                ucLed_dr2=0;  
  284.                ucLed_dr3=1;  
  285.                ucLed_dr4=0;  
  286.                ucLed_dr5=1;  
  287.                ucLed_dr6=0;  
  288.                ucLed_dr7=1;  
  289.                ucLed_dr8=0;  
  290.                ucLed_dr9=1;  
  291.                ucLed_dr10=0;  
  292.                ucLed_dr11=1;  
  293.                ucLed_dr12=0;  
  294.                ucLed_dr13=1;  
  295.                ucLed_dr14=0;  
  296.                ucLed_dr15=1;  
  297.                ucLed_dr16=0;  
  298.   
  299.                ucLed_update=1;  //更新显示  
  300.                ucLedStep=1; //切换到下一个步骤  
  301.            }  
  302.            break;  
  303.      case 1:  
  304.            if(uiTimeCnt>=const_time_level) //时间到  
  305.            {  
  306.                uiTimeCnt=0; //时间计数器清零  
  307.   
  308.                ucLed_dr1=0;  //每个变量都代表一个LED灯的状态  
  309.                ucLed_dr2=1;  
  310.                ucLed_dr3=0;  
  311.                ucLed_dr4=1;  
  312.                ucLed_dr5=0;  
  313.                ucLed_dr6=1;  
  314.                ucLed_dr7=0;  
  315.                ucLed_dr8=1;  
  316.                ucLed_dr9=0;  
  317.                ucLed_dr10=1;  
  318.                ucLed_dr11=0;  
  319.                ucLed_dr12=1;  
  320.                ucLed_dr13=0;  
  321.                ucLed_dr14=1;  
  322.                ucLed_dr15=0;  
  323.                ucLed_dr16=1;  
  324.   
  325.                ucLed_update=1;  //更新显示  
  326.                ucLedStep=0; //返回到上一个步骤  
  327.            }  
  328.            break;  
  329.     
  330.    }  
  331.   
  332. }  
  333.   
  334.   
  335. void T0_time() interrupt 1  
  336. {  
  337.   TF0=0;  //清除中断标志  
  338.   TR0=0; //关中断  
  339.   
  340.   if(uiTimeCnt<0xffff)  //设定这个条件,防止uiTimeCnt超范围。  
  341.   {  
  342.       uiTimeCnt++;  //累加定时中断的次数,  
  343.   }  
  344.   
  345.   TH0=0xf8;   //重装初始值(65535-2000)=63535=0xf82f  
  346.   TL0=0x2f;  
  347.   TR0=1;  //开中断  
  348. }  
  349.   
  350. void delay_short(unsigned int uiDelayShort)   
  351. {  
  352.    unsigned int i;    
  353.    for(i=0;i<uiDelayShort;i++)  
  354.    {  
  355.      ;   //一个分号相当于执行一条空语句  
  356.    }  
  357. }  
  358.   
  359. void delay_long(unsigned int uiDelayLong)  
  360. {  
  361.    unsigned int i;  
  362.    unsigned int j;  
  363.    for(i=0;i<uiDelayLong;i++)  
  364.    {  
  365.       for(j=0;j<500;j++)  //内嵌循环的空指令数量  
  366.           {  
  367.              ; //一个分号相当于执行一条空语句  
  368.           }  
  369.    }  
  370. }  
  371.   
  372.   
  373. void initial_myself()  //第一区 初始化单片机  
  374. {  
  375.   
  376.   TMOD=0x01;  //设置定时器0为工作方式1  
  377.   
  378.   
  379.   TH0=0xf8;   //重装初始值(65535-2000)=63535=0xf82f  
  380.   TL0=0x2f;  
  381.   
  382.   
  383. }  
  384.   
  385. void initial_peripheral() //第二区 初始化外围  
  386. {  
  387.   EA=1;     //开总中断  
  388.   ET0=1;    //允许定时中断  
  389.   TR0=1;    //启动定时中断  
  390.   
  391. }   

总结陈词:
这节讲了把74HC595驱动程序翻译成类似单片机IO口直接驱动的方式,接下来,我们该如何来运用这种驱动方式实现跑马灯的程序?欲知详情,请听下回分解-----依次逐个点亮LED之后,再依次逐个熄灭LED的跑马灯程序。

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

已有0条评论

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

添加一条新评论

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

话题作者

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

x

畅学电子网订阅号