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:
#include <reg52.h>
sbit Data_input=P1^0;
sbit Latch_Clock=P2^3;
sbit Shift_Clock=P1^4;
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)
{
unsigned int i=0;
Latch_Clock=0;
for(i=0;i<8;i++)
{
Data_input=(dat<<i)&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);
while(1)
{
if(up_flag==1)
{
for(i=0;i<8;i++)
{
P1=~(LED<<i);
delay_ms(1000);
}
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;
|