ESP32 for Arduino 学习笔记:数码管显示与数组应用

一、数码管基础控制

1.1 数码管引脚定义与显示原理

数码管通过多个LED段的亮灭组合显示数字,通常包含a、b、c、d、e、f、g七个段和一个小数点dp,共8个引脚。根据公共端的连接方式,分为共阳极(公共端接高电平,低电平点亮LED)和共阴极(公共端接低电平,高电平点亮LED)两种。

1.2 基础控制代码示例

// 定义数码管各段对应的ESP32引脚
const int aPin = 2;   // a段接引脚2
const int bPin = 3;   // b段接引脚3
const int cPin = 4;   // c段接引脚4
const int dPin = 5;   // d段接引脚5
const int ePin = 6;   // e段接引脚6
const int fPin = 7;   // f段接引脚7
const int gPin = 8;   // g段接引脚8
const int dpPin = 9;  // 小数点接引脚9

// 显示数字0(共阳极数码管:1=灭,0=亮)
void disNum0() {
  digitalWrite(aPin, 0);  // a亮
  digitalWrite(bPin, 0);  // b亮
  digitalWrite(cPin, 0);  // c亮
  digitalWrite(dPin, 0);  // d亮
  digitalWrite(ePin, 0);  // e亮
  digitalWrite(fPin, 0);  // f亮
  digitalWrite(gPin, 1);  // g灭
  digitalWrite(dpPin, 1); // 小数点灭
}

// 显示数字1(共阳极数码管)
void disNum1() {
  digitalWrite(aPin, 1);  // a灭
  digitalWrite(bPin, 0);  // b亮
  digitalWrite(cPin, 0);  // c亮
  digitalWrite(dPin, 1);  // d灭
  digitalWrite(ePin, 1);  // e灭
  digitalWrite(fPin, 1);  // f灭
  digitalWrite(gPin, 1);  // g灭
  digitalWrite(dpPin, 1); // 小数点灭
}

void setup() {
  // 将2-9号引脚设置为输出模式(控制数码管)
  for (int i = 2; i <= 9; i++) {
    pinMode(i, OUTPUT);
  }
}

void loop() {
  disNum0();   // 显示0
  delay(1000); // 停留1秒
  disNum1();   // 显示1
  delay(1000); // 停留1秒
}

二、数组的应用

2.1 为什么需要数组?

当控制多个同类型元素(如数码管的8个引脚)时,逐个定义变量会导致代码冗余。数组可以将一组相同类型的数据用一个名称管理,简化重复操作。

2.2 一维数组

定义与初始化

// 定义一个包含8个整数的数组,存储数码管引脚
int pinArray[8] = {2, 3, 4, 5, 6, 7, 8, 9}; 
// 下标从0开始:pinArray[0]=2(a段引脚),pinArray[1]=3(b段引脚)...pinArray[7]=9(dp段引脚)

一维数组控制数码管引脚示例

// 数码管引脚数组(a,b,c,d,e,f,g,dp对应的ESP32引脚)
int pinArray[8] = {2, 3, 4, 5, 6, 7, 8, 9};

void setup() {
  // 用循环初始化所有引脚为输出模式(替代逐个pinMode)
  for (int i = 0; i < 8; i++) { 
    pinMode(pinArray[i], OUTPUT);
  }
}

void loop() {
  // 循环控制各段闪烁(跑马灯效果)
  for (int i = 0; i < 7; i++) { // 跳过dp段(下标7)
    digitalWrite(pinArray[i], LOW);  // 点亮当前段(共阳极)
    delay(150);
    digitalWrite(pinArray[i], HIGH); // 熄灭当前段
  }
}

2.3 二维数组

定义与初始化

二维数组可以理解为“数组的数组”,适合存储多行多列的数据(如不同数字对应的各段亮灭状态)。

// 定义二维数组:存储10个数字+1个小数点的各段状态(共阴极:1=亮,0=灭)
const byte disNum[11][8] = {
  {1,1,1,1,1,1,0,0}, // 0:a,b,c,d,e,f亮;g,dp灭
  {0,1,1,0,0,0,0,0}, // 1:b,c亮;其他灭
  {1,1,0,1,1,0,1,0}, // 2
  {1,1,1,1,0,0,1,0}, // 3
  {0,1,1,0,0,1,1,0}, // 4
  {1,0,1,1,0,1,1,0}, // 5
  {1,0,1,1,1,1,1,0}, // 6
  {1,1,1,0,0,0,0,0}, // 7
  {1,1,1,1,1,1,1,0}, // 8
  {1,1,1,1,0,1,1,0}, // 9
  {0,0,0,0,0,0,0,1}  // 小数点:仅dp亮
};

二维数组控制数码管显示示例

// 数码管引脚数组(a,b,c,d,e,f,g,dp)
const int pinArray[8] = {2, 3, 4, 5, 6, 7, 8, 9};

// 各数字对应的段状态(共阴极)
const byte disNum[11][8] = {
  {1,1,1,1,1,1,0,0}, // 0
  {0,1,1,0,0,0,0,0}, // 1
  {1,1,0,1,1,0,1,0}, // 2
  {1,1,1,1,0,0,1,0}, // 3
  {0,1,1,0,0,1,1,0}, // 4
  {1,0,1,1,0,1,1,0}, // 5
  {1,0,1,1,1,1,1,0}, // 6
  {1,1,1,0,0,0,0,0}, // 7
  {1,1,1,1,1,1,1,0}, // 8
  {1,1,1,1,0,1,1,0}, // 9
  {0,0,0,0,0,0,0,1}  // .
};

void setup() {
  // 初始化所有引脚为输出
  for (int i = 0; i < 8; i++) {
    pinMode(pinArray[i], OUTPUT);
  }
}

// 显示指定数字的函数
void disPlayNum(int num, int delayTime) {
  for (int i = 0; i < 8; i++) {
    // 共阳极需取反(!):将共阴极的1转为0(亮),0转为1(灭)
    digitalWrite(pinArray[i], !disNum[num][i]); 
  }
  delay(delayTime); // 维持显示时间
}

void loop() {
  // 循环显示0-9,每个数字停留500ms
  for (int i = 0; i < 10; i++) {
    disPlayNum(i, 500);
  }
}

三、节省IO口:74HC595移位寄存器

3.1 为什么需要移位寄存器?

直接控制数码管需要8个IO口,若使用多位数码管,IO口会不够用。74HC595 移位寄存器可通过3个IO口控制8位并行输出,节省硬件资源。

3.2 74HC595工作原理

  • 串行输入:通过DS(数据)、SHCP(移位时钟)将数据逐位传入内部寄存器。
  • 并行输出:通过STCP(存储时钟)将内部寄存器的数据一次性输出到8个引脚。
  • 级联扩展:多个74HC595可级联,实现更多位输出(如控制多位数码管)。

四、常用数码管模块推荐

模块型号 特点 价格 适用场景
TM1637 4位数码管 仅需2个IO口,支持亮度调节 ¥4.1 时钟、计数器
MAX7219 8位数码管 3个IO口控制,支持级联 ¥2.73 多位数字显示(如计分板)
TM1650 4位数码管 I2C接口,接线简单 ¥5.5 小型设备显示

五、总结

  1. 数组简化代码:一维数组管理引脚,二维数组存储数字状态,减少重复代码。
  2. 灵活控制显示:通过循环和函数调用,轻松实现数字切换、闪烁等效果。
  3. 节省硬件资源:使用74HC595或专用驱动模块(如TM1637),解决IO口不足问题。

通过以上内容,可掌握从基础数码管控制到数组应用,再到硬件优化的完整流程,为后续复杂项目(如时钟、温湿度显示器)打下基础。

0 条评论

目前还没有评论...