UNO R4 WiFi是Arduino经典单片机系列中的最新成员。除了功能强大的Renesas RA4M1单片机外,这款新板还配备了12 x 8的LED显示矩阵。也许你已经看到了这款LED矩阵上的标志性心形符号。这是每款Arduino UNO R4 WiFi都默认包含的程序,如图1所示。
Arduino UNO R4 WiFi的操作有详细的文档记录,并提供了用户友好的API。不过我们仍可在硬件层面探索LED显示矩阵背后的工作原理。这是详细了解单片机的I/O和多路复用技术的绝佳机会。
图 1 :Arduino Uno R4 LED显示矩阵上的心形
如何用11条控制线来控制96个LED?
答案很简单,就是使用一种称为Charlieplexing的技术,据说是以发明者Charles Allen的名字命名的。该技术依赖于单片机输出引脚的三态特性。每个引脚都可以配置为:
- 输出:逻辑低
- 输出:逻辑高
- 输入:高阻抗
图2中建议使用一系列开关来执行此操作。例如,单片机的三态开关(如TRI_0)决定了相应引脚是输入还是输出。当开关断开时,每个单片机的I/O引脚都会处于浮动状态(高阻抗),允许外部电路决定电压。当开关闭合时,ROW_0驱动器决定了引脚的输出电压。请访问此链接,以图2为基础进行互动MultisimLive模拟。作为一项挑战,尝试按顺序激活LED1到LED6。
图 2 :Arduino UNO R4 WiFi的LED显示矩阵的前6个LED的简化示意图。请访问此链接,进行互动模拟。
在图2中,我们可以看到,LED1被激活了。当ROW_0源电流而ROW_1汇电流时,就会发生这种情况。我们可以通过切换ROW_0和ROW_1的逻辑来激活LED2。操作完毕后,ROW_1将源电流而ROW_0将汇电流。
请注意,ROW_2被配置为具有高阻抗的输入。这很重要,因为它可以防止多个LED同时被激活。举例而言,如图2所示,如果激活了TRI_2:
- ROW_2高:LED1和LED6同时激活
- ROW_2低:LED1和LED3同时激活
技术提示: 电子新手们可能会对“源”(source)和“汇”(sink)这两个术语感到困惑。这是一个参考系问题,部分归因于物理学的历史。它始于本杰明·富兰克林在18世纪50年代所做的实验,他提出了电流从电源的正极流向负极的概念。近150年后,J.J.汤姆森于1897年发现了电子。从那时起,我们就开始用富兰克林的传统电流(正极到负极)和电子电流(负极到正极)来思考电的问题。
你可能认为这是一个已经解决的问题。然而,即使在今天,你也可以找到采用不同惯例的教科书。在检查后你会发现,每个电流向量都发生了反转,所有的右手规则都被左手取代,反之亦然。
再次强调,术语“源”和“汇”的含义取决于你使用的参考系。为清楚起见,我们将遵循传统电流流向,即,正电源端“源”电流,负电源端“汇”电流。在图2中,5VDC是源,地是汇。
Arduino代码示例
我们可以借助Arduino代码更好地理解图2的操作。为方便起见,假设LED矩阵连接到引脚D0、D1和D2,分别对应ROW_0、ROW_1和ROW_2。如代码所示,在以下情况下LED1被激活:
pinMode(D0, OUTPUT); // Tri state configuration
pinMode(D1, OUTPUT);
pinMode(D2, INPUT);
digitalWrite(D0, HIGH); // Logic assertion when the Tri state buffer is active
digitalWrite(D1, LOW);
在另一个示例中,假设我们希望激活LED5:
pinMode(D0, INPUT);
pinMode(D1, OUTPUT);
pinMode(D2, OUTPUT);
digitalWrite(D1, HIGH);
digitalWrite(D2, LOW);
多路复用
到目前为止,我们一直关注于单个LED的控制。在实践中,我们会希望同时打开多个LED。例如,假设我们希望同时激活LED1和LED5。根据图2的示意图,这是不可能的。仔细检查图2就会发现,如果LED1亮起,其他可能亮起的只有LED3或LED6。实际上,如果我们遍历所有8种可能性就会发现,在任何给定的开关状态下,只能同时点亮2个LED。
在这种情况下可以多路复用LED。
利用这种多路复用技术,可确保在任何时候只有一个LED处于活动状态。我们可以快速地在LED之间切换,使每个LED只亮一小段时间。例如,要激活LED1和LED5,我们可以交替使用前一部分中的代码片段。而人眼看到的是两个LED同时亮起,前提是循环顺序的完成速度约超过30Hz。这种视觉持久性(闪烁融合)造成了LED同时被激活的幻觉。
这种技术的一个显著问题是LED的亮度。回想一下,多路复用是一个时间分割过程,给每个LED分配了一个时间段。对于上述两个LED的问题,则每个LED点亮的时间各占50%。对于图2所示的六个LED的问题,每个LED点亮的时间各占16%。可想而知,点亮时间占50%的LED会比点亮时间占16%的LED更亮。有关LED多路复用的广泛探索(含亮度、时间和脉冲电流的分析),请参阅这篇文章。
Arduino UNO R4上的Charlieplexing
粗略看一下Arduino UNO R4 WiFi的规格书,可以发现LED显示矩阵由11个单片机I/O引脚驱动。规格书中还显示了一个互补型LED矩阵,其中每对LED均被配置为阳极到阴极和阴极到阳极。图3展示了一小部分示意图。请注意,这与图2示例几乎相同。Charlieplexing的工作原理与上一部分中的描述完全一致。
图 3 :这一小部分Arduino UNO R4 WiFi示意图对应于图2。
如何提高Arduino UNO R4 WiFi显示屏的亮度?
简单来说,应认识到LED亮度受Charlieplex方法的限制,而Charlieplex方法又受单片机电流限制的I/O引脚的限制。我们还必须考虑修改易于使用的LED矩阵库所产生的负担。
显示屏会显示为所需的亮度。
不过,你也可以添加红色透镜来增加表观亮度。例如,红色半透明的Hammond 1591STRD可以同时用作外壳和透镜。显示效果如视频1中所示。
视频 1 :Hammond 1591STRD外壳用作Arduino UNO R4的红色透镜的视频
Charlieplex方法有哪些局限性?
为帮助你更好地理解Arduino UNO R4的局限性,我们需要考虑Charlieplex方法的局限性。
-
回想一下,Charlieplexing是一种极具成本效益的方法,可用于控制等多个LED。驱动力直接来源于单片机,而无需使用行和列驱动器。因此,亮度(LED电流)直接与单片机驱动引脚的“强度”有关。这是无法改变的物理限制,除非从根本上改变显示硬件。
-
单个LED的亮度由亮起时间(占空比)决定。12x8的显示屏中包含96个LED,每个LED亮起的时间大约占1%。每个LED都必须轮流亮起,但时间非常短暂。这是另一个无法改变的物理限制。尤其是在我们希望显示屏保持亮度一致的情况下。例如,如果只有两个像素处于活动状态,我们可以在它们之间分配时间。然而,随着更多的LED被激活,显示屏的亮度会降低。
总结来说,提高亮度的唯一方法是重新设计硬件,增加行和列驱动器,或者降低期望并减少阵列中的LED数量。虽然这不是个线性过程,但一般来说,将LED总数减半会使感知亮度翻倍,因为每个LED可以被激活的时间翻倍了。
技术提示: 对于诸如Renesas R7FA4M1AB3CFM#AA0等复杂的单片机,并不只有单个引脚电流这一种规格。但一般来说,RA4M1可以处理每个引脚8mA的电流,且所有引脚的总电流限制为60mA。有关更多其他的考虑因素和规定,请参阅规格书。
如何直接通过Arduino UNO R4 LED矩阵访问LED?
通常,你会使用Arduino库来控制LED显示屏。但我们已经深入了解到,我们可以使用Renesas灵活软件包(FSP)直接访问个别RA4M1特殊功能寄存器(SFR):这种技术可能有利于未来的实验,特别在我们需要获得与直接端口访问相关的速度的情况下。
技术提示: Renesas灵活软件包(FSP)是一个硬件抽象层(HAL)。它在很多方面与Arduino语言相似,两者都旨在隐藏/简化底层硬件,从而提高代码的可移植性。
你可能感兴趣的是,Arduino针对UNO R4 Minima和WiFi的实施是以Renesas FSP为基础的。
仔细查看Arduino UNO R4 WiFi的示意图可以得知:
- ROW_0对应于P205(端口2引脚5)
- ROW_1对应于P012(端口0引脚12)
- ROW_2对应于P013(端口0引脚13)
例如,要打开LED 1,我们可以使用这段代码。
R_IOPORT_PinCfg(NULL, ROW_0, IOPORT_CFG_PORT_DIRECTION_OUTPUT);
R_IOPORT_PinCfg(NULL, ROW_1, IOPORT_CFG_PORT_DIRECTION_OUTPUT);
R_IOPORT_PinCfg(NULL, ROW_2, IOPORT_CFG_PORT_DIRECTION_INPUT);
// Assume all other row drivers are inputs (high impedance)
R_IOPORT_PinWrite(&g_ioport_ctrl, ROW_0, BSP_IO_LEVEL_HIGH);
R_IOPORT_PinWrite(&g_ioport_ctrl, ROW_1, BSP_IO_LEVEL_LOW);
要打开LED5,我们可以使用这段代码:
R_IOPORT_PinCfg(NULL, ROW_0, IOPORT_CFG_PORT_DIRECTION_INPUT);
R_IOPORT_PinCfg(NULL, ROW_1, IOPORT_CFG_PORT_DIRECTION_OUTPUT);
R_IOPORT_PinCfg(NULL, ROW_2, IOPORT_CFG_PORT_DIRECTION_OUTPUT);
R_IOPORT_PinWrite(&g_ioport_ctrl, ROW_1, BSP_IO_LEVEL_HIGH);
R_IOPORT_PinWrite(&g_ioport_ctrl, ROW_2, BSP_IO_LEVEL_LOW);
然后我们可以使用这段代码在LED0和LED5之间实现多路复用:
#define ROW_0 BSP_IO_PORT_02_PIN_05
#define ROW_1 BSP_IO_PORT_00_PIN_12
#define ROW_2 BSP_IO_PORT_00_PIN_13
void setup() {
;
}
void loop() {
R_IOPORT_PinCfg(NULL, ROW_0, IOPORT_CFG_PORT_DIRECTION_OUTPUT);
R_IOPORT_PinCfg(NULL, ROW_1, IOPORT_CFG_PORT_DIRECTION_OUTPUT);
R_IOPORT_PinCfg(NULL, ROW_2, IOPORT_CFG_PORT_DIRECTION_INPUT);
R_IOPORT_PinWrite(&g_ioport_ctrl, ROW_0, BSP_IO_LEVEL_HIGH);
R_IOPORT_PinWrite(&g_ioport_ctrl, ROW_1, BSP_IO_LEVEL_LOW);
delay(20);
R_IOPORT_PinCfg(NULL, ROW_0, IOPORT_CFG_PORT_DIRECTION_INPUT);
R_IOPORT_PinCfg(NULL, ROW_1, IOPORT_CFG_PORT_DIRECTION_OUTPUT);
R_IOPORT_PinCfg(NULL, ROW_2, IOPORT_CFG_PORT_DIRECTION_OUTPUT);
R_IOPORT_PinWrite(&g_ioport_ctrl, ROW_1, BSP_IO_LEVEL_HIGH);
R_IOPORT_PinWrite(&g_ioport_ctrl, ROW_2, BSP_IO_LEVEL_LOW);
delay(20);
}
当代码运行时,LED会开始闪烁。当延迟减少到大约10毫秒时,闪烁将停止。
总结
Arduino UNO R4 WiFi包括一个12x8的LED显示屏矩阵,这个矩阵非常有趣!如往常一样,Arduino提供了易于使用的库,支持你在几分钟内配置和使用显示屏。
就个人而言,我很欣赏UNO R4 WiFi的硬件设计,因为它提供了可以探索Charlieplexing技术的学习机会。这种硬件应用为单片机的三态输出、多路复用以及Renesas FSP等工具提供了一个窗口。这些都有助于加深你对LED电流和脉冲操作的理解。
通过回答本文末尾的问题和批判性思维练习来测试你的知识掌握情况。欢迎在下面的空白处提问和评论。
最后,如果本文对你有用,请点个赞。
顺颂商祺,
APDahlen
有用链接
请通过以下链接查看相关的有用信息:
- Digikey的产品选择指南
- Arduino教育内容
- 使用Arduino UNO R4 WiFi LED矩阵
- Arduino UNO R4 WiFi文档
- Renesas RA4M1文档
- Renesas灵活软件包(FSP)