Arduino+数码管 = 量电压 | A+B problem | alphabet

材料

Arduino UNO R3、8041AS 七位数码管、若干导线、电阻、电位器、按钮、面包板。

量电压

A0 读入电压值,然后显示到数码管上即可。

voltage-display.ino
// https://www.lanpade.com/7-segment-led-dot-matrix/8041as.html

// === Pin Definitions ===
// Segments (a,b,c,d,e,f,g,dp) -> Arduino digital pins
const int segPins[8] = {3, 7, 11, 9, 8, 4, 12, 10};
// Digits (D1–D4, common cathode) -> Arduino pins
const int digitPins[4] = {2, 5, 6, 13};

// Segment map for numbers 0–9 (abcdefg, dp separate)
const byte numbers[10] = {
  B11111100, // 0
  B01100000, // 1
  B11011010, // 2
  B11110010, // 3
  B01100110, // 4
  B10110110, // 5
  B10111110, // 6
  B11100000, // 7
  B11111110, // 8
  B11110110  // 9
};

float voltage = 0.0; // measured voltage

// === Functions ===
void displayVoltage(float val) {
  // Scale value: 0.000–5.000 -> up to 5000 (int)
  int scaled = (int)(val * 1000);

  int digits[4];
  for (int i = 3; i >= 0; i--) {
    digits[i] = scaled % 10;
    scaled /= 10;
  }

  // Multiplex display
  for (int d = 0; d < 4; d++) {
    digitalWrite(digitPins[d], LOW); // enable digit

    // set segments
    for (int s = 0; s < 8; s++) {
      bool on = bitRead(numbers[digits[d]], 7 - s);
      digitalWrite(segPins[s], on ? HIGH : LOW);
    }

    // Add decimal point after first digit (x.xxx)
    if (d == 0) digitalWrite(segPins[7], HIGH); // dp ON for digit 1
    else digitalWrite(segPins[7], LOW);

    delay(3);
    digitalWrite(digitPins[d], HIGH); // disable digit
  }
}

void setup() {
  for (int i = 0; i < 8; i++) pinMode(segPins[i], OUTPUT);
  for (int i = 0; i < 4; i++) {
    pinMode(digitPins[i], OUTPUT);
    digitalWrite(digitPins[i], HIGH); // all off initially
  }
}

void loop() {
  // Read analog input (0–5V → 0–1023)
  int adcValue = analogRead(A0);
  voltage = (adcValue * 5.0) / 1023.0;

  // Refresh display continuously
  displayVoltage(voltage);
}

可以进一步地,输出到 Serial,并取最近 \(10\) 次结果取平均值,以稳定测量结果。

voltage-display.ino
// https://www.lanpade.com/7-segment-led-dot-matrix/8041as.html

// === Pin Definitions ===
// Segments (a,b,c,d,e,f,g,dp) -> Arduino digital pins
const int segPins[8] = {3, 7, 11, 9, 8, 4, 12, 10};
// Digits (D1–D4, common cathode) -> Arduino pins
const int digitPins[4] = {2, 5, 6, 13};

// Segment map for numbers 0–9 (abcdefg, dp separate)
const byte numbers[10] = {
  B11111100, // 0
  B01100000, // 1
  B11011010, // 2
  B11110010, // 3
  B01100110, // 4
  B10110110, // 5
  B10111110, // 6
  B11100000, // 7
  B11111110, // 8
  B11110110  // 9
};

// === Functions ===
void displayVoltage(float val)
{
  // Scale value: 0.000–5.000 -> up to 5000 (int)
  int scaled = (int)(val * 1000);

  int digits[4];
  for (int i = 3; i >= 0; i--)
  {
    digits[i] = scaled % 10;
    scaled /= 10;
  }

  // Multiplex display
  for (int d = 0; d < 4; d++)
  {
    digitalWrite(digitPins[d], LOW); // enable digit

    // set segments
    for (int s = 0; s < 8; s++)
    {
      bool on = bitRead(numbers[digits[d]], 7 - s);
      digitalWrite(segPins[s], on ? HIGH : LOW);
    }

    // Add decimal point after first digit (x.xxx)
    if (d == 0)
      digitalWrite(segPins[7], HIGH); // dp ON for digit 1
    else
      digitalWrite(segPins[7], LOW);

    delay(3);
    digitalWrite(digitPins[d], HIGH); // disable digit
  }
}

