在电子制作中,点阵LED可以堪称为标准配件。使用点阵LED,可以用很少的引脚控制大量LED。在本文中,我们将为您介绍点阵LED的典型控制方式——动态点亮控制。
目录
- 用大量LED显示字符和图像!在电子制作中如何实现?
- 控制多个LED的“动态点亮控制”
- Arduino与点阵LED的接线
- 先了解动态点亮的基本工作
- 通过数组控制LED点亮
- 滑动显示字符使其像电子广告牌一样工作
- 增加LED的数量并进行复杂的控制
用大量LED显示字符和图像!在电子制作中如何实现?
如果您仔细观察街角和车站的电子广告牌,就会发现是通过上面很多呈网格状排列的LED分别点亮来显示字符和图像的。
稍微接触过像Arduino这样的微控制器开发板的人可能会想知道,他们是如何用只有几十个引脚的微控制器来控制几百乃至几千个LED的?
在本文中,我们将介绍使用点阵LED(电子制作中常用的典型电子组件)用很少的引脚控制大量LED的动态点亮控制。
控制多个LED的“动态点亮控制”
动态点亮控制是通过高速切换LED的点亮状态,使其看起来像多个LED同时点亮的一种控制方式。例如,当在1秒内对多个LED的点亮进行几百次切换时,人眼会觉得这些LED是同时点亮的。通过这种点亮控制,就可以用很少的微控制器板引脚控制很多LED。
这种动态点亮控制常用的是点阵LED,即以矩阵状排列多个LED。通过与动态点亮控制相结合,只需很少的布线即可实现各种LED点亮模式。
Arduino与点阵LED的接线
这次我们将介绍在电子制作中经常使用的8列x8行共64个LED的点阵LED的使用方法。这个点阵LED的布线包括列和行在内只有16根线。
点阵LED没有用来限制电流的电阻器。我们一边查看技术规格书,一边将8个电阻分别连接到阳极侧或阴极侧吧。
电阻值由Arduino的数字输入输出引脚的电压(5V)、LED固有的正向压降(VF)和LED的亮度(电流)决定。但是,请注意Arduino对可从引脚获取的电流值是有限制的。电阻器连接到阳极侧或阴极侧都可以。
使用Arduino Uno时,布线请避免使用草图写入用的数字0,1(TX、RX)引脚和连接着内置LED的数字13引脚。虽然数字引脚不足,但可将模拟引脚A0~A5分别用作数字引脚D14~D19,这样就足够连接16个引脚。
先了解动态点亮的基本工作
点阵LED接线完成后,需要编写一个草图。首先,需要让点阵LED的所有LED点亮。方法是让1行中的所有LED点亮,并快速切换列,使其看起来像所有LED都点亮了。
//矩阵LED引脚顺序 int anode[8] = { 15, 4, 5, 11, 7, 12, 17, 18 }; int cathode[8] = { 10, 16, 9, 14, 2, 8, 3, 6 }; void setup() { //引脚初始化 for ( int i = 0; i < 8; ++i ) { pinMode( anode[i], OUTPUT ); digitalWrite( anode[i], LOW ); } for ( int i = 0; i < 8; ++i ) { pinMode( cathode[i], OUTPUT ); digitalWrite( cathode[i], HIGH ); } } void loop() { for ( int i = 0; i < 8; ++i ) { digitalWrite( cathode[i], LOW ); for ( int j = 0; j < 8; ++j ) { digitalWrite( anode[j], HIGH ); } //delay(100); for ( int j = 0; j < 8; j++ ) { digitalWrite( anode[j], LOW ); } digitalWrite( cathode[i], HIGH ); } }
使用数组和for语句即可对点阵LED编写一个简单的草图。下面简要解说一下程序的流程。
在最开始的anode数组和cathode数组中,分别输入了矩阵LED引脚和Arduino引脚的接线信息。在anode数组中,依次输入了矩阵LED列的引脚。在cathode数组中,依次输入了矩阵LED行的引脚。我们要注意的是,确保所连接的Arduino引脚按照矩阵LED的行列编号顺序保存在数组中。
在接下来的setup函数中,为了定义Arduino中使用的引脚的状态,使用anode和cathode数组以及for语句对每个引脚逐一进行了初始化。
矩阵LED的点亮状态由loop函数控制。如果使用双重for循环语句,将会干净利落地实现矩阵LED的点亮。
在外侧for语句中,将要点亮的行的cathode侧设置为LOW,以便使电流流过整个行。之后,通过内侧for语句按顺序指定要点亮的列。这次需要将所有列的LED都点亮,因此将anode侧全部设置为HIGH。当这些处理完成后,1整行的灯都会亮起。通过对所有的行快速重复该动作,使人看起来好像所有的LED都同时亮起了。
如果启用第29行注释的delay函数,应该可以看到是如何逐行切换显示的。综上所述,我们已经了解了动态点亮是通过快速切换LED的ON/OFF实现看起来像多个LED同时点亮的一种方式。
matrix led 07通过数组控制LED点亮
至此,您应该已经了解了点阵LED的控制机制。然而,仅仅点亮LED是不够的,我们需要让LED的点亮状态能够自由切换!在这次的案例中,我们尝试使之显示DEVICE PLUS的一个字母“D”。
由于LED的ON/OFF控制只需要0和1的数据(boolean型)即可,因此我们使用如下所示的数组来定义字母“D”的点亮数据。我们设要点亮的LED为“1”,要熄灭的LED为“0”,并以点图的方式来定义数组。由于我们使用的是8×8点阵,因此数组也是8×8。
boolean matrix[8][8] = { { 0, 1, 1, 1, 1, 0, 0, 0 }, { 0, 1, 1, 1, 1, 1, 0, 0 }, { 0, 1, 1, 0, 1, 1, 1, 0 }, { 0, 1, 1, 0, 0, 1, 1, 0 }, { 0, 1, 1, 0, 0, 1, 1, 0 }, { 0, 1, 1, 0, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 0, 0 }, { 0, 1, 1, 1, 1, 0, 0, 0 } };
下面需要更改草图,以使数组的内容反映在显示中。将双重for语句中的digitalWrite函数更改为引用定义的数组。
digitalWrite( anode[j], HIGH );
↓
digitalWrite( anode[j], matrix[i][j] )
反映了这些更改的草图如下:
//矩阵LED引脚顺序 int anode[8] = { 15, 4, 5, 11, 7, 12, 17, 18 }; int cathode[8] = { 10, 16, 9, 14, 2, 8, 3, 6 }; void setup() { //引脚初始化 for ( int i = 0; i < 8; ++i ) { pinMode( anode[i], OUTPUT ); digitalWrite( anode[i], LOW ); } for ( int i = 0; i < 8; ++i ) { pinMode( cathode[i], OUTPUT ); digitalWrite( cathode[i], HIGH ); } } boolean matrix[8][8] = { { 0, 1, 1, 1, 1, 0, 0, 0 }, { 0, 1, 1, 1, 1, 1, 0, 0 }, { 0, 1, 1, 0, 1, 1, 1, 0 }, { 0, 1, 1, 0, 0, 1, 1, 0 }, { 0, 1, 1, 0, 0, 1, 1, 0 }, { 0, 1, 1, 0, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 0, 0 }, { 0, 1, 1, 1, 1, 0, 0, 0 } }; void loop() { // 字符数据的输出处理 for ( int i = 0; i < 8; i++ ) { digitalWrite( cathode[i], LOW ); for ( int j = 0; j < 8; j++ ) { digitalWrite( anode[j], matrix[i][j] ); } //delay(50); for ( int j = 0; j < 8; j++ ) { digitalWrite( anode[j], LOW ); } digitalWrite( cathode[i], HIGH ); } }
执行草图程序,LED应会按照数组的内容亮起。与之前的草图一样,如果启用注释的delay函数,就可以看到在逐行绘制D的形状时LED是如何切换的。
草图的处理很简单,即分别读取数组中的“0”和“1”,并控制相应位置的LED的点亮状态。也就是说,只要能够这样读取数组,就可以自由自在地控制LED的点亮状态了。
至此,您应该已经了解了点阵LED的动态点亮控制机制。
滑动显示字符使其像电子广告牌一样工作
当您能够自由自在地控制点阵LED后,接下来可能就会想要实现像电子广告牌一样的效果了。当然,只要您能使用点阵LED和Arduino,就可以切换点亮状态下的显示状态,也可以实现像电子广告牌一样滚动,但这里需要一些草图技巧。
例如,如何才能在进行动态点亮控制的同时使字符以1秒为单位滚动?在这里,如果使用LED闪烁中经常使用的delay函数,微控制器就会停止,动态点亮控制也会停止,无法显示字符。
要想不间断地控制LED,就需要考虑怎样处理才能使微控制器不会停动。而且,要想像电子广告牌那样显示很多字符时,还需要很多数组数据,并需要考虑如何从这些数组中提取要显示的部分。
因此,为了避免微控制器停动,这次我们将添加一个处理:使用millis函数检测经过的时间,同时滚动字符。
if (tm + SCROLL_TIME <= millis()) { for (int i = 0; i < 8 ; i++) { for (int j = 0; j < 8 ; j++) { matrix[i][j] = matrix_data[i][j + slide]; } } //滑动保存位置,到达终点时返回起点 if (slide < 49) { ++slide; } else { slide = 0; } //重新检测经过的时间 tm = millis(); }
如果是滚动显示的话,字符数据的数组也会变大。这次,我们将创建能够滚动显示字符“DEVICE PLUS”的数组数据。
boolean matrix_data[8][57] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0 } };
添加了滚动显示功能的草图如下。整个草图的流程是从保存有字符数据的数组中提取要显示部分的数组,并在指定的时间滚动。由于Arduino自始至终不会停止,因此可以始终执行动态点亮控制。
//矩阵LED引脚顺序 int anode[8] = { 15, 4, 5, 11, 7, 12, 17, 18 }; int cathode[8] = { 10, 16, 9, 14, 2, 8, 3, 6 }; //字符数据 boolean matrix_data[8][57] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0 } }; boolean matrix[8][8] = {}; //输出用的数组变量 int slide = 0; unsigned long tm = 0; //滚动时间 #define SCROLL_TIME 90 //毫秒 void setup() { //引脚初始化 for ( int i = 0; i < 8; ++i ) { pinMode( anode[i], OUTPUT ); digitalWrite( anode[i], LOW ); } for ( int i = 0; i < 8; ++i ) { pinMode( cathode[i], OUTPUT ); digitalWrite( cathode[i], HIGH ); } // 将输出用的数组初始化 for (int i = 0; i < 8 ; ++i) { for (int j = 0; j < 8 ; ++j) { matrix[i][j] = 0; } } //保存初始经过时间 tm = millis(); } void loop() { //按照每个经过时间将字符数据保存在输出用的数组中 if (tm + SCROLL_TIME <= millis()) { for (int i = 0; i < 8 ; i++) { for (int j = 0; j < 8 ; j++) { matrix[i][j] = matrix_data[i][j + slide]; } } //滑动保存位置,到达终点时返回起点 if (slide < 49) { ++slide; } else { slide = 0; } //重新检测经过的时间 tm = millis(); } // 字符数据的输出处理 for ( int i = 0; i < 8; i++ ) { digitalWrite( cathode[i], LOW ); for ( int j = 0; j < 8; j++ ) { digitalWrite( anode[j], matrix[i][j] ); } //delay(50); for ( int j = 0; j < 8; j++ ) { digitalWrite( anode[j], LOW ); } digitalWrite( cathode[i], HIGH ); } }
在这个草图中,可以通过更改第23行的SCROLL_TIME的数字来调整滚动速度。视频因为反光有点不方便看,不过即使将速度提高到70ms,也可以看到字符形状。
增加LED的数量并进行复杂的控制
在使用Arduino直接控制点阵LED的方法中,最大可以控制8×8的点阵LED,这是极限。如果想要控制更大的点阵LED,需要使用专用IC进行通信控制,或使用外部存储器。
乍一看很简单,其实点阵LED是一种比较复杂深奥的电子组件。要想很好地使用它,需要掌握电子元器件和微控制器技术。
处理点阵的技术也可以应用在其他电子元器件上,因此点阵LED可能是非常适合用来学习的电子组件。
无论是用于电子制作还是用来学习,鉴于它是一种很易于买到的电子产品,在购买Arduino时把点阵LED也一起买下来,可能是个不错的选择。