Arduino点阵屏案例
LED点阵屏
LED点阵屏通过LED(发光二极管)组成,以灯珠亮灭来显示文字、图片、动画、视频等led点阵显示汉字,是各部分组件都模块化的显示器件,通常由显示模块、控制系统及电源系统组成。LED点阵显示屏制作简单,安装方便,被广泛应用于各种公共场合,如汽车报站器、广告屏以及公告牌等。
显示原理
以简单的8X8点阵为例,它共由64个发光二极管组成,且每个发光二极管是放置在行线和列线的交叉点上,当对应的某一行置1电平,某一列置0电平,则相应的二极管就亮。
模块外围有16个引脚,序号如下。
而内部线序却不与外部引脚一致,点亮点阵屏中的LED需要按照内部线序来操作,如要将第一个点点亮,则9脚接高电平13脚接低电平,则第一个点就亮了;如果要将第一行点亮,则第9脚要接高电平,而(13、3、4、10、6、11、15、16)这些引脚接低电平,那么第一行就会点亮;如要将第一列点亮,则第13脚接低电平,而(9、14、8、12、1、7、2、5)接高电平,那么第一列就会点亮。
8x8点阵屏引脚连接
如上一节介绍,要正常点亮LED点阵需要连接16根线,也就是需要用到16个IO口,根据内部线序正确连接LED点阵的正极引脚和负极引脚(实质上为内部LED点亮的正极引脚与负极引脚);点阵屏的(9, 14, 8, 12, 1, 7, 2, 5)分别连接Arduino控制板的(6,11, 5, 9, 14, 4, 15, 2),这8个引脚为内部LED的正极引脚,点阵屏的(13, 3, 4, 10, 6, 11, 15, 16)分别连接开发板的(10,16, 17, 7, 3, 8, 12, 13),这8个引脚为内部LED的负极引脚。(如果你用的控制板是UNO和NANO这些,模拟引脚A0 - A5 也可以当点阵屏的控制引脚)
LED点阵屏Arduino UNO
正极引脚连接
9
6
14
11
8
5
12
9
1
A0
7
4
2
A1
5
2
负极引脚连接
13
10
3
A2
4
A3
10
7
6
3
11
8
15
12
16
13
8x8点阵屏代码编写
int leds[8] = {6, 11, 5, 9, A0, 4, A1, 2}; //点阵屏正极引脚
int gnds[8] = {10, A2, A3, 7, 3, 8, 12, 13}; //点阵屏负极引脚
void setup() {
for (int i = 0; i < 8; i++)
{
//将所有引脚配置为输出引脚
pinMode(leds[i], OUTPUT);
pinMode(gnds[i], OUTPUT);
digitalWrite(gnds[i], HIGH); //内部LED负极引脚给高电平,熄灭所有LED
}
}
//点亮点阵屏
void ledopen()
{
//将点阵屏正极引脚拉高,负极引脚拉低,开启显示
for (int i = 0; i < 8; i++)
{
digitalWrite(leds[i], HIGH);
digitalWrite(gnds[i], LOW);
}
}
//熄灭点阵屏
void ledclose()
{
//将点阵屏正极引脚拉低,负极引脚拉高,关闭显示
for (int i = 0; i < 8; i++)
{
digitalWrite(leds[i], LOW);
digitalWrite(gnds[i], HIGH);
}
}
//逐列扫描
void ledCol()
{
for (int i = 0 ; i < 8; i++)
{
digitalWrite(gnds[i], LOW);
for (int j = 0; j < 8; j++)
{
digitalWrite(leds[j], HIGH);
delay(40);
}
digitalWrite(gnds[i], HIGH);
ledclean();
}
}
//逐行扫描
void ledRow()
{
for (int i = 0 ; i < 8; i++)
{
digitalWrite(leds[i], HIGH);
for (int j = 0; j < 8; j++)
{
digitalWrite(gnds[j], LOW);
delay(40);
}
digitalWrite(leds[i], LOW);
ledclean();
}
}
void loop() {
ledopen(); //点阵屏打开
delay(500);
ledclose(); //点阵屏关闭
delay(500);
ledCol(); //列扫描
ledRow(); //行扫描
}
8x8点阵屏实验现象
根据程序控制的效果,点阵屏的显示为全亮,全灭,列扫描,行扫描,如下。
MAX7219
传统的点阵模块点亮需要用到16个IO引脚,这对IO口有限的控制板来说负担太大,接线也变得相对复杂,因此有了新的LED点阵屏解决方案 – MAX7219。
MAX7219 是美国MAXIM 公司推出的多位LED 显示驱动器,采用3 线串行接口传送数据,可直接与单片机接口连接,用户能方便修改其内部参数,以实现多位LED 显示。它内含硬件动态扫描电路、BCD译码器、段驱动器和位驱动器。此外,其内部还含有8X8 位静态RAM,用于存放8 个数字的显示数据。显然,它可直接驱动64 段LED点阵显示器。当多片MAX7219 级联时,可控制更多的LED 点阵显示器。显示的数据通过单片机数据处理后,送给MAX7219 显示。
MAX7219/MAX7221是一种集成化的串行输入/输出共阴极显示驱动器,它连接微处理器与8位数字的7段数字LED显示,也可以连接条线图显示器或者64个独立的LED。其上包括一个片上的B型BCD编码器、多路扫描回路,段字驱动器,而且还有一个8*8的静态RAM用来存储每一个数据。 只有一个外部寄存器用来设置各个LED的段电流。 MAX7221与SPI™、 QSPI™以及 MICROWIRE™相兼容,同时它有限制回转电流的段驱动来减少EMI(电磁干扰)。 一个方便的四线串行接口可以联接所有通用的微处理器。 每个数据可以寻址在更新时不需要改写所有的显示。MAX7219/MAX7221同样允许用户对每一个数据选择编码或者不编码。 整个设备包含一个150μA的低功耗关闭模式,模拟和数字亮度控制,一个扫描限制寄存器允许用户显示1-8位数据,还有一个让所有LED发光的检测模式。
MAX7219内部原理框图
MAX7219典型应用框图
关于MAX7219的应用框图如下,控制器连接MAX7219输入端,MAX7219控制端连接8位数码管或者是8x8LED点阵屏。同时也不要被图片的接线所误导,图中DIG 0 - DIG
7是指的MAX7219 DIG0,DIG1,DIG2,DIG3,DIG4,DIG5,DIG6,DIG7这7个引脚,同理SEG A-G,SEG DP也是指的MAX7219的8个引脚。
简单来说,MAX7219芯片可以驱动一块8x8的LED点阵,而连接控制板的就只需要3根线,即采用MAX7219方案只需要3根线可以控制一块8x8LED点阵屏。
MAX7219点阵显示模块
MAX7219点阵显示模块,通过16位数据串行输入输出方式完成控制64个LED,全程仅需3个IO口。市面上售卖的MAX7219点阵显示模块有两种规格,如下面的横向级联式:
靠近MAX7219芯片一端的是输入引脚,另一端是级联下一个MAX7219点阵显示模块的输出引脚,同样是5个引脚,只是输入的DIN引脚变为输出的DOUT引脚;可级联多个点阵模块,但基本只能是作为横向级联用。
下面是另一种规格,因为电路板的大小与点阵屏大小一致或略微小于点阵屏,这样就很方便将8x8点阵屏拼接成16x16或是32x32的大点阵屏:
点阵显示模块接线
模块接线。
MAX7219点阵模块Arduino UNO
VCC
5V
GND
GND
DIN
5
CS
4
CLK
3
点阵显示模块示例代码
int clk =3;
int cs=4;
int din=5;
unsigned char disp1[12][8]={
{0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C}, //0
{0x08,0x18,0x28,0x08,0x08,0x08,0x08,0x08}, //1
{0x7E,0x2,0x2,0x7E,0x40,0x40,0x40,0x7E}, //2
{0x3E,0x2,0x2,0x3E,0x2,0x2,0x3E,0x0}, //3
{0x8,0x18,0x28,0x48,0xFE,0x8,0x8,0x8}, //4
{0x3C,0x20,0x20,0x3C,0x4,0x4,0x3C,0x0}, //5
{0x3C,0x20,0x20,0x3C,0x24,0x24,0x3C,0x0}, //6
{0x3E,0x22,0x4,0x8,0x8,0x8,0x8,0x8}, //7
{0x0,0x3E,0x22,0x22,0x3E,0x22,0x22,0x3E}, //8
{0x3E,0x22,0x22,0x3E,0x2,0x2,0x2,0x3E}, //9
{0x08,0x7F,0x49,0x49,0x7F,0x08,0x08,0x08}, //中
{0xFE,0xFE,0x92,0xFE,0x9A,0xFE,0x82,0xFE}, //国
};
void setup(){
//设置引脚为输出
pinMode(cs,OUTPUT);
pinMode(clk,OUTPUT);
pinMode(din,OUTPUT);
//初始化MAX7219
Init_MAX7219();
}
void loop(){
char i,j;
//字体扫描显示
for(j=0;j<12;j++)
{
for(i=1;i<9;i++)
{
Write_Max7219(i,disp1[j][i-1]);
delay(100);
}
delay(500);
}
}
void Write_Max7219_byte(char DATA)
{
char i;
digitalWrite(cs,0);
for(i=8;i>=1;i--)
{
digitalWrite(clk,0);
if((DATA&0x80)>0){
digitalWrite(din,1);
}else{
digitalWrite(din,0);
}
//提取最高位给DIN端口
DATA=DATA<<1; //左移一位
digitalWrite(clk,1);
}
}
void Write_Max7219(char address,char dat)
{
digitalWrite(cs,0);
Write_Max7219_byte(address); //写入地址,即数码管编号
Write_Max7219_byte(dat); //写入数据,即数码管显示数字
digitalWrite(cs,1);
}
void Init_MAX7219(void)
{
Write_Max7219(0x09, 0x00); //译码方式:BCD码
Write_Max7219(0x0a, 0x01); //亮度
Write_Max7219(0x0b, 0x07); //扫描界限;8个数码管显示
Write_Max7219(0x0c, 0x01); //掉电模式:0,普通模式:1
Write_Max7219(0x0f, 0x00);
delay(500); //显示测试:1;测试结束,正常显示:0
}
点阵显示模块实验现象
按照代码轮流显示数字 “1 - 9” 以及中文 “中”,“国”,如图8x8点阵用于显示的话最好是显示数字及字母,中文的话显示少比划的字会比较直观,显示笔画较多或者复杂文字的话,就会显得有点尬了,可以参考下面的 “国” 字。
16x16点阵屏
用于显示文字用16x16点阵屏更为合适led点阵显示汉字,如下16x16的字模预览图。
市面上级联的点阵屏方案有很多,用于做案例的话基本是用四块8x8的LED拼接成的16x16点阵屏,可以买现成的16x16 LED点阵屏UART控制模块。
或者是自己动手将四块8x8点阵屏拼接起来,但最好是先跑一编程序过后再将四块8x8点阵屏粘起来或者用透明胶圈在一起,否正将出现以下情况,某块8x8的点阵屏跟其他8x8点阵屏的文字朝向不同,或者四块点阵屏是四个朝向,那就很尴尬了,如下图可以看到左上角的8x8点阵方向与其他点阵屏方向不同,导致一个字不能完整的显示出来。
16x16点阵屏编程
不管是8x8或16x16的点阵显示,有字模软件都是可以很方便的生成所需字模,例如16x16所要用到的字模软件,很方便的将多个汉字的字模一起提取出来。
字模提取
需要注意的一点是,字模软件上不管是提取一个汉字或者多个汉字,生成的字模并不是直接就能放进代码里面的,先以一个字为例,“科” 字取模,能得到的一组16进制数组如下:
{0x00,0x24,0x24,0xA4,0xFE,0xA3,0x22,0x00,0x22,0xCC,0x00,0x00,0xFF,0x00,0x00,0x00,
0x00,0x08,0x06,0x01,0xFF,0x00,0x01,0x04,0x04,0x04,0x04,0x04,0xFF,0x02,0x02,0x02}
因为每个汉字都是显示在16x16点阵上,所以每个8x8点阵都需要分担四分之一的汉字显示区域,即是一个汉字生成的数组字模,也需要分成四份,给到四块8x8点阵,将软件生成的单个汉字的32个16进制数组按8个,8个分成4组,如下:
unsigned char disp1[1][8] = {
{0x00,0x24,0x24,0xA4,0xFE,0xA3,0x22,0x00}, //科1 (左上角8x8点阵显示)
};
unsigned char disp2[1][8] = {
{0x22,0xCC,0x00,0x00,0xFF,0x00,0x00,0x00}, //科2 (右上角8x8点阵显示)
};
unsigned char disp3[1][8] = {
{0x00,0x08,0x06,0x01,0xFF,0x00,0x01,0x04}, //科3 (左下角8x8点阵显示)
};
unsigned char disp4[1][8] = {
{0x04,0x04,0x04,0x04,0xFF,0x02,0x02,0x02}, //科4 (右下角8x8点阵显示)
};
如果要显示两个字交替显示的话,字模数组这么写:
unsigned char disp1[2][8] = {
{0x00,0x24,0x24,0xA4,0xFE,0xA3,0x22,0x00}, //科1
{0x00,0x10,0x10,0x10,0xFF,0x10,0x90,0x08}, //技1
};
unsigned char disp2[2][8] = {
{0x22,0xCC,0x00,0x00,0xFF,0x00,0x00,0x00}, //科2
{0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x08}, //技2
};
unsigned char disp3[2][8] = {
{0x00,0x08,0x06,0x01,0xFF,0x00,0x01,0x04}, //科3
{0x00,0x04,0x44,0x82,0x7F,0x01,0x80,0x80}, //技3
};
unsigned char disp4[2][8] = {
{0x04,0x04,0x04,0x04,0xFF,0x02,0x02,0x02}, //科4
{0x40,0x43,0x2C,0x10,0x28,0x46,0x81,0x80}, //技4
};
16x16点阵屏代码
提取出字模后直接写代码。
//引脚定义
int clk =13;
int cs=10;
int din=11;
//字模数组
unsigned char disp1[4][8]={
{0x00,0xFE,0x02,0x02,0xFA,0x82,0x82,0xF2},
{0x80,0x80,0xFE,0x80,0xFC,0x00,0xFE,0x20},
{0x00,0xFC,0x04,0x04,0x04,0xFC,0x40,0x40},
{0x00,0x80,0xFE,0x02,0x04,0x00,0x00,0xFE},
};
unsigned char disp2[4][8]={
{0x82,0xA2,0x92,0xFA,0x02,0x02,0xFE,0x02},
{0x90,0x8C,0x92,0xE0,0x98,0x84,0x80,0x00},
{0xFE,0x40,0x20,0x20,0x12,0x0A,0x06,0x02},
{0x10,0x10,0x20,0x20,0xC0,0x30,0x08,0x04},
};
unsigned char disp4[4][8]={
{0x00,0x3F,0x20,0x20,0x2F,0x20,0x20,0x27},
{0x00,0x00,0x3F,0x00,0x1F,0x01,0x7F,0x02},
{0x00,0x1F,0x10,0x10,0x10,0x1F,0x10,0x10},
{0x01,0x00,0x1F,0x10,0x21,0x01,0x01,0x7F},
};
unsigned char disp3[4][8]={
{0x20,0x20,0x20,0x2F,0x20,0x20,0x3F,0x20},
{0x04,0x18,0x65,0x02,0x0C,0x30,0x02,0x01},
{0x1F,0x10,0x10,0x10,0x12,0x14,0x18,0x10},
{0x02,0x04,0x0C,0x03,0x00,0x01,0x06,0x38},
};
void setup(){
pinMode(cs,OUTPUT);
pinMode(clk,OUTPUT);
pinMode(din,OUTPUT);
Init_MAX7219();
}
void loop(){
char i,j;
//“国泰民安”轮流显示
for(j=0;j<4;j++)
{
for(i=1;i<9;i++){
Write_Max7219_1(i,disp1[j][i-1]);
Write_Max7219_2(i,disp2[j][i-1]);
Write_Max7219_3(i,disp3[j][i-1]);
Write_Max7219_4(i,disp4[j][i-1]);
}
delay(500);
}
}
void Write_Max7219_byte(char DATA)
{
char i;
digitalWrite(cs,0);
for(i=8;i>=1;i--)
{
digitalWrite(clk,0);
if((DATA&0x80)>0) digitalWrite(din,1);
else digitalWrite(din,0);
//提取最高位给DIN端口
DATA=DATA<<1; //左移一位
digitalWrite(clk,1);
}
}
void Write_Max7219_1(char address1,char dat1)
{
digitalWrite(cs,0);
Write_Max7219_byte(address1); //写入地址,即数码管编号
Write_Max7219_byte(dat1); //写入数据,即数码管显示数字
digitalWrite(cs,1);
}
void Write_Max7219_2(char address2,char dat2)
{
digitalWrite(cs,0);
Write_Max7219_byte(address2); //写入地址,即数码管编号
Write_Max7219_byte(dat2); //写入数据,即数码管显示数字
digitalWrite(clk,1);
Write_Max7219_byte(0x00);
Write_Max7219_byte(0x00);
digitalWrite(cs,1);
}
void Write_Max7219_3(char address3,char dat3)
{
digitalWrite(cs,0);
Write_Max7219_byte(address3); //写入地址,即数码管编号
Write_Max7219_byte(dat3); //写入数据,即数码管显示数字
digitalWrite(clk,1);
Write_Max7219_byte(0x00);
Write_Max7219_byte(0x00);
Write_Max7219_byte(0x00);
Write_Max7219_byte(0x00);
digitalWrite(cs,1);
}
void Write_Max7219_4(char address4,char dat4)
{
digitalWrite(cs,0);
Write_Max7219_byte(address4); //写入地址,即数码管编号
Write_Max7219_byte(dat4); //写入数据,即数码管显示数字
digitalWrite(clk,1);
Write_Max7219_byte(0x00);
Write_Max7219_byte(0x00);
Write_Max7219_byte(0x00);
Write_Max7219_byte(0x00);
Write_Max7219_byte(0x00);
Write_Max7219_byte(0x00);
digitalWrite(cs,1);
}
void Init_MAX7219(void)
{
Write_Max7219_1(0x09, 0x00); //译码方式:BCD码
Write_Max7219_1(0x0a, 0x01); //亮度
Write_Max7219_1(0x0b, 0x07); //扫描界限;8个数码管显示
Write_Max7219_1(0x0c, 0x01); //掉电模式:0,普通模式:1
Write_Max7219_1(0x0f, 0x00);
Write_Max7219_2(0x09, 0x00); //译码方式:BCD码
Write_Max7219_2(0x0a, 0x01); //亮度
Write_Max7219_2(0x0b, 0x07); //扫描界限;8个数码管显示
Write_Max7219_2(0x0c, 0x01); //掉电模式:0,普通模式:1
Write_Max7219_2(0x0f, 0x00);
Write_Max7219_3(0x09, 0x00); //译码方式:BCD码
Write_Max7219_3(0x0a, 0x01); //亮度
Write_Max7219_3(0x0b, 0x07); //扫描界限;8个数码管显示
Write_Max7219_3(0x0c, 0x01); //掉电模式:0,普通模式:1
Write_Max7219_3(0x0f, 0x00);
Write_Max7219_4(0x09, 0x00); //译码方式:BCD码
Write_Max7219_4(0x0a, 0x01); //亮度
Write_Max7219_4(0x0b, 0x07); //扫描界限;8个数码管显示
Write_Max7219_4(0x0c, 0x01); //掉电模式:0,普通模式:1
Write_Max7219_4(0x0f, 0x00); //显示测试:1;测试结束,正常显示:0
delay(500);
}
16x16汉字显示
程序效果如下
好了,赶快动手把你的点阵屏也玩起来吧。
8x8汉字取模和16x16汉字取模打包链接 → 字模资源链接
文章由启和科技编辑
下一篇:led与lcd显示屏的区别 LCD与LED显示屏区别