const int NUM_SAMPLES = 10;
int samples[NUM_SAMPLES];
int sampleIndex = 0;
bool bufferFilled = false;

void setup()
{
  for (int i = 0; i < 8; i++)
    pinMode(segPins[i], OUTPUT);
  for (int i = 0; i < 4; i++)
  {
    pinMode(digitPins[i], OUTPUT);
    digitalWrite(digitPins[i], HIGH); // all off initially
  }
  pinMode(A0, INPUT);
  Serial.begin(115200);
  for (int i = 0; i < NUM_SAMPLES; i++)
  {
    samples[i] = 0;
  }
}

void loop()
{
  // Read analog input (0–5V → 0–1023)
  int adcValue = analogRead(A0);

  samples[sampleIndex] = adcValue;
  sampleIndex++;
  if (sampleIndex >= NUM_SAMPLES)
  {
    sampleIndex = 0;
    bufferFilled = true;
  }

  float result = 0.0;
  int total = bufferFilled ? NUM_SAMPLES : sampleIndex;
  for (int i = 0; i < total; i++)
  {
    result += samples[i];
  }
  result *= 5. / 1023.;
  result /= total;

  Serial.print("Sensor reading: ");
  Serial.print(adcValue);
  Serial.print(" Voltage: ");
  Serial.print((float)adcValue * 5. / 1023., 3);
  Serial.print(" Average: ");
  Serial.println(result, 3);

  // Refresh display continuously
  displayVoltage(result);
}

voltage-display

A+B problem

让我们先把操作数码管的代码简单封装一下,可以得到以下并不标准的 segment.cpp

segment.cpp
#ifndef SEGMENT_H_
#define SEGMENT_H_

// https://www.lanpade.com/7-segment-led-dot-matrix/8041as.html

// === Pin Definitions ===
// Segments (a,b,c,d,e,f,g,dp) -> Arduino digital pins
const int segPins[8] = { 3, 7, 11, 9, 8, 4, 12, 10 };
// Digits (D1–D4, common cathode) -> Arduino pins
const int digitPins[4] = { 2, 5, 6, 13 };

// Segment map for numbers 0–9 (abcdefg, dp separate)
const byte numbers[10] = {
  B11111100,  // 0
  B01100000,  // 1
  B11011010,  // 2
  B11110010,  // 3
  B01100110,  // 4
  B10110110,  // 5
  B10111110,  // 6
  B11100000,  // 7
  B11111110,  // 8
  B11110110   // 9
};
// Segment map for alphas a-z
const unsigned char alphas[26] = {
  0xee, 0x3e, 0x9c, 0x7a, 0x9e, 0x8e, 0xbc, 0x6e, 0xf0, 0x70,
  0xae, 0x1c, 0xec, 0x2a, 0x3a, 0xce, 0xe6, 0x8c, 0x92, 0x1e,
  0x7c, 0x38, 0x7e, 0x26, 0x76, 0x5a
};

const unsigned long stayMillis = 3;
const unsigned long BATCHMILLIS = 500;  // time for show four characters
const int strBufSize = 256;

const int shockShowMillis = 200;
const int shockHideMillis = 200;

byte getPattern(char c, bool dp) {
  byte pattern = 0;
  if (c >= '0' && c <= '9') {
    pattern = numbers[c - '0'];
  } else if (c >= 'A' && c <= 'Z') {
    pattern = alphas[c - 'A'];
  } else if (c >= 'a' && c <= 'z') {
    pattern = alphas[c - 'a'];
  }
  if (dp) {
    pattern |= B00000001;
  }
  return pattern;
}

