材料
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, // 0B01100000, // 1B11011010, // 2B11110010, // 3B01100110, // 4B10110110, // 5B10111110, // 6B11100000, // 7B11111110, // 8B11110110 // 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 displayfor (int d = 0; d < 4; d++) {digitalWrite(digitPins[d], LOW); // enable digit// set segmentsfor (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 1else 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 continuouslydisplayVoltage(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, // 0B01100000, // 1B11011010, // 2B11110010, // 3B01100110, // 4B10110110, // 5B10111110, // 6B11100000, // 7B11111110, // 8B11110110 // 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 displayfor (int d = 0; d < 4; d++){digitalWrite(digitPins[d], LOW); // enable digit// set segmentsfor (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 1elsedigitalWrite(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 continuouslydisplayVoltage(result);
}
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, // 0B01100000, // 1B11011010, // 2B11110010, // 3B01100110, // 4B10110110, // 5B10111110, // 6B11100000, // 7B11111110, // 8B11110110 // 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 displayfor (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_displayShockvoid 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);
}
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。