3 Star 15 Fork 4

建伟F4nniu / FN1895E-MCU101

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
MCU017.md 7.49 KB
一键复制 编辑 原始数据 按行查看 历史
建伟F4nniu 提交于 2016-12-23 00:30 . Track 1 files into repository.

第十七节:两片联级74HC595驱动16个LED灯的基本驱动程序。

开场白:

上一节讲了如何把矩阵键盘翻译成独立按键的处理方式。这节讲74HC595的驱动程序。要教会大家两个知识点:

  • 第一点:朱兆祺的学习板是用74HC595控制LED,因此可以直接把595的OE引脚接地。如果在工控中,用来控制继电器,那么此芯片的片选脚OE不要为了省一个IO口而直接接地,否则会引起上电瞬间继电器莫名其妙地动作。为了解决这个问题,OE脚应该用一个IO口单独驱动,并且千万要记住,此IO必须接一个15K左右的上拉电阻,然后在程序刚上电运行时,先把OE置高,并且尽快把所有的74HC595输出口置低,然后再把OE置低.当然还有另外一种解决办法,就是用一个10uF的电解电容跟一个100K的下拉电阻,组成跟51单片机外围复位电路原理一样的电路,连接到OE口,这样确保上电瞬间OE口有一小段时间是处于高电平状态,在此期间,尽快通过软件把74hc595的所有输出口置低。
  • 第二点:两个联级74HC595的工作过程:每个74HC595内部都有一个8位的寄存器,两个联级起来就有两个寄存器。ST引脚就相当于一个刷新信号引脚,当ST引脚产生一个上升沿信号时,就会把寄存器的数值输出到74HC595的输出引脚并且锁存起来,DS是数据引脚,SH是把新数据送入寄存器的时钟信号。也就是说,SH引脚负责把数据送入到寄存器里,ST引脚负责把寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来。

具体内容,请看源代码讲解。

  • (1)硬件平台:基于朱兆祺51单片机学习板。
  • (2)实现功能:两片联级的74HC595驱动的16个LED灯交叉闪烁。比如,先是第1,3,5,7,9,11,13,15八个灯亮,其它的灯都灭。然后再反过来,原来亮的就灭,原来灭的就亮。交替闪烁。
  • (3)源代码讲解如下:
#include "REG52.H"

#define const_time_level 200

void initial_myself();
void initial_peripheral();
void delay_short(unsigned int uiDelayShort);
void delay_long(unsigned int uiDelaylong);
void led_flicker();
void hc595_drive(unsigned char ucLedStatusTemp16_09, unsigned char ucLedStatusTemp08_01);
void T0_time();  //定时中断函数

/* 注释一:
* 朱兆祺的学习板是用74HC595控制LED,因此可以直接把595的OE引脚接地。如果在工控中,用来控制继电器,
* 那么此芯片的片选脚OE不要为了省一个IO口而直接接地,否则会引起上电瞬间继电器莫名其妙地动作。
* 为了解决这个问题,OE脚应该用一个IO口单独驱动,并且千万要记住,此IO必须接一个15K左右的
* 上拉电阻,然后在程序刚上电运行时,先把OE置高,并且尽快把所有的74HC595输出口置低,然后再把OE置低.
* 当然还有另外一种解决办法,就是用一个10uF的电解电容跟一个100K的下拉电阻,组成跟51单片机外围复位电路原理
* 一样的电路,连接到OE口,这样确保上电瞬间OE口有一小段时间是处于高电平状态,在此 期间,
* 尽快通过软件把74hc595的所有输出口置低。
*/
sbit hc595_sh_dr = P2 ^ 3;
sbit hc595_st_dr = P2 ^ 4;
sbit hc595_ds_dr = P2 ^ 5;


unsigned char ucLedStep = 0; //步骤变量
unsigned int  uiTimeCnt = 0; //统计定时中断次数的延时计数器


void main()
{
    initial_myself();
    delay_long(100);
    initial_peripheral();
    while(1)
    {
        led_flicker();
    }

}

