目录
1.LED点阵屏简介
LED点阵屏真的是遍布我们我们生活的每个角落,从街边的流动显示字的招牌到你的液晶显示屏,都是基于点阵屏的原理研究出来的。还有那个世界上最大的球状建筑物:MSG Sphere,也是基于LED点阵的原理实现的:
把单色的LED换成彩色的RGB,实现幻彩般的视觉观感,这也是科技的魅力吧。
我们单片机上的就是比较简单的一种点阵屏,它不仅仅是一些LED,我们需要了解的更多应该是怎么实现使用更少的IO口控制这个LED点阵屏。
我们开发板上的LED点阵屏一共有16个,我们使用这些点阵屏可以制作很多有意思的东西。比如网上很火的坤坤跳舞(doge)和贪吃蛇小游戏,这里我们就来了解一下它到底是使用什么方式实现的吧。
首先LED点阵屏和数码管还有矩阵键盘都有异曲同工之处,使用循环行列式扫描实现图像显示,然后是使用共阴共阳连接减少IO口占用。至于行列扫描,我们应该都比较熟悉了,还是一样的,这里主要介绍一下IO口的占用。
如果说,数码管的显示数据减少IO口的方式是使用74HC138芯片实现位选,74HC245芯片实现数选,这里我们对LED点阵屏的使用也要有相应的芯片达到减少IO占用的结果,而这里我们使用的是74HC595芯片来减少IO占用。
74HC595是串行输入并行输出的移位寄存器,可用3根线输入串行数据,8根线输出并行数据,多片级联后,可输出16位、24位、32位等,常用于IO口扩展。
具体功能的实现像一个队列,只不过换了一种形式:
这个是大概的实现原理的流程图:我们使用从SRC端口接入数据,当上升沿移位寄存器从0变成1的时候,从SER的数据就再进入一个,把前面得到的数据往下移1位,SERCLK变回0。当上升沿锁存寄存器RCLK置为1的时候,在整个寄存器中的数据就会全部移到和输出端相连的输出缓存处,直接输出数据,从而实现全部数据同时输出的作用。
当当前的数据储存存满了之后,我们可以使用片级联的方法,使得再进入数据可以继续储存数据,从而实现16位32位甚至更多。
像这样,离总输出端最近的部分再次输入数据,数据就会通过最下方传输到下一个级联的SER,为下一个级联的部分输入数据。等到上升沿锁存置为1的时候,所有的芯片都会向IO口输出数据,从而实现更多位的LED输出。
2.配置LED点阵屏代码
这里配置一下LED点阵屏的代码
这里可以看到我们需要配置三个引脚,RCLK,SRCLK,SER。
我们可以把这几个引脚使用sbit重新命名一下。
这里说明一下,类似引脚这样的重命名是使用sbit和sfr两种
针对P0,P1,P2等这样的寄存器重新命名使用sfr,比如我们可以把使用LED时把P2命名成LED,即sfr LED = P2;
这样我们就可以直接对我们取的名字直接操纵,比如LED = 0xf0;
sbit针对的是一个寄存器中更加精确的位,例如P2^2,我们使用sbit LED = P2^2;就定义了单位,如果我们不重新命名,我们就要使用P2^2就只能使用P2_2 = 0;这样才可以使用,因为在头文件中定义的只有P2_2这样的形式,P2^2这样的定义意思其实就是P2寄存器中第二位的意思,这样才找到的这个位。
这里我们使用sbit重新定义这几个引脚,目的是增加代码可读性
这里我们不能直接定义P3^5为RCLK,在头文件的184行有一个定义过的RCLK,所以我们就要使用别的名字,只要知道谁是谁就好了。
cpp
sbit RCK = P3^5;
sbit SRCLK = P3^6;
sbit SER = P3^4;
现在开始编写函数实现输入一个8位二级制数据,使用74HC595芯片把内容写入。首先我们要知道的是,我们是使用一位一位的把数据输入到芯片SER引脚,每次需要把一位数据输入到芯片里面,我们的SERCLK就要置为高电平,然后数据才会移位,我们再把SERCLK置为0.。循环这个过程,直到我们的数据全部都进入,这个时候我们就要使用上升沿锁存RCLK置为高电平,把数据输出到缓存区。
cpp
void Write74HC595(unsigned char byte)
{
unsigned char i = 0;
for(i = 0;i<8;i++)
{
SER = byte&(0x80>>i);
SRCLK = 1;
SRCLK = 0;
}
RCK = 1;
RCK = 0;
}
这样我们调用函数,我们就可以把数据输出了。但是我们要实现点阵屏亮,还要实现一点东西:
根据原理图我们可以知道:我们74HC595芯片输出的是LED点阵的一列A1-A8的阳极,我们还需要在K1-K8输入低电平才可以让LED点阵亮起来。
假设我想要让一个对角线亮起来,我们就要使用循环控制行和列来实现,就好像我们的数码管的数选和位选,我们就要使用循环的形式达成。
这里我们再实现一个函数,让我们可以通过输入列的数和输入芯片的数据,然后输出一列的对应的LED
cpp
void MartixLEDShow(unsigned char col,unsigned char byte)
{
SRCLK = 0;
RCK = 0;
Write74HC595(byte);
P0 = ~(0x80>>(col-1));
}
然后我们调用函数:
cpp
void main()
{
while(1)
{
MartixLEDShow(1,0x80);
MartixLEDShow(2,0x40);
MartixLEDShow(3,0x20);
MartixLEDShow(4,0x10);
MartixLEDShow(5,0x08);
MartixLEDShow(6,0x04);
MartixLEDShow(7,0x02);
MartixLEDShow(8,0x01);
}
}
然后到了这里如果LED点阵还没亮,不要慌,把LED点阵旁边的跳线帽J24拔下来,插到另外两个针头上就可以了
这样我们就可以在我们的LED上显示一个对角线的灯光了,但是我们还有一点问题,就是我们会发现:我们的LED点阵屏上有一些本来不该亮的地方亮了,其实就和前面讲过的数码管一样的原理,就是位选+数选的叠加导致上一个数选和下一个位选结合或者上一个数选和下一个位选结合然后导致显示的错误,所以我们就要做一件事:消隐。保证消除上一次的位选或者数选。
同时,消隐会道义一点问题:就是我们的这个亮度会变暗,所以我们就要消隐前使用Delay函数把这个LED亮的时长增加,就可以实现正常亮度了。
更改之后的函数如下:
cpp
void MartixLEDShow(unsigned char col,unsigned char byte)
{
SRCLK = 0;
RCK = 0;
Write74HC595(byte);
P0 = ~(0x80>>(col-1));
Delay(1);
P0 = 0Xff;//消隐
}
这样就实现了一个对角线的LED点阵亮。
实现一个对角线还是比较简单的,这里我们再实现一个笑脸:
这里实现这个笑脸,红色部分是需要点亮的地方,我们要把每一列的数据都记录在一个数组里面:
cpp
unsigned char Image[] = {0x3c,0x42,0xa9,0x85,0x85,0xa9,0x42,0x3c};
对了,这里可以在数组名字前面加上51的关键字:code,这样我们就可以把数组的内容存储在单片机的flash缓存中了,我们也就可以写入更多的数据了:
cpp
unsigned char code Image[] = {0x3c,0x42,0xa9,0x85,0x85,0xa9,0x42,0x3c};
然后再在main函数里调用函数就可以实现一个笑脸了:
cpp
void main()
{
while(1)
{
unsigned char i = 0;
for(i=0;i<8;i++)
{
MartixLEDShow(i+1,Image[i]);
}
}
}
这里再封装一个函数,我们输入数组的名字+长度就可以实现调用了:
cpp
void ImageShow(unsigned char*Image,unsigned int len)
{
unsigned char i = 0;
for(i=0;i<len;i++)
{
MartixLEDShow(i+1,Image[i]);
}
}
void main()
{
while(1)
{
ImageShow(Image,8);
}
}
对了,这里可以使用一个软件,也是买板子的时候给的:
这个是取模软件,我们可以自行生成想要图案,但是这个生成文字的功能需要16*16以上的点阵,这里就只使用8*8的功能:
选择新建一个8*8的图像
放大,以便操作
点击格点画图
点击生成之后复制代码到自己的数组中使用即可。
当然,还想要实现什么都可以靠自己实现。