本文将介绍一个在Raspberry Pi Pico上运行的MicroPython程序,该程序控制一个8x8 LED矩阵(MAX7219),并通过I2C与EEPROM进行数据交互。程序会随机生成一个数字,将其存储到EEPROM中,并在LED矩阵上显示相应的数字。如果从EEPROM读取的值与存储的值匹配,则显示数字;如果不匹配,则显示叉号。

效果

24LC64.gif

完整源码

eeprom_24LC64_pico.zip

使用的组件:

  • Raspberry Pi Pico:一款基于RP2040芯片的小型微控制器开发板。
  • MAX7219 8x8 LED矩阵:一种常见的显示模块,用于显示数字或字符。
  • 24LC64 EEPROM:一种通过I2C通信的串行EEPROM,用于数据存储。

关键功能:

  1. 使用SPI协议与MAX7219通信:MAX7219 LED矩阵通过SPI协议进行控制。
  2. 通过I2C与EEPROM交互:程序使用I2C协议与24LC64 EEPROM进行读写操作。
  3. 随机生成数字并存储:程序会生成一个随机数字并将其写入EEPROM。
  4. 显示效果:根据读取的EEPROM值来决定LED矩阵显示数字或叉号。

程序分析

from machine import Pin, SPI, I2C
from max7219 import max7219
import time
import random

# SPI接口设置
spi = SPI(1, baudrate=10000000, polarity=0, phase=0)
cs = Pin(0, Pin.OUT)

# I2C接口设置 (修改为I2C1,SDA=GPIO2, SCL=GPIO3)
i2c = I2C(1, scl=Pin(3), sda=Pin(2), freq=400000)

首先,程序初始化了SPI接口(用于与MAX7219进行通信)和I2C接口(用于与EEPROM进行通信)。SPI接口使用的是SPI(1),波特率设定为10MHz,极性和相位均为0。I2C接口设置为I2C1,使用GPIO2作为SDA,GPIO3作为SCL。

def scan_i2c():
    devices = i2c.scan()
    if len(devices) == 0:
        print("没有检测到I2C设备。")
        return None
    elif len(devices) == 1:
        print(f"检测到1个设备,地址: 0x{devices[0]:02X}")
        return devices[0]
    else:
        print("检测到多个I2C设备:")
        for i, device in enumerate(devices):
            print(f"{i + 1}: 0x{device:02X}")
        while True:
            try:
                choice = int(input("请选择设备 (输入序号): ")) - 1
                if 0 <= choice < len(devices):
                    return devices[choice]
                else:
                    print("无效选择,请重试。")
            except ValueError:
                print("请输入有效数字。")

scan_i2c函数用于扫描I2C总线上连接的设备。该函数会返回设备的地址,如果未检测到设备或检测到多个设备,程序会给出提示让用户自行选择一个设备。如果只检测到一个设备那么程序会直接使用。

检测到多个I2C设备

EEPROM_ADDR = scan_i2c()
if EEPROM_ADDR is None:
    raise Exception("未检测到EEPROM设备,程序终止。")

通过调用scan_i2c函数来确定连接的EEPROM设备。如果未找到设备,程序会抛出异常并终止。

# 初始化MAX7219
matrix = max7219.Matrix8x8(spi, cs, 1)
matrix.brightness(0)

# 显示方向(1=0°,2=90°,3=180°,4=270°)
display_direction = 2  # 默认顺时针旋转90度

在此部分,程序初始化了MAX7219模块并设置亮度为最低。display_direction变量决定显示的旋转方向,默认值为2,表示旋转90度。

