【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示

一、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端为低电平时,锁存器的数据输出到总线。

【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第1张图片
图1 74hc595引脚图
【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第2张图片
图2  74HC595引脚功能


下面具体介绍一下各引脚及其功能:

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真值表:

【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第3张图片
 图3 74hc595真值表


3.内部结构                                                

【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第4张图片
图4 74HC595内部结构图

其中,shift register为移位寄存器,latch为锁存器。

(1)移位寄存器

假如,我们要将二进制数据0111 1111 输入到595的移位寄存器中,下面的图片,模拟了前2个位输入的情景。


【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第5张图片
【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第6张图片
【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第7张图片
【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第8张图片

0111 1111这个数据完全输入后结果如下图所示:


【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第9张图片

这里要注意一个引脚,11脚,(shift registerclock input)  移位寄存器时钟引脚。上升沿有效。

(2)锁存器

锁存器是直接和8个输出引脚相通的,将移位寄存器的数据转移到锁存器后,Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 就可以接受到开始输入的一个字节的数据。所谓存储器,就是数据可以存在这个寄存器中,并不会随着一次输出就消失,只要74HC595不断电,也没有新的数据从移位寄存器中过来,数据就一直不变且有效。新的数据过来后,存储寄存器中的数据就会被覆盖更新。

这里要注意的是12脚为锁存器时钟。数据从位移寄存器转移到锁存器,也是需要时钟脉冲驱动的,这就是12脚的作用,它也是上升沿有效。

【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第10张图片


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.按键和上拉电阻那些不可不知的事

不知大家是否还记得,在任务七中,我们初次接触到了微动开关。还记得它有什么特点吗?

【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第11张图片
图5 微动开关

简单的两脚按钮是可以直接作为开关使用的,但是使用四脚按钮时就需要格外的注意了,它是对脚相断、邻脚相通的。意思就是说,如果我们不小心两端接到了相通的脚上,这个微动开关是起不到它原有的作用的。

而经常与微动开关搭配使用的,是上拉电阻,常用于floating状态下,是非常实用的一个搭配。上拉的意思就是把电位往上提升,把原本悬空的杂讯电位,拉到稳定的高电位状态。它的工作原理是这样子的,把一个20千欧的电阻,连接到5伏特的高电位。这些电学概念我们在这里不讲也罢,实际操作过程中还是很简单方便的。

【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第12张图片
图6 上拉电阻工作原理

事实上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时(为低电平),存储寄存器的数据输出到总线。

【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第13张图片
图7 74HC595引脚图

在今天的实验中,就用了两个微动开关,分别控制两个时钟:一个控制SH_CP的串行输入(一个一个输入),一个控制ST_CP并行输出(像一个大平台将所有信号一起输出),按钮按八下一个一个个信号,按第九下。于是我们设计了如下电路,有ds为低和ds为高两种情况:

【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第14张图片
图8 ds为高电平


【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第15张图片
图9 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函数就万事大吉了!具体的程序代码我们就放在9.3的教程里,9.2的分享就到此结束啦,感谢您的观看!






三、用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更常用

【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第16张图片
图10 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绘制的电路如下所示:

【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示_第17张图片
图11 用74HC595实现0-9循环显示,每个数字显示1秒  

(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)实验结果

下方为实验结果演示视频:


用74HC595实现0-9循环显示,每个数字显示1秒_腾讯视频



以上为“【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示”的全部内容,欢迎老师同学批评指正~


你可能感兴趣的:(【项目7-任务9-小组15】利用一位数码管实现0-9数字的显示)