目录
[1.1 回顾](#1.1 回顾)
[1.2 概述](#1.2 概述)
[1.3 工作原理](#1.3 工作原理)
[1.4 硬件设计](#1.4 硬件设计)
[1.5 实验设计](#1.5 实验设计)
[2. LED点阵](#2. LED点阵)
[2.1 概述](#2.1 概述)
[2.2 软件设计](#2.2 软件设计)
[2.2.1 点亮一个灯](#2.2.1 点亮一个灯)
[2.2.2 显示一个数字](#2.2.2 显示一个数字)
1.74HC595
1.1 回顾
前面动态数码管实验中提到 74HC138 拓展单片机 IO ,回顾:
"2个四位一体的数码管位选线有8根,但单片机IO资源有限
通常使用一种IO扩展芯片 ,如 74HC138,74HC164,74HC595
只需要用很少的单片机IO口就可扩展出8个控制口,通过级联方式甚至可以拓展更多IO口"
本篇介绍另外一种 IO口 拓展方式------串转并,使用的芯片是74HC595 芯片
1.2 概述
开发板板载一个 74HC595芯片,仅单片机3个IO口即可拓展8个IO口
如果需要还可以将2个74HC595级联拓展出16个IO,即可实现用少数 IO 口资源控制多个设备
74HC595是一个 8位 串行输入,并行输出的位移缓存器
并行输出为三态输出(高电平、低电平、高阻扛)
1.3 工作原理
下图左边均是芯片管脚图,但管脚命名不同,重在关注管脚功能即可


74HC595 具有一个八位移位寄存器、存储寄存器。移位寄存器和存储寄存器是单独的时钟。数据通过 14脚 上升沿输入,当 MR 为高电平、OE为低电平时,数据在 11脚 的上升沿(高电平)进入到 移位寄存器,再通过 12脚 的上升沿(高电平)移动到 存储寄存器,若需要级联,则通过 9脚 串行输出,14 脚 串行数据输入即可;否则直接通过 15和1-7脚 并行数据输出到外围设备即可;
1.4 硬件设计
下图,中间是 74HC595 芯片,右端为 LED 点阵
OE :**LED 点阵的 "驱动总开关"。**低电平允许芯片驱动点阵显示,高电平切断驱动以关闭显示或隔离信号
图中左侧标注为"J24",典型的跳线接口。黄色跳线帽连接1、2脚,OE引脚被拉低(低电平状态),黄色跳线帽连接2、3引脚,OE引脚被拉高(高电平状态);若不插跳线帽,OE 引脚悬空,可能导致输出不稳定
从图中可以看到,74HC595 需要用到的控制管脚连接单片机的 P34-P36 IO口,输出端连接LED点阵模块的行端口上,即为 LED发光二极管的阳极,单片机 P0口 控制点阵列
此外,数据是一位一位的传输到八位的移位寄存器,且从数据最高位开始移入,移位寄存器满八位之后,再一次性传输到存储寄存器
如 1001 0001 ,先将最高位 1 存入移位寄存器,再将 0 存入移位寄存器,如此类推,一直到最低位 1 也存入移位寄存器,移位寄存器满了之后,将数据一次性传输到存储寄存器。且最高位 1 对应 Dph,即 点阵屏第一行,次高位 0 对应 Dpg,即点阵屏第二行,如此类推

1.5 实验设计
通过74HC595控制LED点阵以行滚动方式循环显示
cpp
//74HC595 控制 LED点阵逐行点亮
#include <at89c51RC2.h>
#include <intrins.h>
//简化类型名
typedef unsigned char u8;
typedef unsigned int u16;
//定义 74HC595 关键引脚
sbit SER = P3^4; //串行数据输入
sbit RCLK_595 = P3^5; //存储寄存器输入:头文件中已经预定义了 RCLK
sbit SRCLK = P3^6; //移位寄存器输入
//74HC595 串行输入数据
u8 hc595[] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
/*延时函数:74HC595 对时钟信号的上升/下降沿有最小时间要求
如果时钟翻转太快,芯片来不及采样数据,会导致输出错误。*/
void Delay10us(u16 ms) //@11.0592MHz
{
unsigned char data i;
while(ms--)
{
i = 2;
while (--i);
}
}
//串行数据输入--->并行数据输出
void hc595_write(u8 date)//date即要写入的字节数据
{
u8 i = 0;
for(i=0;i<8;i++)//1字节=8位,逐位传输8次
{
SER = date>>7;//先把最高位传输到SER引脚
date <<= 1; //下一位左移(去掉最高位,末位补0)到最高位
//产生移位时钟脉冲
SRCLK = 0; //时钟拉低
Delay10us(1);//稳定低电平(10us)
SRCLK = 1; //时钟拉高,上升沿触发,将 SER 数据传输到移位寄存器
Delay10us(1);//稳定高电平
}
//产生存储时钟脉冲,触发数据输出
RCLK_595 = 0; //时钟拉低
Delay10us(1); //稳定低电平(10us)
RCLK_595 = 1; //时钟拉高,上升沿触发,将移位寄存器数据传输到存储寄存器
Delay10us(1); ////稳定高电平
//之后,74HC595的 QA-QH 并行输出传入的8位数据,驱动LED点阵
}
void main()
{
u8 i = 0;
while(1)
{
//LED点阵阴极为低电平
P0 = 0x00;
for(i=0;i<8;i++)
{
hc595_write(0x00); //消影:"清空旧数据",避免LED余晖和视觉暂留导致的重影
hc595_write(hc595[i]); //输入串行数据
Delay10us(20000);
//延时作用:保持当前 LED 的点亮状态,但解决不了"切换瞬间的新旧数据叠加"
}
}
}
2. LED点阵
2.1 概述
LED点阵 是由发光二极管排列组成的显示器件,被广泛应用于汽车报站器、广告屏等
2.2 软件设计
2.2.1 点亮一个灯
要求:点亮 LED点阵 第一行第一列的灯

cpp
//点亮LED点阵一个灯
#include <at89c51RC2.h>
#include <intrins.h>
//简化类型名
typedef unsigned char u8;
typedef unsigned int u16;
//定义 74HC595 关键引脚
sbit SER = P3^4; //串行数据输入
sbit RCLK_595 = P3^5; //存储寄存器输入:头文件中已经预定义了 RCLK
sbit SRCLK = P3^6; //移位寄存器输入
/*延时函数:74HC595 对时钟信号的上升/下降沿有最小时间要求
如果时钟翻转太快,芯片来不及采样数据,会导致输出错误。*/
void Delay10us(u16 ms) //@11.0592MHz
{
unsigned char data i;
while(ms--)
{
i = 2;
while (--i);
}
}
//串行数据输入--->并行数据输出
void hc595_write(u8 date)//date即要写入的字节数据
{
u8 i = 0;
for(i=0;i<8;i++)//1字节=8位,逐位传输8次
{
SER = date>>7;//先把最高位传输到SER引脚
date <<= 1; //下一位左移(去掉最高位,末位补0)到最高位
//产生移位时钟脉冲
SRCLK = 0; //时钟拉低
Delay10us(1);//稳定低电平(10us)
SRCLK = 1; //时钟拉高,上升沿触发,将 SER 数据传输到移位寄存器
Delay10us(1);//稳定高电平
}
//产生存储时钟脉冲,触发数据输出
RCLK_595 = 0; //时钟拉低
Delay10us(1); //稳定低电平(10us)
RCLK_595 = 1; //时钟拉高,上升沿触发,将移位寄存器数据传输到存储寄存器
Delay10us(1); ////稳定高电平
//之后,74HC595的 QA-QH 并行输出传入的8位数据,驱动LED点阵
}
void main()
{
while(1)
{
//LED点阵阴极为低电平
P0 = 0x7f;
//输入行数据
hc595_write(0x80);
}
}
2.2.2 显示一个数字
要求:显示一个数字 0
想要在 LED点阵 上显示一个数字,需要知道哪些灯是熄灭的,哪些灯是点亮的,也就是需要获取对应的显示数据,将数字字符对应的显示数据通过 74HC595 发送到点阵的行或列就能显示数字字符
取字模软件可以方便地获取显示数据




显示图像各行对应的数据:0x00,0x00,0x3C,0x42,0x42,0x3C,0x00,0x00
第一、二列:没有灯需要点亮 ,所以行对应数据:0x00,0x00
第三列;第 3.4.5.6 行需要点亮,所以行对应数据:0011 1100: 0x3C
如此类推

实验代码与前面点亮一个灯的核心代码是一样的,重点要理解动态扫描


动态扫描:首先设置最左边第一列(P0^7)有效,即低电平,其余列为高电平,然后通过74HC595输出该列对应的行数据,延时一段时间等待显示稳定,最后清除列对应的行数据,即消影
cpp
//LED点阵显示数字
#include <at89c51RC2.h>
#include <intrins.h>
//简化类型名
typedef unsigned char u8;
typedef unsigned int u16;
//定义 74HC595 关键引脚
sbit SER = P3^4; //串行数据输入
sbit RCLK_595 = P3^5; //存储寄存器输入:头文件中已经预定义了 RCLK
sbit SRCLK = P3^6; //移位寄存器输入
// 共阴点阵适配:字模用原数组(高电平有效)
u8 led_row[] = {0x00,0x00,0x3C,0x42,0x42,0x3C,0x00,0x00}; //LED点阵显示数字0的行数据
u8 led_col[] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe}; //LED点阵显示数字0的列数据
/*延时函数:74HC595 对时钟信号的上升/下降沿有最小时间要求
如果时钟翻转太快,芯片来不及采样数据,会导致输出错误。*/
void Delay10us(u16 ms) //@11.0592MHz
{
unsigned char data i;
while(ms--)
{
i = 2;
while (--i);
}
}
//串行数据输入--->并行数据输出
void hc595_write(u8 date)//date即要写入的字节数据
{
u8 i = 0;
for(i=0;i<8;i++)//1字节=8位,逐位传输8次
{
SER = date>>7;//先把最高位传输到SER引脚
date <<= 1; //下一位左移(去掉最高位,末位补0)到最高位
//产生移位时钟脉冲
SRCLK = 0; //时钟拉低
Delay10us(1);//稳定低电平(10us)
SRCLK = 1; //时钟拉高,上升沿触发,将 SER 数据传输到移位寄存器
Delay10us(1);//稳定高电平
}
//产生存储时钟脉冲,触发数据输出
RCLK_595 = 0; //时钟拉低
Delay10us(1); //稳定低电平(10us)
RCLK_595 = 1; //时钟拉高,上升沿触发,将移位寄存器数据传输到存储寄存器
Delay10us(1); ////稳定高电平
//之后,74HC595的 QA-QH 并行输出传入的8位数据,驱动LED点阵
}
void main()
{
u8 i=0;
while(1)
{
for(i=0;i<8;i++)
{
P0 = led_col[i]; // 传送列数据
hc595_write(led_row[i]);// 传送行数据
Delay10us(40); // 延时一段时间,等待显示稳定
hc595_write(0x00); // 消影
}
}
}