/* 注释二:
* 两个联级74HC595的工作过程:
* 每个74HC595内部都有一个8位的寄存器,两个联级起来就有两个寄存器。ST引脚就相当于一个刷新
* 信号引脚,当ST引脚产生一个上升沿信号时,就会把寄存器的数值输出到74HC595的输出引脚并且锁存起来,
* DS是数据引脚,SH是把新数据送入寄存器的时钟信号。也就是说,SH引脚负责把数据送入到寄存器里,ST引脚
* 负责把寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来。
*/
void hc595_drive(unsigned char ucLedStatusTemp16_09, unsigned char ucLedStatusTemp08_01)
{
    unsigned char i;
    unsigned char ucTempData;
    hc595_sh_dr = 0;
    hc595_st_dr = 0;

    ucTempData = ucLedStatusTemp16_09; //先送高8位
    for(i = 0; i < 8; i++)
    {
        if(ucTempData >= 0x80)hc595_ds_dr = 1;
        else hc595_ds_dr = 0;

        hc595_sh_dr = 0;   //SH引脚的上升沿把数据送入寄存器
        delay_short(15);
        hc595_sh_dr = 1;
        delay_short(15);

        ucTempData = ucTempData << 1;
    }

    ucTempData = ucLedStatusTemp08_01; //再先送低8位
    for(i = 0; i < 8; i++)
    {
        if(ucTempData >= 0x80)hc595_ds_dr = 1;
        else hc595_ds_dr = 0;

        hc595_sh_dr = 0;   //SH引脚的上升沿把数据送入寄存器
        delay_short(15);
        hc595_sh_dr = 1;
        delay_short(15);

        ucTempData = ucTempData << 1;
    }

    hc595_st_dr = 0; //ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来
    delay_short(15);
    hc595_st_dr = 1;
    delay_short(15);

    hc595_sh_dr = 0;  //拉低,抗干扰就增强
    hc595_st_dr = 0;
    hc595_ds_dr = 0;

}


void led_flicker() ////第三区 LED闪烁应用程序
{
    switch(ucLedStep)
    {
    case 0:
        if(uiTimeCnt >= const_time_level) //时间到
        {
            uiTimeCnt = 0; //时间计数器清零
            hc595_drive(0x55, 0x55);
            ucLedStep = 1; //切换到下一个步骤
        }
        break;
    case 1:
        if(uiTimeCnt >= const_time_level) //时间到
        {
            uiTimeCnt = 0; //时间计数器清零
            hc595_drive(0xaa, 0xaa);
            ucLedStep = 0; //返回到上一个步骤
        }
        break;

    }

}


void T0_time() interrupt 1
{
    TF0 = 0; //清除中断标志
    TR0 = 0; //关中断

    if(uiTimeCnt < 0xffff) //设定这个条件,防止uiTimeCnt超范围。
    {
        uiTimeCnt++;  //累加定时中断的次数,
    }

    TH0 = 0xf8; //重装初始值(65535-2000)=63535=0xf82f
    TL0 = 0x2f;
    TR0 = 1; //开中断
}

void delay_short(unsigned int uiDelayShort)
{
    unsigned int i;
    for(i = 0; i < uiDelayShort; i++)
    {
        ;   //一个分号相当于执行一条空语句
    }
}

void delay_long(unsigned int uiDelayLong)
{
    unsigned int i;
    unsigned int j;
    for(i = 0; i < uiDelayLong; i++)
    {
        for(j = 0; j < 500; j++) //内嵌循环的空指令数量
        {
            ; //一个分号相当于执行一条空语句
        }
    }
}


void initial_myself()  //第一区 初始化单片机
{

    TMOD = 0x01; //设置定时器0为工作方式1


    TH0 = 0xf8; //重装初始值(65535-2000)=63535=0xf82f
    TL0 = 0x2f;


}

void initial_peripheral() //第二区 初始化外围
{
    EA = 1;   //开总中断
    ET0 = 1;  //允许定时中断
    TR0 = 1;  //启动定时中断

}

总结陈词:

这节讲了74HC595的驱动程序,它是一次控制16个LED同时亮灭的,在实际中应用不太方便,如果我们想要像单片机IO口直接控制LED那样方便,我们该怎么编写程序呢?欲知详情,请听下回分解-----把74HC595驱动程序翻译成类似单片机IO口直接驱动的方式。

(未完待续,下节更精彩,不要走开哦)

C
1
https://gitee.com/F4NNIU/FN1895E-MCU101.git
git@gitee.com:F4NNIU/FN1895E-MCU101.git
F4NNIU
FN1895E-MCU101
FN1895E-MCU101
Development

搜索帮助