void showSingle(byte pattern, int digit) {
  if (!pattern) {
    delay(stayMillis);
    return;
  }
  digitalWrite(digitPins[digit], LOW);
  for (int i = 0; i < 8; i++) {
    digitalWrite(segPins[i], bitRead(pattern, 7 - i));
  }
  delay(stayMillis);
  digitalWrite(digitPins[digit], HIGH);
}

int initStrDP(const char *str, const bool *DP, char *strBuf, bool *dpBuf) {
  int bufLen = 0, strLen = strlen(str);
  for (int i = 0; i < strLen; i++) {
    if (str[i] == '.') {
      if (bufLen > 0 && !dpBuf[bufLen - 1]) {
        dpBuf[bufLen - 1] = true;
      } else {
        strBuf[bufLen] = ' ';
        dpBuf[bufLen] = true;
        bufLen++;
      }
    } else {
      strBuf[bufLen] = str[i];
      dpBuf[bufLen] = DP != NULL ? DP[i] : false;
      bufLen++;
    }
  }
  strBuf[bufLen] = '\0';
  return bufLen;
}

struct displayLoopStateNode {
  char strBuf[strBufSize];
  bool dpBuf[strBufSize];
  int bufLen;

  unsigned long totalMillis;
  unsigned long batchMillis;
  unsigned long start;
  unsigned long startBatch;

  int currentRound;
  int totalRounds;

  bool active;
} _displayLoopState;

void displayLoopTaskInit(const char *str, const bool *DP = NULL, unsigned long totalMillis = 1000, unsigned long batchMillis = BATCHMILLIS) {
  int strLen = strlen(str);
  if (str == NULL || strLen == 0) return;
  _displayLoopState.bufLen = initStrDP(str, DP, _displayLoopState.strBuf, _displayLoopState.dpBuf);

  _displayLoopState.totalRounds = _displayLoopState.bufLen + 4;
  _displayLoopState.batchMillis = batchMillis;
  _displayLoopState.totalMillis = totalMillis;
  unsigned long requiredTotal = _displayLoopState.totalRounds * batchMillis;
  if (requiredTotal > totalMillis) {
    _displayLoopState.batchMillis = totalMillis / _displayLoopState.totalRounds;
  }

  _displayLoopState.start = millis();
  _displayLoopState.startBatch = _displayLoopState.start;
  _displayLoopState.currentRound = 0;

  _displayLoopState.active = true;
}

// return a bool, false for task ended
bool displayLoopTaskUpdate() {
  if (!_displayLoopState.active) {
    return false;
  }
  if (millis() - _displayLoopState.start >= _displayLoopState.totalMillis) {
    _displayLoopState.active = false;
    return false;
  }
  for (int digit = 0; digit < 4; digit++) {
    int charPos = _displayLoopState.currentRound - 3 + digit;
    char displayChar = ' ';
    bool displayDP = false;
    if (0 <= charPos && charPos < _displayLoopState.bufLen) {
      displayChar = _displayLoopState.strBuf[charPos];
      displayDP = _displayLoopState.dpBuf[charPos];
    }
    byte pattern = getPattern(displayChar, displayDP);
    showSingle(pattern, digit);
  }
  unsigned long currentTime = millis();
  while (currentTime - _displayLoopState.startBatch >= (_displayLoopState.currentRound + 1) * _displayLoopState.batchMillis) {
    _displayLoopState.currentRound++;
    if (_displayLoopState.currentRound >= _displayLoopState.totalRounds) {
      _displayLoopState.currentRound = 0;
      _displayLoopState.startBatch = currentTime;
    }
  }
  return true;
}

/**
 * 在四位数码管上滚动显示字符串
 * @param str 要显示的字符串
 * @param DP 小数点控制数组,与 str 等长
 * @param totalMillis 总显示时间(毫秒)
 * @param batchMillis 每四个字符的显示时间(毫秒)
 */
void displayLoop(const char *str, const bool *DP = NULL, unsigned long totalMillis = 1000, unsigned long batchMillis = BATCHMILLIS) {
  displayLoopTaskInit(str, DP, totalMillis, batchMillis);
  while (!displayLoopTaskUpdate())
    continue;
}

