8x8 LED 点阵模块

罗大富 BigRich大约 5 分钟ESP32Arduino

之前我们已经点亮过数码管了,今天我们来学习 8x8 点阵 LED 屏,先通过点阵屏显示一个图案,最终实现使用 PS2 摇杆控制点阵屏制作一个 LED 移动的小游戏。

实验原理

LED 8*8 点阵屏模块是一种常见的 LED 屏幕模块,它由 8 行 8 列的 LED 点阵组成。每个 LED 点可以控制亮灭,通过对每个点的亮灭状态的控制,可以在屏幕上显示出各种图案和文字等信息。

这个 8x8 点阵的原理,其实与数码管是一样的。看看下面的原理图就知道了。

从图中可以看出,LED 点阵屏由 64 个发光二极管组成,且每个发光二极管是放置在行线和列线的交叉点上,当对应的某一列置 1 电平,某一行置 0 电平,则相应的二极管就亮,我们这款点阵屏是共阴型的,共阳型则相反,给列置 0 电平,给行置 1 电平。

直接使用 I/O 口驱动,占用较多的 I/O 口资源,特别是随着点阵屏的数量增加,所以一般的应用,会选择专用的驱动芯片,例如 74HC595,MAX7219 等等。

硬件电路设计

物料清单(BOM 表):

材料名称数量
PS2 摇杆模块1
8*8 LED 点阵屏1
杜邦线(跳线)若干

PS2 模块的 +5V 引脚接 ESP32 的 3V3 引脚,GND 接 GND,SW 接 D34,X 接 D15,Y 接 D35。

LED 点阵屏的 1-8 分别接 D23、D22、D21、D19、D18、D5、D4、D2;9 - 16 分别接 D13、D12、D14、D27、D26、D25、D33、D32。

软件程序设计

1. 循环遍历所有 LED

我们第一个程序就先写检测一下是否所有的 LED 都可以正常工作,代码如下:

// 定义行引脚数组
int row_array[8] = {13, 25, 2, 27, 23, 4, 22, 18};
// 定义列引脚数组
int col_array[8] = {26, 21, 19, 12, 5, 14, 33, 32};


void setup() {
  // 配置所有行引脚为输出模式,初始化为高电平
  for (int i=0;i<8;i++) {
    pinMode(row_array[i], OUTPUT);
    digitalWrite(row_array[i], HIGH);
    }

  // 配置所有列引脚为输出模式,初始化为低电平
  for (int i=0;i<8;i++) {
    pinMode(col_array[i], OUTPUT);
    digitalWrite(col_array[i], LOW);
    }

}

void loop() {
  // 遍历所有的 LED
  for (int i=0;i<8;i++) {
    digitalWrite(row_array[i], LOW);

    for (int j=0;j<8;j++) {
      digitalWrite(col_array[j], HIGH);
      delay(100);
      digitalWrite(col_array[j], LOW);
      }
    digitalWrite(row_array[i], HIGH);
    }
}

2. 在点阵屏上显示图案

这里我们需要再次用到取模软件,与之前不同的是,这里我们需要新建图像并且,设置图像的宽和高为 8,这样就能保证与我们的点阵屏对应。

字模设置也需要改一下,

接着在屏幕上画出我们想要显示的图案,比如一个爱心,然后生成字模。

这里,我们获取了一个 8 个 16 进制数的列表,每个 16 进制数转换成二进制就是 LED 点阵屏每行所有 LED 的逻辑,

{0x00,0x66,0xFF,0xFF,0xFF,0x7E,0x3C,0x18}

在 Arduino 中,想要把 16 进制数转二进制时,可以使用 bitRead() 函数,该函数在单片机中使用时比较频繁的,尤其对于数码管以及与数码管类似的存在未操作的器件中使用较多。这里我们介绍一下它的使用方法。

bitRead(x, n)

参数说明:

  • x: 被读取位的数值;
  • n: 被读取的位置(右起第一位为 0 位,第二位为 1,以此类推。)
  • 返回值:1 或 0。

因此,我们的代码可以这么写:

// 定义行引脚数组
int row_array[8] = {13, 25, 2, 27, 23, 4, 22, 18};
// 定义列引脚数组
int col_array[8] = {26, 21, 19, 12, 5, 14, 33, 32};

// 定义图案逻辑数组
int hex_array[8] = {0x00,0x66,0xFF,0xFF,0xFF,0x7E,0x3C,0x18};


void setup() {

  // 设置串口波特率
  Serial.begin(9600);

  
  // 配置所有行引脚为输出模式,初始化为高电平
  for (int i=0;i<8;i++) {
    pinMode(row_array[i], OUTPUT);
    digitalWrite(row_array[i], HIGH);
    }

  // 配置所有列引脚为输出模式,初始化为低电平
  for (int i=0;i<8;i++) {
    pinMode(col_array[i], OUTPUT);
    digitalWrite(col_array[i], LOW);
    }
}


void loop() {
  for (int i=0;i<8;i++) {
      for (int j=0;j<8;j++) {
        digitalWrite(col_array[j], bitRead(hex_array[i], j));
      }
      digitalWrite(row_array[i], LOW);
      delay(1);
      digitalWrite(row_array[i], HIGH);
  }
}

3. 使用 PS2 摇杆控制 LED 移动

最后,我们就可以写摇杆控制 LED移动的代码了:

#define PS2_X   15
#define PS2_Y   35


// 定义行引脚数组
int row_array[8] = {13, 25, 2, 27, 23, 4, 22, 18};
// 定义列引脚数组
int col_array[8] = {26, 21, 19, 12, 5, 14, 33, 32};

// 初始化 LED 位置
int led_pos[2] = {1, 1};

// 初始化摇杆信号变量
int x_value;
int y_value;


void setup() {
  // 配置 PS2 摇杆引脚
  pinMode(PS2_X, INPUT);
  pinMode(PS2_Y, INPUT);
  
  // 配置所有行引脚为输出模式,初始化为高电平
  for (int i=0;i<8;i++) {
    pinMode(row_array[i], OUTPUT);
    digitalWrite(row_array[i], HIGH);
    }

  // 配置所有列引脚为输出模式,初始化为低电平
  for (int i=0;i<8;i++) {
    pinMode(col_array[i], OUTPUT);
    digitalWrite(col_array[i], LOW);
    }

}


void loop() {
  // 读取摇杆信号
  x_value = analogRead(PS2_X);
  y_value = analogRead(PS2_Y);

  // 清除 LED 之前的状态
  digitalWrite(row_array[led_pos[0]], HIGH);
  digitalWrite(col_array[led_pos[1]], LOW);

  // 检测 x 轴是否移动
  if (x_value > 4095 / 2 + 300 && led_pos[0] < 7) {
    led_pos[0] += 1;
  }else if (x_value < 4095 / 2 - 300 && led_pos[0] > 0) {
    led_pos[0] -= 1;
  }

  // 检测 y 轴是否移动
  if (y_value > 4095 / 2 + 300 && led_pos[1] > 0) {
    led_pos[1] -= 1;  
  }else if (y_value < 4095 / 2 -300 && led_pos[1] < 7) {
    led_pos[1] += 1;  
  }

  // 显示新位置的 LED
  digitalWrite(row_array[led_pos[0]], LOW);
  digitalWrite(col_array[led_pos[1]], HIGH);

  delay(50);
}
上次编辑于:
贡献者: Luo