IO 扩展(串转并)-74HC595
前面接的一些输入输出设备都是直接连接的单片机 IO 口,单片机仅有的 IO 口非常有限。而使用 IO 扩展可以大量增加可使用的端口。比如后面要使用的 LED 点阵,8*8个格子,使用扩展 IO 输入就更为合适。如果多级联一个,就又有了8位输出,能实现16*16的点阵。
74HC595 是一个位移缓存器,有8位串行输入、并行输出,并行输出是三态输出(高电平、低电平、高阻抗)。比如一次输入一个比特,输入八次,并行输出可以输出一个8位的字 1010 1010.
点亮 LED 点阵
注意事项:LED 点阵旁的 J24 黄色跳线帽短接到 GND 一端!
注意事项:LED 点阵旁的 J24 黄色跳线帽短接到 GND 一端!
注意事项:LED 点阵旁的 J24 黄色跳线帽短接到 GND 一端!
传入数据如列是0100 0000,行是0000 0001,则代表最后一行第二列的点会被点亮。
SRCLK:移位寄存器,数据先传输到移位寄存器中。移位寄存器上升沿时移位,再接收下一次数据。
RCLK:存储寄存器。存储寄存器上升沿时把寄存器中所有数据都通过端口输出。
#include "reg52.h"
//编写程序先定义管脚和端口。管脚用sbit,端口宏定义
#define LED_MATRIX P0
sbit SRCLK=P3^6;
//因为 RCLK 是关键字不能被复用了
sbit rCLK=P3^5;
sbit SER=P3^4;
unsigned char hc_led_arr[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
void delay(int i){while(i--);}
void hc_write_data(unsigned char c){
//要传入8个输入,需要循环
int i=0;
for(i;i<8;i++){
//注意 芯片传数据先传高位 再传低位,所以要反着写。这个问题在write函数内部解决,传入的数据和想要的形式一样就好。
//通过移位获取
SER=c>>7;
//想获取下一位寄存器,需要移位寄存器移位。需要创造上升沿
SRCLK=0;
//芯片一般给定一个延时时间,经过这个时间之后才能处理完毕
delay(1);
SRCLK=1;
delay(1);
//让传入数据的次高位变为下次循环的高位
c<<=1;
}
//最后通过存储寄存器的上升沿,传输全部数据
rCLK=0;
delay(1);
rCLK=1;
}
void main(){
LED_MATRIX=0x00;
while(1){
int i=0;
for(i;i<8;i++){
hc_write_data(0x00);//消隐
hc_write_data(hc_led_arr[i]);
delay(500000);
}
}
}
比如0000 0001,传入LED阵列的数据是:每轮循环传入最高位的值,并且所有数据向左移动一位。因此前7轮 SER 传入都是0,最后一轮 SER 传入1,最下面一行全亮。
LED 点阵实验
上面的方法只能确定某一具体的行被点亮。可不可以具体确定哪些点点亮的方法?
我们让想被点亮的点列为低电平,行为高电平,就会被点亮。如果我们只想点亮第一行第一列的点,只需行脚只有第一行接高电平,列脚只有第一列接低电平即可。
所以只要先让第一列为低电平,其他列为高天平来只读取第一列,遍历所有行检查第一列哪些点应该被点亮;然后第二列,第三列……一次类推,每轮循环不用消除上次的结果即可。
#include "reg52.h"
//编写程序先定义管脚和端口。管脚用sbit,端口宏定义
#define LED_MATRIX P0
sbit SRCLK=P3^6;
sbit rCLK=P3^5;
sbit SER=P3^4;
unsigned char hc_led_arr[8]={0x38,0x7C,0x7E,0x3F,0x3F,0x7E,0x7C,0x38};
unsigned char col[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
void delay(int i){while(i--);}
void hc_write_data(unsigned char c){
//要传入8个输入,需要循环
int i=0;
for(i;i<8;i++){
//注意 芯片传数据先传高位 再传低位,所以要反着写
//通过移位获取
SER=c>>7;
//想获取下一位寄存器,需要移位寄存器移位。需要创造上升沿
SRCLK=0;
//芯片一般给定一个延时时间,经过这个时间之后才能处理完毕
delay(1);
SRCLK=1;
delay(1);
//让传入数据的次高位变为下次循环的高位
c<<=1;
}
//最后通过存储寄存器的上升沿,传输全部数据
rCLK=0;
delay(1);
rCLK=1;
}
void main(){
LED_MATRIX=0x00;
while(1){
int i=0;
for(i;i<8;i++){
LED_MATRIX=col[i];
hc_write_data(hc_led_arr[i]);
//不知道为什么,下面两部分不写图形会偏移。不知道会不会有大佬解答一下
delay(100);
hc_write_data(0x00);
}
}
}
点阵的具体图案生成方法:字模提取软件。