void display(int value, unsigned int DP = B0000) {
  int digits[4];
  for (int i = 3; i >= 0; i--) {
    digits[i] = value % 10;
    value /= 10;
  }
  // Multiplex display
  for (int d = 0; d < 4; d++) {
    byte pattern = getPattern('0' + digits[d], DP & B1 << d ? true : false);
    showSingle(pattern, d);
  }
}

void display(const char* str, unsigned DP = B0000) {
  for (int d = 0; d < 4; d++) {
    byte pattern = getPattern(str[d], DP & B1 << d ? true : false);
    showSingle(pattern, d);
  }
}

#define __define_displayForMillis(TYPE) \
  void displayForMillis(TYPE value, unsigned int DP = B0000, unsigned long millisCount = 1000) { \
    unsigned long start = millis(); \
    while (millis() - start < millisCount) { \
      display(value, DP); \
    } \
  }
__define_displayForMillis(int)
__define_displayForMillis(const char*)
#undef __define_displayForMillis

#define __define_displayShock(TYPE) \
  void displayShock(TYPE value, unsigned int DP = B0000, unsigned long millisCount = 1000) { \
    unsigned long start = millis(); \
    while (millis() - start < millisCount) { \
      displayForMillis(value, DP, min(millisCount - (millis() - start), shockShowMillis)); \
      delay(shockHideMillis); \
    } \
  }
__define_displayShock(int)
__define_displayShock(const char*)
#undef __define_displayShock

void segmentInit() {
  for (int i = 0; i < 8; i++)
    pinMode(segPins[i], OUTPUT);
  for (int i = 0; i < 4; i++) {
    pinMode(digitPins[i], OUTPUT);
    digitalWrite(digitPins[i], HIGH);  // all off initially
  }
}

#endif

于是可以方便地写出如下程序:

aplusb.ino
#include "include/segment.cpp"

const int inputScale = 5;
const int inputPin = A0;
const int buttonPin = A1;

int readInt() {
  while (true) {
    int raw = analogRead(inputPin);
    int value = raw / inputScale;
    display(value);
    if (digitalRead(buttonPin) == HIGH) {
      displayForMillis(value, 0, 20);
      while (digitalRead(buttonPin) == HIGH) {
        display(value);
      }
      displayShock(value);
      return value;
    }
  }
}

void setup() {
  segmentInit();
  pinMode(inputPin, INPUT);
  pinMode(buttonPin, INPUT);
  Serial.begin(115200);
}

void SerialPrintf(const char *fmt, ...) {
  char buf[128];
  va_list args;
  va_start(args, fmt);
  vsnprintf(buf, sizeof(buf), fmt, args);
  va_end(args);
  Serial.print(buf);
}

void loop() {
  int a = readInt();
  SerialPrintf("Read a = %d\n", a);
  int b = readInt();
  SerialPrintf("Read b = %d\n", b);
  int sum = a + b;
  SerialPrintf("%d + %d = %d\n", a, b, sum);
  displayForMillis(sum, B0111, 5000);
}

aplusb

alphabet

我们已经封装好了,直接用就行了。

alphabet.ino
#include "include/segment.cpp"

void setup() {
  segmentInit();
  displayLoop(".0123456789.A...BCDEFGHIJKLMNOPQRSTUVWXYZ", NULL, 5000);
  displayLoop("520", NULL, 5000);
  displayLoop("520 1314", NULL, 8000);
  displayLoop("i love you", NULL, 8000);
  displayForMillis(" ADD", 0, 1000);
  displayShock("F  K", 0, 3000);
  displayLoopTaskInit("F  K YOU", NULL, 5000);
}

void loop() {
  if (digitalRead(A1) == HIGH) {
    while (digitalRead(A1) == HIGH)
      continue;
    displayShock("F  K", 0, 3000);
  }
  if (!displayLoopTaskUpdate()) {
    displayLoopTaskInit("F  K ME. PLEASE", NULL, 5000);
  }
}

接线同 aplusb。

posted @ 2025-10-04 10:43  XuYueming  阅读(19)  评论(0)    收藏  举报