0x06 使用74HC595扩展IO输出(上)

【目标】

  • 理解简单的串口逻辑
  • 使用74HC595芯片扩展IO输出

【所需素材】

  • 7段数码管 x 1
  • 270Ω 电阻 x 8
  • SN74HC595 x 1
图1 74HC595芯片

【基本原理】

 

=前言=

前面我们使用了静态和动态两种方式,点亮了一个数码管。 我们发现,通过动态驱动数码管的方式,需要的GPIO数量为 需要显示的位数+8 个GPIO,我们显示4位数字就需要12个GPIO,其实树莓派的GPIO资源并不是很充足,40个PIN中有12个是电源PIN,也就是只有28个数据PIN可用。显然用12个PIN来驱动4位数字太浪费了。 本篇我们通过一个串口转并口输出的芯片,来解决GPIO口资源紧张的问题。

=基本概念=

先祭出Datasheet,SN74HC595_Datasheet Datasheet中对595的功能描述如下:

图2 功能描述

我们把上面这坨东西翻译成人话: 595有一个8位的串口(serial)输入并口(parallel)输出的移位(shift)寄存器(register),这个位移寄存器给一个8位的锁存器提供数据。锁存器具有并行三态输出功能。移位寄存器和锁存器有不同的时钟(clocks)。移位寄存器有一个清空输入(SRCLR)、串口输入(SER)和一个级联串口输出。当输出使能(OE)为高电平时,输出处于高阻抗状态。 然而就算是人话,也还是众脸蒙逼。 接下来我们把上面提到的几个概念搞清楚

串口

串口是相对于并口来说的,数据在计算机中都是以1和0来存储,所以数据传输自然也就是1和0的传输,一个字节是由8个1和0组成,也就是8bit。这8bit通过一个pin一个一个传输,就是串行,如果通过8个pin,每个pin传输1bit,就是并口。

-移位寄存器-

这个寄存器用来接收串口输入的数据,每接收1bit,寄存器数据向前移动一位。移位寄存器为8bit。

-锁存器-

移位寄存器接收到的数据不会直接输出,需要将数据提交到锁存器之后,数据才会从595以并行的方式输出。 也就是说数据的接收和输出是异步进行的。移位寄存器接收数据的操作不会影响并口输出。 锁存器也是8bit,每一bit控制一个输出PIN Q[A-G]。

-三态输出-

输出口除了输出高低电平之外,还会呈现高阻抗的状态。高阻抗状态一般是用来屏蔽设备对线路的影响。 (本篇不涉及此功能)

-时钟-

可以简单的理解为一个高低电平的变化周期。后面我们结合具体的应用来说

-上升沿-

在电子学中,把逻辑电平由低向高变化的过程,称之为上升沿(rising edge)。反之由高向低变化称之为下降沿(falling edge)。 引申的说一下信号边缘,信号边缘指的是一个电平高低变化的方向,并不是电平本身的高或者低。一般时钟控制电路都是通过T触发器来获得时钟,而T触发器是靠电平的高低变化来触发。

=74HC595工作原理=

我们先看一下引脚图

图3 74HC595引脚图

看起来接口不少,其实需要通过树莓派操作的端口最少可以只用3个(SER、RCLK、SRCLK),工作原理也很简单。 将数据发送到595进行输出大概概括一下,需要如下几个步骤:

  1. 将需要发送的数据置于SER引脚;
  2. SRCLK制造一个上升沿信号,将SER引脚状态移入移位寄存器; 我们假设移位寄存器叫S,当遇到SRCLK上升沿时,SER的数据会写入S[H],此时S[H]的数据会移到S[G],S[G]的数据移动到S[F],后面各位依次向前移动。
  3. 循环执行1和2,直到数据发送完毕;
  4. RCLK制造一个上升沿,将移位寄存器的数据写入锁存器; S[A]的数据写入锁存器Q[A],S[B]的数据写入Q[B],以此类推。

这样,就完成了串口到并口的转换过程。 工作过程也可以看下面的GIF,红色代表高电平,黑色代表低电平。

图4 74HC595工作原理图解

【硬件连接】

