1,第八章-LED点阵
如何驱动LED点阵:
(1)单片机端口直接驱动。要驱动8*8的点阵需要2个IO端口(16个IO口)、要驱动16*16的点阵需要4个IO端口(32个IO口)。
(2)使用串转并移位锁存器驱动。要驱动16*16点阵只需要4个74HC595+3个IO口即可(数据口、SCLK、RCLK)。
通过三个IO端口和4个74HC595级联的方式对16*16的LED点阵进行控制。
74HC595:
主要用的控制管角为,SER:串行数据输入管脚;SRCLK:数据输入时钟线;RCLK:输出存储器锁存时钟线;QA-QH:数据输出管脚;QH’:串行数据输出管脚,OE是使能管脚,低有效。
数据通过SER按bit输入,循环8次即可将一个字节写入寄存器中,每次循环需要设置一个SRCLK上升沿,当8个移位寄存器写满后,在通过SER输入的数据,会将前边写入移位寄存器的8个bit依次通过QH'输出;
设置RCLK的上升沿将前面写入移位寄存器中的数据通过输出存储器通过QA-QH输出。
以下代码为点亮16*16点阵中一个点:
(让第一个74HC595 输出0X01(0000 0001),这样点阵第一行就是高电平,而第3 个74HC595 输出0XFE(1111 1110),第4 个74HC595 输出0XFF(1111 1111),这样点阵第一列就是低电平,从而让LED 点阵第一个点点亮)
******************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net
实验名称:LED 点阵实验(点亮一个点)
接线说明:
实验现象:下载程序后,16*16LED 点阵点亮左上角第一个点
注意事项:
*********************************************************************
******************/
#include "reg52.h"
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
//定义74HC595 控制管脚
sbit SRCLK=P3^6; //移位寄存器时钟输入
sbit RCLK=P3^5; //存储寄存器时钟输入
sbit SER=P3^4; //串行数据输入
/********************************************************************
***********
* 函数名: delay_10us
* 函数功能: 延时函数,ten_us=1 时,大约延时10us
* 输入: ten_us
* 输出: 无
*********************************************************************
**********/
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
/********************************************************************
***********
* 函数名: hc595_write_data(u8 dat)
* 函数功能: 向74HC595 写入4 个字节的数据
* 输入: dat1:对应74HC595(A)输出第1 行-第8 行
dat2:对应74HC595(B)输出第9 行-第16 行
dat3:对应74HC595(C)输出第1 列-第8 列
dat4:对应74HC595(D)输出第9 列-第16 列
* 输出: 无
*********************************************************************
**********/
void hc595_write_data(u8 dat1,u8 dat2,u8 dat3,u8 dat4)
{
u8 i=0;
for(i=0;i<8;i++)//循环8 次即可将一个字节写入寄存器中
{
SER=dat4>>7;//优先传输一个字节中的高位
dat4<<=1;//将低位移动到高位
SRCLK=0;
delay_10us(1);
SRCLK=1;
delay_10us(1);//移位寄存器时钟上升沿将端口数据送入寄存器中
}
for(i=0;i<8;i++)
{
SER=dat3>>7;
dat3<<=1;
SRCLK=0;
delay_10us(1);
SRCLK=1;
delay_10us(1);
}
for(i=0;i<8;i++)
{
SER=dat2>>7;
dat2<<=1;
SRCLK=0;
delay_10us(1);
SRCLK=1;
delay_10us(1);
}
for(i=0;i<8;i++)
{
SER=dat1>>7;
dat1<<=1;
SRCLK=0;
delay_10us(1);
SRCLK=1;
delay_10us(1);
}
RCLK=0;
delay_10us(1);
RCLK=1;//存储寄存器时钟上升沿将前面写入到寄存器的数据输出
}
/********************************************************************
***********
* 函数名: main
* 函数功能: 主函数
* 输入: 无
* 输出: 无
*********************************************************************
**********/
void main()
{
u8 i=0;
while(1)
{
hc595_write_data(0x01,0x00,0xfe,0xff);//将LED 点阵上边第一行设置为
1,即LED 阳极为高电平,其余行为0,即低电平
}
}
要实现行列不同位置亮灯,需要使用动态显示的方法,也要结合扫描的方法。在第一行亮灯一段时间以后灭掉,点亮第二行一段时间以后灭掉,点亮第三行一段时间以后灭掉,如此点亮,直到八行全部点亮一次,在第一行点亮到最后一行灭掉的总时间不能超过人肉眼可识别的时间,即24 毫秒。在每一行点亮的时候,给列一个新的数据,此时对应列的数据就可以体现在这行上要点亮的灯上。这样就和动态数码管的显示一样,只不过数码管的LED 灯是段值。这里使用LED 点阵显示数字,也是多个LED 同时点亮。
要想在点阵上显示数字等字符,首先要获取在LED 点阵上显示数字字符所需的数据,即一个数字字符在LED 点阵上显示,对应的每行每列都会有一些灯点亮或者熄灭,这样就会构成一组数据,也就是数字字符的显示数据,我们只要将这些数据通过74HC595 发送到点阵对应的行或列就能显示数字字符。
数字字符可以通过取模软件获取。
LED点阵显示数字:
/********************************************************************
******************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net
实验名称:LED 点阵实验(显示数字)
接线说明:
实验现象:下载程序后,16*16LED 点阵显示数字0
注意事项:
*********************************************************************
******************/
#include "reg52.h"
#include "intrins.h"
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
//定义74HC595 控制管脚
sbit SRCLK=P3^6; //移位寄存器时钟输入
sbit RCLK=P3^5; //存储寄存器时钟输入
sbit SER=P3^4; //串行数据输入
//LED 点阵显示数字0 的列数据
u8 gled_col[32]=
{0x00,0x00,0xE0,0x03,0x10,0x04,0x08,0x08,0x04,0x10,0x04,0x10,0x04,0x10,0x04,0x10,0x04,0x10,0x04,0x10,0x04,0x10,0x04,0x10,0x08,0x08,0x10,0x04,0xE0,0x03,
0x00,0x00};
//LED 点阵显示数字0 的行数据
u8 gled_row[32]=
{0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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--);
}
/********************************************************************
***********
* 函数名: hc595_write_data(u8 dat)
* 函数功能: 向74HC595 写入4 个字节的数据
* 输入: dat1:对应74HC595(A)输出第1 行-第8 行
dat2:对应74HC595(B)输出第9 行-第16 行
dat3:对应74HC595(C)输出第1 列-第8 列
dat4:对应74HC595(D)输出第9 列-第16 列
* 输出: 无
*********************************************************************
**********/
void hc595_write_data(u8 dat1,u8 dat2,u8 dat3,u8 dat4)
{
u8 i=0;
for(i=0;i<8;i++)//循环8 次即可将一个字节写入寄存器中
{
SER=dat4>>7;//优先传输一个字节中的高位
dat4<<=1;//将低位移动到高位
SRCLK=0;
// delay_10us(1);
_nop_();
SRCLK=1;
_nop_();
// delay_10us(1);//移位寄存器时钟上升沿将端口数据送入寄存器中
}
for(i=0;i<8;i++)
{
SER=dat3>>7;
dat3<<=1;
SRCLK=0;
// delay_10us(1);
_nop_();
SRCLK=1;
_nop_();
// delay_10us(1);//移位寄存器时钟上升沿将端口数据送入寄存器中
}
for(i=0;i<8;i++)
{
SER=dat2>>7;
dat2<<=1;
SRCLK=0;
// delay_10us(1);
_nop_();
SRCLK=1;
_nop_();
// delay_10us(1);//移位寄存器时钟上升沿将端口数据送入寄存器中
}
for(i=0;i<8;i++)
{
SER=dat1>>7;
dat1<<=1;
SRCLK=0;
// delay_10us(1);
_nop_();
SRCLK=1;
_nop_();
// delay_10us(1);//移位寄存器时钟上升沿将端口数据送入寄存器中
}
RCLK=0;
delay_10us(1);
RCLK=1;//存储寄存器时钟上升沿将前面写入到寄存器的数据输出
}
/********************************************************************
***********
* 函数名: main
* 函数功能: 主函数
* 输入: 无
* 输出: 无
*********************************************************************
**********/
void main()
{
u8 i=0;
while(1)
{
for(i=0;i<16;i++)//循环16 次扫描16 行、列
{
hc595_write_data(gled_row[i],gled_row[i+16],~gled_col[i*2],~gled_
col[i*2+1]);//传送行列选数据
delay_10us(10);//延时一段时间,等待显示稳定
hc595_write_data(0x00,0x00,0x00,0x00);//消影
}
}
}