点阵LED显示屏是很常见的并被广泛使用的模块,本文学习点阵的使用和基础知识的学习
点阵就是矩阵状的LED,对他的使用和上一章数码管类似
左侧的 8 个引脚是接的内部 LED 的阳极,上侧的 8 个引脚接的是内部 LED 的阴极
要想点亮LED小灯就需要左侧高电平,上侧为低电平,例如将引脚5置高电平,引脚16置低电平,这点亮了最右下角的LED小灯
接着是怎么控制点阵呢?
我们还是用上我们常用的74HC138应用电路(三八译码器)
观察点阵左侧都连在三极管他们都是用LEDC0~LEDC7控制,而这些都是由74HC138中的U4控制,而U4怎么开启呢?那就是ENLED = 0;ADDR3 = 0;(可通过原理图的得知,U3的ENLED需要低电平ADDR3需要高电平才能开启,U4则是ENLED和ADDR3都为低电平才能开启)
这样开启的就是U4不是U3,而上侧自然是由74HC245电路驱动,看过我前面的文章的朋友应该知道,DB0~DB7对应在单片机就是P0.0~P0.7,操作方法还是控制P0即可
点亮点阵的一个LED
#include<reg52.h>
sbit LED = P0^7; //特殊位声明LED与IO口P0.7联系
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
void main()
{
ENLED = 0;
ADDR3 = 0; //使能U4
ADDR2 = 1;
ADDR1 = 1;
ADDR0 = 1; //经U4的Y7输出开启三极管Q21
LED = 0;
while(1);
}
二、开启点阵
1.开启点阵第一排的LED
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
void main()
{
ENLED = 0;
ADDR3 = 0; //开启U4
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 0; //经U4的Y1输出开启三级管Q11
P0 = 0x00; //向P0的所有IO口写入0
while(1);
}
2.点亮点阵所有LED
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
void main()
{
EA = 1;
ENLED = 0;
ADDR3 = 0; //开启U4
TMOD = 0x01; //开启定时器模式1
TH0 = 0xFC;
TL0 = 0x67; //定时1ms
ET0 = 1; //使能T0中断
TR0 = 1; //启动T0
while(1);
}
void InterruptTimer0() interrupt 1
{
static unsigned char i = 0;
TH0 = 0xFC;
TL0 = 0x67;
P0 =0xFF; //显示消隐
switch(i)
{
case 0: ADDR2=0;ADDR1=0;ADDR0=0;i++;P0=0x00;break;
case 1: ADDR2=0;ADDR1=0;ADDR0=1;i++;P0=0x00;break;
case 2: ADDR2=0;ADDR1=1;ADDR0=0;i++;P0=0x00;break;
case 3: ADDR2=0;ADDR1=1;ADDR0=1;i++;P0=0x00;break;
case 4: ADDR2=1;ADDR1=0;ADDR0=0;i++;P0=0x00;break;
case 5: ADDR2=1;ADDR1=0;ADDR0=1;i++;P0=0x00;break;
case 6: ADDR2=1;ADDR1=1;ADDR0=0;i++;P0=0x00;break;
case 7: ADDR2=1;ADDR1=1;ADDR0=1;i=0;P0=0x00;break;
default:break;
} //动态刷新三八译码器的八个输出口
}
三、用点阵显示图像
点阵的图像显示,按照课本和金沙滩的推荐可以使用取模软件,取模软件不会使用可以看课本也可以在b站看金沙滩的网课,视频比口头讲述更易懂
我们就分析这个爱心,取模软件可以大大提高我们写代码的速度,如果无法使用取模软件,我们就应该了解原理,口头计算也行
首先我们知道我们使用的是8x8的点阵屏总共有64个小LED
按照前面我们对点阵硬件部分的认识开启每一行的核心是三八译码器的输出,每一列的开启和P0这个IO口的控制有关,但我们全设为低电平也无妨(即P0 = 0x00),这样点亮LED的唯一因素就是U4三八译码器的配置了
我们知道让点阵显图案的原因就是点阵的动态刷新,和上一章动态刷新数码管同理,我们只需要将三八译码器的控制的图案的二进制代码封装在函数即可,原理和上一章类似
那我们开始认识分析代码吧
点阵显示爱心
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
unsigned char code image[]={
0xFF,0x99,0x00,0x00,0x00,0x81,0xC3,0xE7
}; //封装的函数保存图像
void main()
{
EA = 1;
ENLED = 0;
ADDR3 = 0;
TMOD = 0x01;
TH0 = 0xFC;
TL0 = 0x67;
ET0 = 1;
TR0 = 1;
while(1);
}
void InterruptTimer0() interrupt 1
{
static unsigned char i = 0;
TH0 = 0xFC;
TL0 = 0x67;
P0 =0xFF;
switch(i)
{
case 0: ADDR2=0;ADDR1=0;ADDR0=0;i++;P0=image[0];break;
case 1: ADDR2=0;ADDR1=0;ADDR0=1;i++;P0=image[1];break;
case 2: ADDR2=0;ADDR1=1;ADDR0=0;i++;P0=image[2];break;
case 3: ADDR2=0;ADDR1=1;ADDR0=1;i++;P0=image[3];break;
case 4: ADDR2=1;ADDR1=0;ADDR0=0;i++;P0=image[4];break;
case 5: ADDR2=1;ADDR1=0;ADDR0=1;i++;P0=image[5];break;
case 6: ADDR2=1;ADDR1=1;ADDR0=0;i++;P0=image[6];break;
case 7: ADDR2=1;ADDR1=1;ADDR0=1;i=0;P0=image[7];break;
default:break;
} //动态刷新
}
四、点阵的动画显示
1.纵向移动
纵向移动没什么技术含量,但是也很酷
在前面代码的前提上增多了图像的数量,但是动态刷新发生改变,原因也很简答,图片的二进制数控制的是一排的LED小灯,但是每次刷新,八排的LED都要发生变化,且向下刷新,而下一排在刷新后就变成就是上一排图片,所以switch(i)中的代码改成这样image[index + 0];,下一排都是上一排数+1
case 0:ADDR2=0;ADDR1=0;ADDR0=0;i++;P0=image[index + 0];break;
case 1:ADDR2=0;ADDR1=0;ADDR0=1;i++;P0=image[index + 1];break;
case 2:ADDR2=0;ADDR1=1;ADDR0=0;i++;P0=image[index + 2];break;
case 3:ADDR2=0;ADDR1=1;ADDR0=1;i++;P0=image[index + 3];break;
case 4:ADDR2=1;ADDR1=0;ADDR0=0;i++;P0=image[index + 4];break;
case 5:ADDR2=1;ADDR1=0;ADDR0=1;i++;P0=image[index + 5];break;
case 6:ADDR2=1;ADDR1=1;ADDR0=0;i++;P0=image[index + 6];break;
case 7:ADDR2=1;ADDR1=1;ADDR0=1;i=0;P0=image[index + 7];break;
default:break;
纵向移动图片
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
unsigned char code image[] ={
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xC3,0xE7,0xE7,0xE7,0xE7,0xE7,0xC3,0xFF,
0x99,0x00,0x00,0x00,0x81,0xC3,0xE7,0xFF,
0x99,0x99,0x99,0x99,0x99,0x81,0xC3,0xFF,
0xFF,0xFF,0xFf,0xFF,0xFF,0xFF,0xFF,0xFF
}; //32张图片组成的字模表
void main()
{
EA = 1;
ENLED = 0;
ADDR3 = 0;
TMOD = 0x01;
TH0 = 0xFC;
TL0 = 0x67;
ET0 = 1;
TR0 = 1;
while(1);
}
void InterruptTimer0() interrupt 1
{
static unsigned char i = 0;
static unsigned char index = 0;
static unsigned char tmr = 0;
TH0 = 0xFC;
TL0 = 0x67;
P0 = 0xFF;
switch(i)
{
case 0:ADDR2=0;ADDR1=0;ADDR0=0;i++;P0=image[index + 0];break;
case 1:ADDR2=0;ADDR1=0;ADDR0=1;i++;P0=image[index + 1];break;
case 2:ADDR2=0;ADDR1=1;ADDR0=0;i++;P0=image[index + 2];break;
case 3:ADDR2=0;ADDR1=1;ADDR0=1;i++;P0=image[index + 3];break;
case 4:ADDR2=1;ADDR1=0;ADDR0=0;i++;P0=image[index + 4];break;
case 5:ADDR2=1;ADDR1=0;ADDR0=1;i++;P0=image[index + 5];break;
case 6:ADDR2=1;ADDR1=1;ADDR0=0;i++;P0=image[index + 6];break;
case 7:ADDR2=1;ADDR1=1;ADDR0=1;i=0;P0=image[index + 7];break;
default:break;
} //动态刷新
tmr++;
if(tmr >= 250) //250ms改变一次图片索引
{
tmr = 0;
index++;
if(index >= 32)
{
index = 0; //刷完图片归零从头开始刷新图片
}
} //
}
2.横向移动
主要利用的是二维数组,因为我们控制三八译码器控制的是每一行LED的亮灭,而让图片横着走就会出现问题,二维数组就能很好解决这个问题
如果您c语言对数组的了解比较清晰我相信很好理解,不够还是很多同学不是很清楚,在这里我还是讲一下二维数组如何在这里面应用的
我们定义一个二维数组a[3][4],这是一个三行四列的数组,每一行从0开始到2有三个数,每一列从0开始到3,有四个数,而二维数组的顺序是什么了二维数组的数依次是[0][0],[0][1],[0][2],[0][3],[1][0],[1][2]......,我们不难发现前几个数行数不变列号一直在相加,我们遍触发核心功能,我们横向刷新的图片不就是保持行不变列的图片在改变吗
横向移动图片
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
unsigned char code image[30][8]={
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0xFF,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F},
{0xFF,0x3F,0x7F,0x7F,0x7F,0x7F,0x7F,0x3F},
{0xFF,0x1F,0x3F,0x3F,0x3F,0x3F,0x3F,0x1F},
{0xFF,0x0F,0x9F,0x9F,0x9F,0x9F,0x9F,0x0F},
{0xFF,0x87,0xCF,0xCF,0xCF,0xCF,0xCF,0x87},
{0xFF,0xC3,0xE7,0xE7,0xE7,0xE7,0xE7,0xC3},
{0xFF,0xE1,0x73,0x73,0x73,0xF3,0xF3,0xE1},
{0xFF,0x70,0x39,0x39,0x39,0x79,0xF9,0xF0},
{0xFF,0x38,0x1C,0x1C,0x1C,0x3C,0x7C,0xF8},
{0xFF,0x9C,0x0E,0x0E,0x0E,0x1E,0x3E,0x7C},
{0xFF,0xCE,0x07,0x07,0x07,0x0F,0x1F,0x3E},
{0xFF,0x67,0x03,0x03,0x03,0x07,0x0F,0x9F},
{0xFF,0x33,0x01,0x01,0x01,0x03,0x87,0xCF},
{0xFF,0x99,0x00,0x00,0x00,0x81,0xC3,0xE7},
{0xFF,0xCC,0x80,0x80,0x80,0xC0,0xE1,0xF3},
{0xFF,0xE6,0xC0,0xC0,0xC0,0xE0,0xF0,0xF9},
{0xFF,0x73,0x60,0x60,0x60,0x70,0x78,0xFC},
{0xFF,0x39,0x30,0x30,0x30,0x38,0x3C,0x7E},
{0xFF,0x9C,0x98,0x98,0x98,0x9C,0x1E,0x3F},
{0xFF,0xCE,0xCC,0xCC,0xCC,0xCE,0x0F,0x1F},
{0xFF,0x67,0x66,0x66,0x66,0x67,0x07,0x0F},
{0xFF,0x33,0x33,0x33,0x33,0x33,0x03,0x87},
{0xFF,0x99,0x99,0x99,0x99,0x99,0x81,0xC3},
{0xFF,0xCC,0xCC,0xCC,0xCC,0xCC,0xC0,0xE1},
{0xFF,0xE6,0xE6,0xE6,0xE6,0xE6,0xE0,0xF0},
{0xFF,0xF3,0xF3,0xF3,0xF3,0xF3,0xF0,0xF8},
{0xFF,0xF9,0xF9,0xF9,0xF9,0xF9,0xF8,0xFC},
{0xFF,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFE},
{0xFF,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF}
}; //动画帧
void main()
{
EA = 1;
ENLED = 0;
ADDR3 = 0;
TMOD = 0x01;
TH0 = 0xFC;
TL0 = 0x67;
ET0 = 1;
TR0 = 1;
while(1);
}
void InterruptTimer0() interrupt 1
{
static unsigned char i = 0;
static unsigned char tmr = 0;
static unsigned char index = 0;
TH0 = 0xFC;
TL0 = 0x67;
P0 = 0xFF;
switch(i)
{
case 0:ADDR2=0;ADDR1=0;ADDR0=0;i++;P0=image[index][0];break;
case 1:ADDR2=0;ADDR1=0;ADDR0=1;i++;P0=image[index][1];break;
case 2:ADDR2=0;ADDR1=1;ADDR0=0;i++;P0=image[index][2];break;
case 3:ADDR2=0;ADDR1=1;ADDR0=1;i++;P0=image[index][3];break;
case 4:ADDR2=1;ADDR1=0;ADDR0=0;i++;P0=image[index][4];break;
case 5:ADDR2=1;ADDR1=0;ADDR0=1;i++;P0=image[index][5];break;
case 6:ADDR2=1;ADDR1=1;ADDR0=0;i++;P0=image[index][6];break;
case 7:ADDR2=1;ADDR1=1;ADDR0=1;i=0;P0=image[index][7];break;
default: break;
} //动态刷新
tmr++;
if(tmr >= 250)
{
tmr = 0;
index++;
if(index >= 30)
{
index = 0;
}
}
}
那么它的代码部分结合我之前的分析逻辑在进行分析你很快就会透彻的
独立分析代码也是学习的重要一环,希望你我共同进步
总结
文章围绕8x8点阵展开,首先介绍其硬件结构,左侧8个引脚接内部LED阳极,上侧8个引脚接阴极,通过74HC138三八译码器和74HC245电路,配合单片机控制引脚电平实现LED点亮 。接着阐述点阵的使用,包括开启点阵第一排LED、点亮所有LED的代码实现;然后讲解用取模软件获取图像二进制代码,通过动态刷新在点阵上显示图像;最后介绍点阵动画显示,纵向移动通过增加图像数量和改变动态刷新方式实现,横向移动则借助二维数组解决行不变列变化的问题,均通过定时器中断完成动态刷新,实现不同的显示效果。
最后本文用于个人学习和帮助他人学习解惑,如有不对的地方欢迎给作者建议和学习交流,本文以《手把手教你学51单片机》作为课本教材,本文图片摘自其中,如有侵犯,私下联系,作者会及时更改,感谢。