51单片机74HC595操作
上次流水灯电路中将LED-E-IN直接接到VCC上,也就使得74HC573处于直通状态,这次将LED-E-IN引脚接到LED-E引脚上,LED-E引脚接74HC595的输出Q6。
流水灯电路:
595电路:
595的14、12、11引脚分别接到单片机的P1.0、P2.3、P1.4引脚。电路图大致就是这样,下面分析如何操作74HC595芯片,首先查阅芯片手册:
看标题可以知道595是一个8位串行输入,并行输出的移位寄存器,拥有3态输出,即高电平、低电平和高阻态。下面是其内部结构图:
可以看出,595的输入端由输出使能信号OUTPUT_ENABLE、锁存信号LATCH_ClOCK、串行数据输入端SERIAL_DATA_INPUT、移位信号SHIFT_CLOCK和复位信号RESET构成。最显眼的部分是中间的两排D触发器,第一排的D触发器上一个的输出接在下一个的输入端,如SRA的输出接在SRB的输入端,在每一个移位信号SHIFT_CLOCK作用下实现数据的移位。当数据全部移入第一排D触发器中后,只需要开启锁存信号LATCH_ClOCK就可以使第二排D触发器输出第一排D触发器中的数据,也即串行输入的数据。这是通过观察结构图得出的结论,下面分析一下手册上595的时序图:
这里标出了8个移位信号SHIFT_CLOCK的上升沿,结合下面的引脚描述,SHIFT_CLOCK在上升沿时候会将输入数据移入移位寄存器SRX(X=A、B、C等)中。RESET引脚是一个异步复位引脚,也就是不管单片机时钟信号是什么情况,只要RESET按键按下,就实现复位功能,也就是将结构图中第一排D触发器的输出全部置0。LATCH_CLOCK引脚只需一个上升沿就可以将输入数据锁存到移位寄存器中,这个需要结合结构图看,LATCH_CLOCK接的是第二排D触发器,它的输入是第一排D触发器的输出,即输入的数据,它的输出是595芯片的输出端,因此LATCH_CLOCK的上升沿会将输入的数据
送到输出端。OUTPUT_ENABLE输出端三态缓冲器的控制端,低电平使能输出,允许数据的传输,高电平则使输出呈现高阻态,可以理解为该芯片失去对下一级电路的控制,输出电平未知,可为高,也可为低。SQH端用于级联更多的595芯片,一片595芯片同时最多只能移8位数据,增加595芯片数目可以使一次性移位数据更多。
步入正题:分析时序图,当RESET由低变高后,芯片复位,从开始的第一个移位时钟上升沿分析,此时SERIAL_DATA_INPUT为高电平,所以1这个数据被送入结构图中左边第一排第一个触发器中,第二个上沿,此时数据为0,所以0送入第一排第一个触发器中,而1就被挤到第二个触发器中,接着在第三个时钟上升沿到来之前,LATCH_CLOCK出现了上升沿,因此输出Q会被立即更新,可以看到,QA变成了0,而QB还是1,由于一开始的RESET作用,第一排D触发器输出都被清了0,LATCH_CLOCK上升沿到来使输出数据更新,因此QC~QH全部变成了0,QB是由于数据移入了一个1,而维持不变。第三个时钟上升沿到来,从时序图上看这里送入的数据应该是0,但是分析到后面会发现这里应该是1,可能是时序图有误,不过无所谓,只要掌握分析方法就行了。直接到第7个时钟,也就是LATCH_CLOCK上升沿前端,此时送了7个数据是1011000,第8个数据QH不看,在LATCH_CLOCK上升沿进行输出数据的更新,可以看到,后面数据变成了00001101,数据1是最先送入的,所以最后送出,体现了一点一点移位的特点。到此595的分析就差不多了,可以进行编程了。
打开keil:
/***51单片机点亮流水灯***/
#include <reg52.h>
sbit Data_input=P1^0;//串行数据输入端
sbit Latch_Clock=P2^3;//锁存信号端,通过上面分析可以理解为输出数据更新信号
sbit Shift_Clock=P1^4;//移位信号端
/***delay_ms函数***/
void delay_ms(unsigned int xms)
{unsigned int i=0,j=0;for(i=xms;i>0;i--)for(j=110;j>0;j--);
}
void write595_byte(unsigned int dat)//595写一个字节操作
{unsigned int i=0;//用来移位Latch_Clock=0;//先把锁存信号拉低,也可以在数据移入后拉低,影响不大for(i=0;i<8;i++){Data_input=(dat<<i)&0x80;//左移数据,进行移位,&0x80是为了提取最高位数据Shift_Clock=0;//移位信号拉低Shift_Clock=1;//移位信号拉高,产生一个上升沿,移入数据}Shift_Clock=0;//移位信号拉低,也可以不拉,不影响Latch_Clock=1;//锁存信号拉高,产生一个上升沿,输出更新Latch_Clock=0;//拉低,与上面语句重复了,也可以不要
}
void main()
{unsigned int i=0;char LED=0x01;//用于移位/***流水灯亮灭方向标志***/char up_flag=0;//向上标志char down_flag=0;//向下标志down_flag=1;//默认向下write595_byte(0x40);//使能LED_E引脚,驱动LED的74HC573while(1){if(up_flag==1){for(i=0;i<8;i++)//向上循环移位{P1=~(LED<<i);delay_ms(1000);//延时1s}up_flag=0;down_flag=1;}if(down_flag==1)//向下循环移位{for(i=0;i<8;i++){P1=~((LED<<7)>>i);delay_ms(1000);}down_flag=0;up_flag=1;}}
}
这里要解释的就是下面这句话,这里相当于给P1.0写入了一个8位的数据,比如0x40,P1^0=0x40,在51单片机中,给端口赋值,只要不是0,单片机就会输出高电平(负数我没试过),0x40相当于十进制数64,效果与写1等价。
Data_input=(dat<<i)&0x80;
此外还有一点需要提醒,即数字电路的建立时间,看下面这段代码,拉低后直接进行拉高操作,我们知道,电平不会立马翻转,有一个上升时间,从手册上可以看出,移位信号的最小建立时间是ns级的,如果单片机的建立时间小于这个时间tsu,则会使这个移位信号无法稳定的被建立,如果单片机输出电平频繁的翻转,则每次都无法使移位信号建立起来,即高电平不高,低电平不低,信号也就无效。51单片机晶振12MHz,时钟频率0.083us,显然是满足这个条件的,因此可以不加_nop_()语句。
Shift_Clock=0;//移位信号拉低Shift_Clock=1;//移位信号拉高,产生一个上升沿,移入数据