(1)实验平台:普中51单片机开发板-A2&A3&A4
在前面章节实验中, 我们是直接使用单片机 IO 口控制外围设备, 从 LED 流水灯到动态数码管显示, 可以看到这些外围设备已经占据了很多的 IO 口, 而 51单片机 IO 口非常有限, 如果想要连接更多外围设备, 此时可以通过 IO 扩展来实现。 本章就来介绍另外一种 IO 口扩展方式-串转并, 使用的芯片是 74HC595。 开发板板载 1 个 74HC595 芯片, 仅需单片机 3 个 IO 口即可扩展 8 个, 如果需要还可以将 2 个 74HC595 级联扩展出 16 个 IO, 这就实现用少数 IO 资源控制多个设备。 通过本章的学习, 让大家学会使用 74HC595 芯片来扩展 IO 口。 本章所要实现的功能是: 通过 74HC595 模块控制 LED 点阵以一行循环滚动显示。 学习本章可以参考前面的实验章节内容。 本章分为如下几部分内容:
[15.1 74HC595 芯片介绍](#15.1 74HC595 芯片介绍)
[15.2 硬件设计](#15.2 硬件设计)
[15.3 软件设计](#15.3 软件设计)
[15.4 实验现象](#15.4 实验现象)
15.1 74HC595 芯片介绍
74HC595 是一个 8 位串行输入、 并行输出的位移缓存器, 其中并行输出为三态输出(即高电平、 低电平和高阻抗) 。 芯片管脚及功能说明如下:


上面两张都是 74HC595 芯片管脚图, 细心的朋友就会发现左侧的 1 脚是 QB,而右侧芯片的 1 脚是 Q1, 左侧芯片的 11 脚是 SCK, 而右侧芯片的 11 脚是 SH_CP,还有很多其他管脚不一样, 其实这个都没有什么, 每个人在绘制芯片管脚图时命名可能不一样而已, 看一个芯片重点是管脚功能。
15 和 1 到 7 脚 QA--QH: 并行数据输出
9 脚 QH 非: 串行数据输出
10 脚 SCLK 非( MR) : 低电平复位引脚
11 脚 SCK( SHCP) : 移位寄存器时钟输入
12 脚 RCK( STCP) : 存储寄存器时钟输入
13 脚 G 非( OE) : 输出有效
14 脚 SER( DS) : 串行数据输入
74HC595 是具有 8 位移位寄存器和一个存储器, 三态输出功能。 移位寄存器和存储器是单独的时钟。 数据在 SCK 的上升沿输入, 在 RCK 的上升沿进入到存储器中。 如果两个时钟连在一起, 则移位寄存器总是比存储器早一个脉冲。 移位寄存器有一个串行输入(DS) , 和一个串行输出(Q7 非) , 和一个异步的低电平复位, 存储寄存器有一个并行 8 位的, 具有三态的总线输出, 当 MR 为高电平, OE 为低电平时, 数据在 SHCP 上升沿进入移位寄存器, 在 STCP 上升沿输出到并行端口。
有关 74HC595 芯片的更多详细介绍, 大家可以在资料"\6--芯片资料\开发板芯片数据手册" 内查看。
15.2 硬件设计
本实验使用到硬件资源如下:
(1) 8*8LED 点阵模块
(2) 74HC595 模块
开发板上的 74HC595 模块电路如下图所示:


从上图中可以看出, 74HC595 需要用到的控制管脚 SER、 RCLK、 SRCLK 直接连接到 51 单片机的 P3.4-P3.6 IO 口上, 输出端则是直接连接到 LED 点阵模块的行端口上, 即为 LED 发光二极管的阳极, LED 点阵的列则为发光二极管的阴极。
要想控制 LED 点阵, 可以将单片机管脚按照 74HC595 芯片的通信时序要求来传输数据, 这样即可控制 LED 点阵的行数据。 根据 LED 发光二极管导通原理, 当阳极为高电平, 阴极为低电平则点亮, 否则熄灭。 因此通过单片机 P0 口可控制点阵列, 74HC595 可控制点阵行。
15.3 软件设计
本章所要实现的功能是: 通过 74HC595 模块控制 LED 点阵以一行循环滚动显示。
我们打开"\4--实验程序\1--基础实验\10-IO 扩展(串转并)实验-74HC595"工程, 控制代码全部都在 main.c 中, 代码如下:
cpp
/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net
PRECHIN
普中
实验名称:IO扩展(串转并)实验-74HC595
接线说明:
实验现象:下载程序后,8*8LED点阵以一行循环滚动显示
注意事项:LED点阵旁的J24黄色跳线帽短接到GND一端
***************************************************************************************/
#include "reg51.h"
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
//定义74HC595控制管脚
sbit SRCLK=P3^6; //移位寄存器时钟输入
sbit RCLK=P3^5; //存储寄存器时钟输入
sbit SER=P3^4; //串行数据输入
#define LEDDZ_COL_PORT P0 //点阵列控制端口
u8 ghc595_buf[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
/*******************************************************************************
* 函 数 名 : delay_10us
* 函数功能 : 延时函数,ten_us=1时,大约延时10us
* 输 入 : ten_us
* 输 出 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
/*******************************************************************************
* 函 数 名 : delay_ms
* 函数功能 : ms延时函数,ms=1时,大约延时1ms
* 输 入 : ten_us
* 输 出 : 无
*******************************************************************************/
void delay_ms(u16 ms)
{
u16 i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}
/*******************************************************************************
* 函 数 名 : hc595_write_data(u8 dat)
* 函数功能 : 向74HC595写入一个字节的数据
* 输 入 : dat:数据
* 输 出 : 无
*******************************************************************************/
void hc595_write_data(u8 dat)
{
u8 i=0;
for(i=0;i<8;i++)//循环8次即可将一个字节写入寄存器中
{
SER=dat>>7;//优先传输一个字节中的高位
dat<<=1;//将低位移动到高位
SRCLK=0;
delay_10us(1);
SRCLK=1;
delay_10us(1);//移位寄存器时钟上升沿将端口数据送入寄存器中
}
RCLK=1;
delay_10us(1);
RCLK=0;//存储寄存器时钟上升沿将前面写入到寄存器的数据输出
}
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
u8 i=0;
LEDDZ_COL_PORT=0x00;//将LED点阵列全部设置为0,即LED阴极为低电平
while(1)
{
for(i=0;i<8;i++)
{
hc595_write_data(0x00);//消除前面寄存器缓存数据
hc595_write_data(ghc595_buf[i]);//写入新的数据
delay_ms(500);//延时500ms
}
}
}
代码还是比较简单易懂的, 首先定义好 74HC595 控制管脚, 以及点阵列控制口, 代码中重新定义了一个 ms 级延时函数 delay_ms, 该函数与前面 delay_10us类似, 都是利用循环占用 CPU 起到延时效果。 然后又定义了 74HC595 的控制函数hc595_write_data, 该函数完全按照 74HC595 的通信时序要求编写, 主要要注意的是 74HC595 是先传输字节的高位后传输低位, 所以需要将字节低位移动到高位传输, 在传输数据时, 要注意移位寄存器时钟和存储寄存器时钟的先后顺序, 将要写入的数据先传输到 74HC595 寄存器中, 即在准备好每位数据时要将 SRCLK进行一个上升沿变化, 此时即可将数据传输到寄存器内, 待循环 8 次即一个字节传输到寄存器中时, 就可以来一个存储时钟上升沿, 此时就可以将 74HC595 寄存器中的数据全部一次传输到 595 端口输出。最后就是在 main 函数中调用 74HC595的控制函数, 将实验中要实现的效果数据写入进去, 从而控制 LED 点阵的阳极,而阴极由 P0 口控制, 默认初始化时已经设置为 0, 也就是说只要 595 输出高电平, 那么对应的行就会点亮。
15.4 实验现象
使用 USB 线将开发板和电脑连接成功后(电脑能识别开发板上 CH340 串口) ,把编译后产生的.hex 文件烧入到芯片内, 实现现象如下: 8*8LED 点阵以一行循环滚动显示。

注意: 做 LED 点阵实验时, 一定要将 LED 点阵旁的 J24 黄色跳线帽短接到 GND一端。 如下所示:
