我们在之前的学习中,都是通过IO口直接控制板子上的外围器件:LED、数码管等。如果想要连接更多的外围设备,就需要通过扩展IO来实现。(74HC595芯片)
目录
I O扩展原理:
SER、SRCLK、RCLK这3个IO输入口对应控制右侧8个输出端口(DPa--DPh).第九个QH’是串行输出端口。注意:这个QH’串行输出对应着左侧的SER串行输入端口,是74HC595芯片IO扩展的关键所在。这个串行输出端口会连接下一个74HC595芯片的串行输入端口(SER),这样又可以扩展8个输出端口。依次连接下去,就会拓展很多的输出端口。
74HC595芯片:
74HC595 是一个 8 位串行输入、并行输出的位移缓存器,其中并行输出为三态输出(即高电平、低电平和高阻抗)。
OE: 打开使能 带上横线的意思:输入低电平这个芯片才能工作
所以要保证用跳线帽将OE(第二个)和地(第三个)短接。
SER(P34):串行数据输入管脚
数据从SER口排着队依次进入。
SRCLK(P36):移位寄存器的时钟输入
数据从SER口排着队等待进入,这个管脚打开数据往里走一点,打开数据往里走一点,打开数据往里走一点........给高电平一下,输入一个位(bit) ;给高电平一下,输入一个位(bit)。
RCLK(P35):存储计时器时钟的输入引脚
把刚才输入的8位数据,给存储起来。使用:给高电平一下,把移位寄存器中的8位数据一次性转存到存储时钟当中。
下面就要编写74HC595的写数据的程序
根据上面描述,先用for循环把数据暂存到8位移位寄存器当中,然后把移位寄存器中的8位数据一次性转存到存储时钟当中即可。
程序:
/******************定义74HC595管脚************************/
sbit rclk=P3^5;
sbit SRCLK=P3^6;
sbit SER=P3^4;
void HC595_write(uchar dat)//74HC595芯片的写数据
{
uchar i;
for(i=0;i<8;i++)//先把数据暂存到8位移位寄存器当中
{
SER=dat>>7;//把最高位的数值赋给SER串行输入端口
dat<<=1;//把dat数据的次高位移至最高位
SRCLK=0;
Delay10us();//进行一个微小的延时
SRCLK=1;//对高低电平进行转换,每置一次高电平,数据就往里传输一位。
Delay10us();
}
//把移位寄存器中的8位数据一次性转存到存储时钟当中
rclk=0;
Delay10us();//进行一个微小的延时
rclk=1;//置为高电平才开始工作
}
LED 8*8点阵
在51单片机上,我们通过74HC595来扩展了一个LED8*8点阵,在使用点阵的时候,要保证OE(第二个)跳线帽和地(第三个)短接。
点阵中,每一行引出的是放光二极管的阳极,在高电平下点亮。
例如DPh置为高电平,第一行就被点亮。
每一列引出的是放光二极管的阴极,由P0口控制,在低电平下点亮。
1.静态点亮(静态数码管)
程序:点亮8*8点阵的左上角的灯
让第一列置0,第一行置1即可。
/**********************点亮左上角第一个点*****************/
/*
#include <reg52.h>
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
/******************对LED灯进行定义*********************
sbit LED1=P2^0;
sbit LED2=P2^1;
/******************定义38译码器的输入管脚*******************
sbit LSA=P2^2; //对单个管脚进行定义用sbit
sbit LSB=P2^3;
sbit LSC=P2^4;
//#define SMG_duanxuan P0//对整个P0端口进行定义 用宏定义
//是对整个段选端口进行定义
/******************定义74HC595管脚************************
sbit rclk=P3^5;
sbit SRCLK=P3^6;
sbit SER=P3^4;
#define LEDdz_lie P0//LED点阵的列都定义在P0端口处
uchar LEDdz_hang[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
//LED点阵从最下面一行依次到最上面一行点亮
void Delayms(uint ms);//1毫秒延时
void Delay10us(); //@11.0592MHz
void HC595_write(uchar dat);
void LED_DZ_work();
void main()
{
while(1)
{
LED_DZ_work();
}
}
void LED_DZ_work()
{
LEDdz_lie=0X7F;//让列输出低电平才能点亮。
HC595_write(0X80);//把行显示的数据传给74HC595芯片
}
void HC595_write(uchar dat)//74HC595芯片的写数据
{
uchar i;
for(i=0;i<8;i++)//先把数据暂存到8位移位寄存器当中
{
SER=dat>>7;//把最高位的数值赋给SER串行输入端口
dat<<=1;//把dat数据的次高位移至最高位
SRCLK=0;
Delay10us();//进行一个微小的延时
SRCLK=1;//对高低电平进行转换,每置一次高电平,数据就往里传输一位。
Delay10us();
}
//把移位寄存器中的8位数据一次性转存到存储时钟当中
rclk=0;
Delay10us();//进行一个微小的延时
rclk=1;//置为高电平才开始工作
}
void Delayms(uint ms)//1毫秒延时
{
uint i,j;
for(i=ms;i>0;i--)
for(j=114;j>0;j--);
}
void Delay10us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 25;
while (--i);
}
2.动态显示(动态数码管)
其原理类似于动态数码管的显示,从第一列开始逐列进行扫描,这一行如果显示就把要显示的灯置高电平。
这里我们用到一个文字取模工具,新建一个8*8的图像之后,可以在模拟动画里面放大图像。用鼠标建立自己想显示的图像。然后点击参数设置,将字节倒序选项取消选中,取模方式选择纵向取模,其余选项默认,点击确定。之后点击取模方式,选择C51格式,就可得到每一列的行方向上的数据。
例如:取模数字0、
第一列的每一行都不需要显示,所以全部置为低电平,第二列中需要显示的那一行置为高电平即可。
0x00,0x7C,0x82,0x82,0x82,0x7C,0x00,0x00,
/***************************显示数字图像*******************/
/*
#include <reg52.h>
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
/******************对LED灯进行定义*********************
sbit LED1=P2^0;
sbit LED2=P2^1;
/******************定义38译码器的输入管脚*******************
sbit LSA=P2^2; //对单个管脚进行定义用sbit
sbit LSB=P2^3;
sbit LSC=P2^4;
//#define SMG_duanxuan P0//对整个P0端口进行定义 用宏定义
//是对整个段选端口进行定义
/******************定义74HC595管脚************************
sbit rclk=P3^5;
sbit SRCLK=P3^6;
sbit SER=P3^4;
#define LEDDZ_lie P0//LED点阵的列都定义在P0端口处
uchar LEDdz_hang[]={0x00,0x7C,0x82,0x82,0x82,0x7C,0x00,0x00};
//LED点阵显示数字0 通过文字取模软件获取
uchar LEDdz_lie[]={0X7F,0XBF,0XDF,0XEF,0XF7,0XFB,0XFD,0XFE};
//LED点阵逐列扫描
void Delayms(uint ms);//1毫秒延时
void Delay10us(); //@11.0592MHz
void HC595_write(uchar dat);
void LED_DZ_work();
void main()
{
while(1)
{
LED_DZ_work();
}
}
void LED_DZ_work()
{
uchar i=0;
for(i=0;i<8;i++)
{
LEDDZ_lie=LEDdz_lie[i];//让列输出低电平才能点亮
//逐列扫描,让每一列都点亮
HC595_write(LEDdz_hang[i]);//把行显示的数据传给74HC595芯片
HC595_write(0X00);//消隐
}
}
void HC595_write(uchar dat)//74HC595芯片的写数据
{
uchar i;
for(i=0;i<8;i++)//先把数据暂存到8位移位寄存器当中
{
SER=dat>>7;//把最高位的数值赋给SER串行输入端口
dat<<=1;//把dat数据的次高位移至最高位
SRCLK=0;
Delay10us();//进行一个微小的延时
SRCLK=1;//对高低电平进行转换,每置一次高电平,数据就往里传输一位。
Delay10us();
}
//把移位寄存器中的8位数据一次性转存到存储时钟当中
rclk=0;
Delay10us();//进行一个微小的延时
rclk=1;//置为高电平才开始工作
}
void Delayms(uint ms)//1毫秒延时
{
uint i,j;
for(i=ms;i>0;i--)
for(j=114;j>0;j--);
}
void Delay10us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 25;
while (--i);
}
文字取模软件链接:
链接:https://pan.baidu.com/s/1uzVLQSOg3LqM7g7yVxT-qA?pwd=x6la
提取码:x6la