引脚I/O描述接线
VCC-电源正极。74HC595为宽电压供电,支持2~6V供电树莓派3.3 Power
GND-接地树莓派GND
Q(A~H)O并口输出。QA接数码管A段,QB接数码管B段 ... QH接数码管DP段
QH‘O级联串口输出本文不用,悬空不连接
SERISerial的简写,串口输入。有些文档中也标为DS树莓派 wPi.3
OEIOutput Enable,输出使能,低电平有效。使能是一个专有名词,英文为Enable。树莓派GND
接地保持输出有效,如果想通过程序控制,可以接到树莓派的数据pin上。
RCLKIRegister Clock,锁存器时钟树莓派 wPi.2
SRCLKISerial Register Clock,移位寄存器时钟树莓派 wPi.0
SRCLRISerial Register Clear,移位寄存器清空树莓派3.3 Power
保持高电平,不清除移位寄存器

【程序实现】

 

74hc595.h

#include <wiringPi.h>
/*
 +-----+-----+---------+------+---+---Pi 3---+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
 |   2 |   8 |   SDA.1 | ALT0 | 1 |  3 || 4  |   |      | 5v      |     |     |
 |   3 |   9 |   SCL.1 | ALT0 | 1 |  5 || 6  |   |      | 0v      |     |     |
 |   4 |   7 | GPIO. 7 |   IN | 1 |  7 || 8  | 1 | IN   | TxD     | 15  | 14  |
 |     |     |      0v |      |   |  9 || 10 | 1 | ALT5 | RxD     | 16  | 15  |
 |  17 |   0 | GPIO. 0 |   IN | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |
 |  27 |   2 | GPIO. 2 |   IN | 1 | 13 || 14 |   |      | 0v      |     |     |
 |  22 |   3 | GPIO. 3 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |
 |     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |
 |  10 |  12 |    MOSI |   IN | 0 | 19 || 20 |   |      | 0v      |     |     |
 |   9 |  13 |    MISO |   IN | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |
 |  11 |  14 |    SCLK |   IN | 0 | 23 || 24 | 1 | OUT  | CE0     | 10  | 8   |
 |     |     |      0v |      |   | 25 || 26 | 1 | OUT  | CE1     | 11  | 7   |
 |   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |
 |   5 |  21 | GPIO.21 |   IN | 0 | 29 || 30 |   |      | 0v      |     |     |
 |   6 |  22 | GPIO.22 |   IN | 0 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |
 |  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |
 |  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |
 |  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |
 |     |     |      0v |      |   | 39 || 40 | 1 | IN   | GPIO.29 | 29  | 21  |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+---Pi 3---+---+------+---------+-----+-----+
*/

#define SER 3
#define RCLK 2
#define SRCLK 0

typedef unsigned char u8;

void init_74hc595();
void sendbyte_74hc595(u8 dat);

 

74hc595.c

#include <wiringPi.h>
#include "74hc595.h"

/*
 * 74HC595初始化
 */ 
void init_74hc595()
{
        pinMode(SER, OUTPUT);
        pinMode(RCLK, OUTPUT);
        pinMode(SRCLK, OUTPUT);
}

/*
 * 发送1字节数据到595
 * @param dat 待发送的数据
 */
void sendbyte_74hc595(u8 dat)
{
        u8 i;

        for (i=0;i<8;i++)
        {
                if((dat&1) == 1)
                /* 按A到H的顺序发送
                 * 每次发送1bit数据到SER
                 */
                {
                        digitalWrite(SER,HIGH);
                } else {
                        digitalWrite(SER,LOW);
                }
                digitalWrite(SRCLK,LOW);
                digitalWrite(SRCLK,HIGH); // 在SRCLK上制造一个上升沿,将SER数据存入移位寄存器
                dat>>=1;
        }
        digitalWrite(RCLK,LOW);
        digitalWrite(RCLK,HIGH); // 在RCLK上制造一个上升沿,将移位寄存器数据发送到锁存器
}

 

main.c

#include <wiringPi.h>
#include "74hc595.h"

int matrix[10] = {
    0b11111100, // 0x7E, // 0
    0b01100000, // 0x30, // 1
    0b11011010, // 0x6D, // 2
    0b11110010, // 0x79, // 3
    0b01100110, // 0x33, // 4
    0b10110110, // 0x5B, // 5
    0b10111110, // 0x5F, // 6
    0b11100100, // 0x70, // 7
    0b11111110, // 0x7F, // 8
    0b11110110 // 0x7B // 9
};

int main(void)
{
    if(wiringPiSetup() != 0)
        return 1;

    init_74hc595();

    int i;

    for(i=0;i&lt;10;i++)  // 显示0到9
    {
        send595byte(matrix[i]);
        delay(500);
    }

    return 0;
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注