一、74HC595的引脚及其功能
1.概述
我们都有Arduino NANO了,为什么还要用74HC595?
扩展输出用!
扩展输出是什么?
以Arduino Uno为例,它的0-13号口可以接LED灯,13号口自己带一个灯,但一般来说Arduino的0和1号口用来串口通信,不用来接灯,只有2-13号口是接灯的,也就是有12个口可以接灯。但假如想要接20个LED灯怎么办呢?这个时候就需要扩展输出。
今天给大家介绍一种常用于扩展数字输出的芯片74HC595,它是一款漏极开路输出的CMOS移位寄存器,输出端口为可控的三态输出端,亦能串行输出控制下一级级联芯片。
74HC595的作用就是把串行的信号转为并行的信号,常用在各种数码管以及点阵屏的驱动芯片,使用74HC595可以节约单片机的I/O口资源,用3个I/O就可以控制8个数码管的引脚。此外,它还具有一定的驱动能力,可以免掉三极管等放大电路,所以这块芯片是驱动数码管的神器,应用非常广泛。
2.特点:串入并出
74HC595的最重要的功能就是:串行输入,并行输出。
74HC595具有8位移位寄存器,1个锁存器和三态输出功能。其中,移位寄存器和锁存器的时钟信号是相互独立的。
数据在SH_CP的上升沿输入,在ST_CP的上升沿进入到锁存器中去。如果两个时钟连在一起,则移位寄存器总是比锁存器早一个脉冲。移位寄存器有一个串行移位输入(Ds)、一个串行输出(Q7’)和一个异步的低电平复位,锁存器有一个并行8位的、具备三态的总线输出,当OE端为低电平时,锁存器的数据输出到总线。
下面具体介绍一下各引脚及其功能:
1-7、15脚:并行输出引脚。
8脚:GND,接地。
9 脚:串行数据出口引脚。当移位寄存器中的数据多于8bit时,会把已有的bit“挤出去”,就是从这里出去的。用于595的级联。
10脚:MR,低电平时,清空移位寄存器中已有的bit数据。一般不用,直接接高电平即可。
11脚:SCK,移位寄存器时钟引脚,上升沿时,移位寄存器中的bit数据整体后移,并接受新的bit(从SER输入)。
12脚:RCK,存储寄存器时钟输入引脚。上升沿时,数据从移位寄存器转存到锁存器中。
13脚:OE,输出使能控制脚,它是低电才使能输出,所以接地GND。
14脚:DS(SER),串行数据输入引脚。
16脚:Vcc,接电源。
下附74hc595真值表:
3.内部结构
其中,shift register为移位寄存器,latch为锁存器。
(1)移位寄存器
假如,我们要将二进制数据0111 1111 输入到595的移位寄存器中,下面的图片,模拟了前2个位输入的情景。
0111 1111这个数据完全输入后结果如下图所示:
这里要注意一个引脚,11脚,(shift registerclock input) 移位寄存器时钟引脚。上升沿有效。
(2)锁存器
锁存器是直接和8个输出引脚相通的,将移位寄存器的数据转移到锁存器后,Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 就可以接受到开始输入的一个字节的数据。所谓存储器,就是数据可以存在这个寄存器中,并不会随着一次输出就消失,只要74HC595不断电,也没有新的数据从移位寄存器中过来,数据就一直不变且有效。新的数据过来后,存储寄存器中的数据就会被覆盖更新。
这里要注意的是12脚为锁存器时钟。数据从位移寄存器转移到锁存器,也是需要时钟脉冲驱动的,这就是12脚的作用,它也是上升沿有效。
4.74HC595具体使用步骤
第一步
目的:将要准备输入的位数据移入74HC595数据输入端上。
方法:送位数据到_595。
第二步
目的:将位数据逐位移入74HC595,即数据串入。
方法:SH_CP产生一上升沿,将DS上的数据移入74HC595移位寄存器中,先送低位,后送高位。
第三步
目的:并行输出数据。即数据并出。
方法:ST_CP产生一上升沿,将由DS上已移入数据寄存器中的数据送入到输出锁存器。
说明: 从上可分析:从SH_CP产生一上升沿(移入数据)和ST_CP产生一上升沿(输出数据)是二个独立过程,实际应用时互不干扰。即可输出数据的 同时移入数据。
二、74HC595的串入并出
1.概述
首先来介绍一下任务9.2要实现的目标:今天我们需要通过一个按键驱动移位亮灯的小实验,来实现芯片74HC595串入并出的功能。安排任务9.2的意义就在于巩固前面关于芯片74HC595、按键等的基础知识,再为9.3的实验专案做基础。下面我们就一起来看一下吧。
2.按键和上拉电阻那些不可不知的事
不知大家是否还记得,在任务七中,我们初次接触到了微动开关。还记得它有什么特点吗?
简单的两脚按钮是可以直接作为开关使用的,但是使用四脚按钮时就需要格外的注意了,它是对脚相断、邻脚相通的。意思就是说,如果我们不小心两端接到了相通的脚上,这个微动开关是起不到它原有的作用的。
而经常与微动开关搭配使用的,是上拉电阻,常用于floating状态下,是非常实用的一个搭配。上拉的意思就是把电位往上提升,把原本悬空的杂讯电位,拉到稳定的高电位状态。它的工作原理是这样子的,把一个20千欧的电阻,连接到5伏特的高电位。这些电学概念我们在这里不讲也罢,实际操作过程中还是很简单方便的。
事实上Arduino考虑到了上拉电阻的问题,已经帮我们设计好了电路,我们只需要通过指令,就能开启工作接脚的上拉电阻功能。但是实际上我们是没有一个专门的上拉电阻指令的,需要以指令搭配的形式来实现,用到的指令是让接脚输出高电位的digitalWrite(某个接脚, HIGH);以及设定接脚为输出模式的pinMode(同个接脚,OUTPUT);。那照这个逻辑讲,pinMode的INPUT配上digitalWrite的LOW,应该会有稳定低电位的下拉电阻的功能,但其实并不是这样的什么都不会发生,因为Arduino并没有内接下拉电阻。
这里附上自制的系列课中关于上拉电阻的一节。密码:792792。
若在本网页无法观看,可点击右下角“优酷视频”的LOGO进入优酷官网或打开客户端进行观看~
关于微动开关和上拉电阻的内容我们就介绍到这里,下面来看一下74HC595芯片和实验。
3.关于74HC595的串入并出
还记得任务9.1的引脚和功能吗,其中最重要的功能就是:串行输入,并行输出。数据在SH_CP的上升沿输入,在ST_CP的上升沿进入的存储寄存器中去。如果两个时钟连在一起,则移位寄存器总是比存储寄存器早一个脉冲。移位寄存器有一个串行移位输入(Ds),和一个串行输出(Q7’),和一个异步的低电平复位,存储寄存器有一个并行8位的,具备三态的总线输出,当使能 OE时(为低电平),存储寄存器的数据输出到总线。
在今天的实验中,就用了两个微动开关,分别控制两个时钟:一个控制SH_CP的串行输入(一个一个输入),一个控制ST_CP并行输出(像一个大平台将所有信号一起输出),按钮按八下一个一个个信号,按第九下。于是我们设计了如下电路,有ds为低和ds为高两种情况:
4.用74HC595实现0-9循环显示,每个数字显示一秒
回想一下任务8这个实验是怎样实现的呢?我们带大家来回顾一下吧:
int a=7;//定义数字接口7 连接a 段数码管
int b=6;// 定义数字接口6 连接b 段数码管
int c=5;// 定义数字接口5 连接c 段数码管
int d=11;// 定义数字接口11 连接d 段数码管
int e=10;// 定义数字接口10 连接e 段数码管
int f=8;// 定义数字接口8 连接f 段数码管
int g=9;// 定义数字接口9 连接g 段数码管
int dp=4;// 定义数字接口4 连接dp 段数码管
unsigned char num[10][8] =
{
//1为点亮,0为关闭,a表示数码管a的led灯,其他类似
//a b c d e f g h
{1, 1, 1, 1, 1, 1, 0, 0}, //0
{0, 1, 1, 0, 0, 0, 0, 0}, //1
{1, 1, 0, 1, 1, 0, 1, 0}, //2
{1, 1, 1, 1, 0, 0, 1, 0}, //3
{0, 1, 1, 0, 0, 1, 1, 0}, //4
{1, 0, 1, 1, 0, 1, 1, 0}, //5
{1, 0, 1, 1, 1, 1, 1, 0}, //6
{1, 1, 1, 0, 0, 0, 0, 0}, //7
{1, 1, 1, 1, 1, 1, 1, 0}, //8
{1, 1, 1, 1, 0, 1, 1, 0}, //9
};
void setup()
{
pinMode(a,OUTPUT); //设置引脚为输出
pinMode(b,OUTPUT); //设置引脚为输出
pinMode(c,OUTPUT); //设置引脚为输出
pinMode(d,OUTPUT); //设置引脚为输出
pinMode(e,OUTPUT); //设置引脚为输出
pinMode(f,OUTPUT); //设置引脚为输出
pinMode(g,OUTPUT); //设置引脚为输出
pinMode(dp,OUTPUT); //设置引脚为输出
}
void loop()
{
for( int i = 0 ; i <= 9 ; i++) //循环显示0-9
{
digitalWrite(a,num[i][0]); //设置a 引脚的电平
digitalWrite(b,num[i][1]); //设置b 引脚的电平
digitalWrite(c,num[i][2]); //设置c 引脚的电平
digitalWrite(d,num[i][3]); //设置d 引脚的电平
digitalWrite(e,num[i][4]); //设置e 引脚的电平
digitalWrite(f,num[i][5]); //设置f 引脚的电平
digitalWrite(g,num[i][6]); //设置g 引脚的电平
digitalWrite(dp,num[i][7]); //设置h 引脚的电平
delay(1000); //延迟1秒
}
}
看了这个程序可以发现,我们的Arduino用了好多好多引脚呢,程序还有二维数组并且非常长!这对于Arduino初学者或者程序小白来说就有太多的不方便。
不过没关系,所有这些问题,我们用74HC595就能统统解决!我们将74HC595连入电路,再搭配一个shiftOut函数就万事大吉了!具体的程序代码我们就放在第三部分中啦,我们第三部分见~
三、用74HC595实现0-9循环显示,每个数字显示1秒
(使用Arduino的shiftOut函数,重点介绍函数用法、电路连接,Fritzing绘出电路图)
根据任务要求不难看出,本次实验所要达成的数码管显示效果与项目七的4.2任务相同,区别仅在于本实验任务需要使用74HC595芯片和Arduino的shiftOut()函数。
既然已经实现了要求的显示结果,为什么还要用74HC595芯片和Arduino的shiftOut()函数再做一遍?
原因在于以下几个方面:
(1)如果不用芯片和shiftOut()函数,需要连接多个Arduino的引脚,而使用芯片和shiftOut()函数,只需要连接Arduino的五个引脚,其中还包括一根接电源的线和一根接地的线。
(2)如果不用芯片和shiftOut()函数,为了将Arduino上的多个引脚与数码管的多个引脚一一相连,并使其依次显示,编写代码时需要使用二维数组。而使用shiftOut()函数,则可以直接使用一维数组,代码的编写更为简单方便。
(3)如果不用shiftOut()函数而只用循环函数来实现,代码十分冗长,而用shiftOut()函数,只需要在loop函数中应用一个for循环,代码更短更易读。
接下来让我们真实地感受一下只用loop循环的冗长代码,程序如下:
int ds= 8; //定义ds接D8
int sh= 11; //定义sh引脚接D11
int st= 12; //定义st引脚接D12
int n0[8]={1,1,1,1,1,1,0,1};
int n1[8]={0,0,0,0,1,1,0,1};
int n2[8]={1,1,0,1,1,0,1,1};
int n3[8]={1,1,1,1,0,0,1,1};
int n4[8]={0,1,1,0,0,1,1,1};
int n5[8]={1,0,1,1,0,1,1,1};
int n6[8]={1,0,1,1,1,1,1,1};
int n7[8]={1,1,1,0,0,1,0,1};
int n8[8]={1,1,1,1,1,1,1,1};
int n9[8]={1,1,1,1,0,1,1,1}; //定义数组
void putX(int CY){ //CY表示数组中的高或低电平
digitalWrite(sh,LOW);
digitalWrite(ds,CY);
digitalWrite(sh,HIGH);
} //定义putX()函数
void num0(){
digitalWrite(st,LOW); //将st引脚写入低电平
for (int i=0;i<8;i++){
putX(n0[i]);
} //执行putX()函数
digitalWrite(st,HIGH); //将st引脚写入高电平
}
void num1(){
digitalWrite(st,LOW); //将st引脚写入低电平
for (int i=0;i<8;i++){
putX(n1[i]);
} //执行putX()函数
digitalWrite(st,HIGH); //将st引脚写入高电平
}
void num2(){
digitalWrite(st,LOW); //将st引脚写入低电平
for (int i=0;i<8;i++){
putX(n2[i]);
} //执行putX()函数
digitalWrite(st,HIGH); //将st引脚写入高电平
}
void num3(){
digitalWrite(st,LOW); //将st引脚写入低电平
for (int i=0;i<8;i++){
putX(n3[i]);
} //执行putX()函数
digitalWrite(st,HIGH); //将st引脚写入高电平
}
void num4(){
digitalWrite(st,LOW); //将st引脚写入低电平
for (int i=0;i<8;i++){
putX(n4[i]);
} //执行putX()函数
digitalWrite(st,HIGH); //将st引脚写入高电平
}
void num5(){
digitalWrite(st,LOW); //将st引脚写入低电平
for (int i=0;i<8;i++){
putX(n5[i]);
} //执行putX()函数
digitalWrite(st,HIGH); //将st引脚写入高电平
}
void num6(){
digitalWrite(st,LOW); //将st引脚写入低电平
for (int i=0;i<8;i++){
putX(n6[i]);
} //执行putX()函数
digitalWrite(st,HIGH); //将st引脚写入高电平
}
void num7(){
digitalWrite(st,LOW); //将st引脚写入低电平
for (int i=0;i<8;i++){
putX(n7[i]);
} //执行putX()函数
digitalWrite(st,HIGH); //将st引脚写入高电平
}
void num8(){
digitalWrite(st,LOW); //将st引脚写入低电平
for (int i=0;i<8;i++){
putX(n8[i]);
} //执行putX()函数
digitalWrite(st,HIGH); //将st引脚写入高电平
}
void num9(){
digitalWrite(st,LOW); //将st引脚写入低电平
for (int i=0;i<8;i++){
putX(n9[i]);
} //执行putX()函数
digitalWrite(st,HIGH); //将st引脚写入高电平
}
void setup() {
pinMode(ds,OUTPUT);
pinMode(st,OUTPUT);
pinMode(sh,OUTPUT);
} //将D8、D11、D12引脚设置为输出状态
void dly(){
delay(1000);
}
void loop() {
num0();
dly();
num1();
dly();
num2();
dly();
num3();
dly();
num4();
dly();
num5();
dly();
num6();
dly();
num7();
dly();
num8();
dly();
num9();
dly();
} //循环执行从0-9数字的显示且每个延迟1s
1.关于shiftOut()函数
(1)四个参数
函数shiftOut(dataPin,clockPin,bitOrder,val)有四个参数,即:dataPin、clockPin、bitOrder、val,其具体含义如下:
dataPin:对于Arduino板,它是输出每一位数据的引脚(即指Arduino板上的某个数字口)。引脚需配置成输出模式。
clockPin:这是为位移芯片提供时钟的引脚(即指Arduino板上的某个数字口)。当我们准备将dataPin的数据推送出去时,发送一个高电平,这个引脚须配置成输出模式!
bitOrder:输出位的顺序。
*两种方式:
最高位优先(MSBFIRST:most-significant bit first)
最低位优先(LSBFIRST:least-significant bit first)*
val:所要输出的数据值,该数据值将以byte形式(8位二进制)输出。
补充:MSB较LSB更常用
(2)shiftOut()函数的参数与74HC595芯片的对应关系
dataPin:对应74HC595芯片的DS引脚(数据引脚),需要注意的是这些数据必须在SCK(SH_CP)引脚触发上升沿时才会被逐位送入74HC595芯片中。
clockPin:对应74HC595芯片的** SCK(SH_CP)引脚**,负责将dataPin送来的数据逐位地送到芯片的寄存器中,每出现一个上升沿就送入一位到寄存器中。
补充:74HC595芯片还有一个RCK(ST_CP)引脚,这个引脚负责输出芯片中已有的数据到8个输出管脚,也就是说,如果没有RCK(ST_CP)引脚的触发,芯片不会向外输出数据,与clockPin同属于上升沿触发,即需要一个由低到高的电平跳变来触发数据输出。
(3)数据的操作方式
shiftOut()函数的作用是将一个数据的一个(8位)字节一次性送出,其内部实际是配合clockPin的时钟信号,一个一个地将bit写入位移芯片。它是一个无返回值函数,从最高有效位(最左边)或最低有效位(最右边)开始,依次向数据脚写入每一位,之后时钟脚被拉高或拉低,指示刚才的数据有效。
2.实验内容
(1)电路图
使用Fritzing绘制的电路如下所示:
(2)程序代码
int DS=8;//定义DS引脚接D8
int SH_CP=12;//定义SH_CP引脚接D12
int ST_CP=11;//定义ST_CP引脚接D11
int a[10]={253,13,219,243,103,183,191,229,255,247};
//用一维数组,以十进制的形式表示数码管上显示的0-9
void setup(){
pinMode(DS,OUTPUT);
pinMode(SH_CP,OUTPUT);
pinMode(ST_CP,OUTPUT);
}//将D8、D11、D12引脚设置为输出状态
void loop(){
for(int i=0;i<10;i++){
digitalWrite(ST_CP,LOW);//将ST_CP脚置为低电平
shiftOut( DS,SH_CP, LSBFIRST,a[i]);//循环输出0-9数字
digitalWrite(ST_CP,HIGH);//将ST_CP脚置为高电平
delay(1000);//延迟1s
}
}
可以明显地看出,同样的任务显示要求,使用shiftOut()函数的代码所占篇幅较前面提到的只用循环函数的代码大大缩减,这也证实了本篇最开始提到的用74HC595芯片和Arduino的shiftOut()函数来完成任务的原因。
(3)实验结果
以上为“【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示”的全部内容,欢迎老师同学批评指正~