
开发者用Z80汇编在RC2014上通过SPI控制LED矩阵
来源标题:Using a SPI LED Matrix from a RC2014
开发者演示了如何用Z80汇编写SPI协议,让RC2014计算机控制MAX7219 8×8 LED矩阵。方案通过SC129数字IO模块单端口位操作SPI,用5根线连接MAX7219,用于2026 RetroChallenge项目。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
在这篇文章中,我将展示如何从 Z80 汇编语言使用 SPI 协议,使 RC2014 计算机能够控制 MAX7219 LED 矩阵。
为参加 2026 RetroChallenge,我正在探索如何从基于 Z80 的 RC2014 计算机使用 SPI 设备。我想使用的第一个设备是一个 8×8 LED 矩阵。Shelia Dixon 之前曾为 RC2014 开发过一个 8×8 LED 矩阵显示模块;不过,该模块通过两个 I/O 端口直接与 RC2014 连接。我将只使用一个端口,并通过 bit-banging 方式实现 SPI 协议来与它通信。
我使用的 8×8 LED 矩阵采用 MAX7219 来处理 SPI 通信并控制 LED。它使用 5 根线与 RC2014 连接。
我使用 Small Computing Central 的 SC129 Digital IO 模块在 RC2014 上提供数字输出。它提供的引脚适合 DuPont 连接器。你也可以使用官方的 RC2014 Digital IO 模块,但需要修改它以增加连接。在这种情况下,使用 SC129 模块更简单。SC129 与 LED 矩阵模块的连接方式如下……
当我们想向 MAX7219 发送数据时,它给出了以下时序图供我们遵循。
因此,要发送数据,我们首先需要将 CS 线拉低。这会激活 MAX7219,使它知道要监听传入的数据。接下来,我们设置 DIN 并将 CLK 拉高。这会将 DIN 上的单个数据位加载到 MAX7219 中。然后我们将 CLK 拉低,为发送下一位做准备。我们总共重复这个过程 8 次,以发送一个字节的数据。
MAX7219 期望每条消息发送两个字节的数据。第一个字节是地址,第二个字节是数据值。
那么,我们在 Z80 上如何实现这一点呢?首先,我们要定义一些常量来提供帮助。
OUTPUT_PORT EQU $01
如前所述,数据位是 D0,时钟是 D1,选择线是 D2。我们将数据位称为 MOSI,它代表 Master Out Slave In。
MOSI EQU %00000001 CLK EQU %00000010 SELECT EQU %00000100
如你所见,我们使用二进制来定义位置。当我们想将这些位置中的某一位置位时,可以使用 OR 语句;而当我们想清除该位时,可以将它与反码(取反)进行 AND 运算。
因此,要启用 MAX7219,我们希望 SELECT 线为低电平、CLK 线为低电平,并将 MOSI 拉高。我们可以使用以下 Z80 子程序来实现这一点。
select_max7219: ld a, 0 & ~SELECT & ~CLK | MOSI out (OUTPUT_PORT),a ret
要禁用 MAX7219,我们希望 SELECT 线为高电平、CLK 线为低电平,并将 MOSI 拉高。
deselect_max7219: ld a, 0 | SELECT & ~CLK | MOSI out (OUTPUT_PORT),a ret
要发送一个字节,需要发送 8 位数据。我们将要发送的字节通过 D 寄存器传入。要发送一位数据,我们知道需要将 SELECT 和 CLK 拉低。我们可以准备好这个值并将其保存到 E 寄存器,以便每一位重复使用。我们将把数据移位到 MOSI 位,因此在保存到 E 之前,先将其右移。现在,对于我们要发送的每一位,首先将缓存 E 寄存器的值加载到 A 寄存器。然后通过将 D 寄存器左移,取出 D 寄存器中的下一位。这会将我们要发送的位推入进位标志。我们通过将 A 寄存器左移来取回它,这样就会将进位标志的值设置到 MOSI 位。我们发送这个值,然后将 CLK 位进行 OR 运算以将其拉高,并发送该值。
这段解释相当冗长,但下面是代码,希望这样更清楚。
transmit_max7219_byte: push bc ld b, 8 ld a, 0 &~SELECT &~CLK | MOSI rra ld e, a .transmit_max7219_bit: ld a, e rl d rla out (OUTPUT_PORT), a or a, CLK out (OUTPUT_PORT), a djnz .transmit_max7219_bit pop bc ret
要向 MAX7219 发送双字节指令,我们需要组合已经构建的子程序。我们需要选中 MAX7219,发送两个字节,然后取消选中它。我们将通过寄存器 B 和 C 传入这两个字节。
max7219_write: call select_max7219 call transmit_max7219 call deselect_max7219 ret
transmit_max7219: ld d, b call transmit_max7219_byte ld d, c call transmit_max7219_byte ret
使用 SPI 控制 MAX7219
要告诉 MAX7219 打开或关闭某个 LED,我们在一个字节中发送列地址,在下一个字节中发送列数据。也就是 8 列位。不过,我们还需要发送一些额外的命令码,以便 MAX7219 知道如何工作。
完整命令列表可在 MAX7219 数据手册中找到。
MAX7219 可以连接 7 段数码管,但我们不需要这些功能,因此需要告诉它不要对任何传入的显示命令进行解码。我们还要确保它以低占空比运行,以降低功耗。
以下是我用来初始化显示器的命令。
ld bc, 0x0C00 ; 关机模式,确保 LED 关闭。 call max7219_write ld bc, 0x0900 ; 不解码 call max7219_write ld bc, 0x0A01 ; 3/32 亮度 call max7219_write ld bc, 0x0B07 ; 扫描全部 7 列 call max7219_write ld bc, 0x0F00 ; 不进行显示测试 call max7219_write
设置完成后,我们就可以发送图像了。我们在寄存器 B 中发送列号,在寄存器 C 中发送列数据。因此,要发送一个十字图案,我可以使用以下代码。
ld hl, cross ld b, 8 .send_image: ld c, (hl) inc hl call max7219_write djnz .send_image
cross: dc %00000000 dc %01000010 dc %00100100 dc %00011000 dc %00011000 dc %00100100 dc %01000010 dc %00000000
最后,我打开显示器。
ld bc, 0x0C01 ; 正常工作模式——打开显示器 call max7219_write
在 RC2014 上构建、部署和运行
为了汇编代码,我在 MacBook Pro 上使用 SjASMPlus Z80 汇编器。RC2014 运行 SCM,因此为了传输汇编后的代码,我需要先将其转换为 Intel hex 格式再发送。我使用 z88dk-appmake 来完成这项工作。传输完成后,我在 SCM 中使用“g”命令运行该应用程序。
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。