# 定义数字0-9、问号和叉的图案
digits = [
    [0x3E, 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x3E],  # 0
    [0x0C, 0x1C, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F],  # 1
    [0x3E, 0x63, 0x03, 0x0E, 0x3C, 0x70, 0x63, 0x7F],  # 2
    [0x3E, 0x63, 0x03, 0x1E, 0x03, 0x03, 0x63, 0x3E],  # 3
    [0x06, 0x0E, 0x1E, 0x36, 0x66, 0x7F, 0x06, 0x06],  # 4
    [0x7F, 0x60, 0x7E, 0x03, 0x03, 0x03, 0x63, 0x3E],  # 5
    [0x1E, 0x30, 0x60, 0x7E, 0x63, 0x63, 0x63, 0x3E],  # 6
    [0x7F, 0x63, 0x06, 0x0C, 0x18, 0x18, 0x18, 0x18],  # 7
    [0x3E, 0x63, 0x63, 0x3E, 0x63, 0x63, 0x63, 0x3E],  # 8
    [0x3E, 0x63, 0x63, 0x63, 0x3F, 0x03, 0x06, 0x3C]   # 9
]
question_mark = [0x3E, 0x63, 0x03, 0x0E, 0x1C, 0x00, 0x1C, 0x1C]  # ?
cross_mark = [0x63, 0x36, 0x1C, 0x08, 0x1C, 0x36, 0x63, 0x00]    # X

在这部分代码中,定义了数字0-9、问号和叉号的图案。这些图案将以字节的形式存储,每个数字或符号由8行数据表示。

def rotate_pattern(pattern, direction):
    rotated = [[0] * 8 for _ in range(8)]
    for y in range(8):
        for x in range(8):
            bit = (pattern[y] >> (7 - x)) & 1
            if direction == 1:
                rotated[y][x] = bit
            elif direction == 2:
                rotated[x][7 - y] = bit
            elif direction == 3:
                rotated[7 - y][7 - x] = bit
            elif direction == 4:
                rotated[7 - x][y] = bit
    return [int("".join(str(bit) for bit in row), 2) for row in rotated]

rotate_pattern函数将数字或符号图案根据direction参数的值进行旋转。旋转方向包括:0°(不旋转)、90°、180°和270°。

def display_pattern(pattern):
    rotated = rotate_pattern(pattern, display_direction)
    matrix.fill(0)
    for y in range(8):
        matrix.buffer[y] = rotated[y]
    matrix.show()

display_pattern函数用于在LED矩阵上显示旋转后的图案。

def write_eeprom(addr, value):
    addr_high = (addr >> 8) & 0xFF
    addr_low = addr & 0xFF
    i2c.writeto(EEPROM_ADDR, bytes([addr_high, addr_low, value]))
    time.sleep(0.01)

def read_eeprom(addr):
    addr_high = (addr >> 8) & 0xFF
    addr_low = addr & 0xFF
    i2c.writeto(EEPROM_ADDR, bytes([addr_high, addr_low]))
    return int.from_bytes(i2c.readfrom(EEPROM_ADDR, 1), 'big')

write_eepromread_eeprom函数分别用于向EEPROM写入数据和从EEPROM读取数据。

last_number = -1

while True:
    new_number = random.choice([i for i in range(10) if i != last_number])
    last_number = new_number
    write_eeprom(EEPROM_MEM_ADDR, new_number)
    display_pattern(question_mark)
    time.sleep(0.5)
    read_number = read_eeprom(EEPROM_MEM_ADDR)
    if read_number == new_number:
        display_pattern(digits[read_number])
    else:
        display_pattern(cross_mark)
    time.sleep(1)

主循环中,程序生成一个新的随机数字(不等于上一个数字),将其写入EEPROM。然后显示一个问号,等待0.5秒后从EEPROM读取数据并与存储的数字进行比较。如果相同,则显示对应的数字;否则,显示叉号。整个过程每秒执行一次。

总结

该程序展示了如何使用MicroPython与Raspberry Pi Pico进行硬件编程,实现了与MAX7219 LED矩阵和24LC64 EEPROM的交互。通过SPI控制LED矩阵显示数字,通过I2C与EEPROM进行数据读写,能够实现数字存储和显示的功能,适用于数字展示、测试等应用场景。

系列文章

Last modification:January 19, 2025
If you think my article is useful to you, please feel free to appreciate