// https://forum.arduino.cc/t/uno-nano-r3-servo-7seg-digit/1441460
// Mechanical, single-digit, seven-segment display.
// Each segment is attached to a servo by an arm
// See bottom of code for MUXED servos
#include <FastLED.h> // https://github.com/FastLED/FastLED
#define NUMPIX 21 // 3pix x 7seg
#define DATAPIN 10 //
#define MAXBRIGHT 255 // adjust
CRGB led[NUMPIX]; // create WS2812B object
#include <Servo.h> // https://github.com/arduino-libraries/Servo
#define SEGMENTS 7 // one servo per segment
Servo servo[SEGMENTS]; // seven servos
int armup = 0, armdown = 90; // servo horn positions
byte count; // case counter
unsigned long timer; // time digit change
enum segs { sega, segb, segc, segd, sege, segf, segg
}; // enumerated segments for calling their servo-pin number
byte srvpin[] = { 2, 8, 6, 5, 4, 3, 7 }; // pins for seg a, b, c, d, e, f, g
/*
SEGMENTS attached to SERVOS by non-interfering ARMS.
- START SEGMENTS (segments in current digit)
- KEEP SEGMENTS (will be used in next digit)
- REMOVE SEGMENTS (will not be used in next digit)
- ADD SEGMENTS (will be added to next digit)
. _____
+--------/--a \
| /\\_____//\
| | | | |
| +---|-f| |b-|-----+
| | | |_____| | |
| | \// g--\\/----+ |
| | /\\_____//\ | |
| | | | | | | |
| | +-|-e| |c-|-+ | |
| | | | |_____| | | | |
| | | \// d \\/ | | |
| | | \__ __/ | | |
| | | | | | |
+ + + + + + +
a f e d c g b <- SEGMENT SERVOS
WS2812B GRN - Kept segment (armup)
WS2812B RED - Removed segment (armdown)
WS2812B BLU - Added segment (armup)
. _____
/ a \ leda 0, 1, 2
/\\_____//\
| | | | ledb 3, 4, 5
| f| |b | ledf 6, 7, 8
| |_____| |
\// g \\/ ledg 9, 10, 11
/\\_____//\
| | | | ledc 12, 13, 14
| e| |c | lede 15, 16, 17
| |_____| |
\// d \\/ ledd 18, 19, 20
\_____/
*/
void setup() {
Serial.begin(115200);
FastLED.addLeds<WS2812B, DATAPIN, GRB>(led, NUMPIX);
FastLED.setBrightness(MAXBRIGHT);
FastLED.clear();
FastLED.show();
for (byte i = 0; i < SEGMENTS; i++) {
servo[i].write(armdown); // configure arms "down"
servo[i].attach(srvpin[i]); // servos 0 - 6 attached to servo pins
}
delay(1000); // settle servos
// test(); // cycle through segment servos and WS2812B
zero(); // starting number
delay(820); // 180ms to move servos 90 degrees
}
void loop() {
unsigned long servotimeout = 820; // 1000ms/second - 180ms/servomove = 820ms
if (millis() - timer > servotimeout) {
timer = millis(); // set new timer
FastLED.clear();
FastLED.show();
if (count > 9) // upper bounds reached...
count = 0; // reset value
switch (count) { // transition digits
case 0: zro_one(); break;
case 1: one_two(); break;
case 2: two_tre(); break;
case 3: tre_for(); break;
case 4: for_fiv(); break;
case 5: fiv_six(); break;
case 6: six_svn(); break;
case 7: svn_eit(); break;
case 8: eit_nin(); break;
case 9: nin_zro(); break;
default: break;
}
count++; // increase digit count
}
}
void keepseg(byte seg) {
// servo[seg.write(); // No servo in keepseg();
for (int j = 0; j < 3; j++) { // only show in WS2812B
led[seg * 3 + j] = CRGB(128, 255, 255); // blu segment of three WS2812B
}
FastLED.show(); // show buffer
}
void addseg(byte seg) {
servo[seg].write(armup);
for (int j = 0; j < 3; j++) {
led[seg * 3 + j] = CRGB(128, 255, 128); // grn
}
FastLED.show();
}
void remseg(byte seg) {
servo[seg].write(armdown);
for (int j = 0; j < 3; j++) {
led[seg * 3 + j] = CRGB(191, 64, 64); // red
}
FastLED.show();
}
void zero() {
for (byte i = 0; i < 6; i++) { // SEGMENTS minus SEG G
addseg(i); // call "add segment"
}
}
void zro_one() { // changing from ZERO to ONE...
keepseg(segb); keepseg(segc); // keep SEG B and C
remseg(sega); remseg(segd); remseg(sege); remseg(segf); // remove SEG A, D, E, and F
// addseg(); // no addseg()
}
void one_two() { // change from ONE to TWO
keepseg(segb);
remseg(segc);
addseg(sega); addseg(segd); addseg(sege); addseg(segg); // add SEG A, D, E, and G
}
void two_tre() {
keepseg(sega); keepseg(segb); keepseg(segd); keepseg(segg);
remseg(sege);
addseg(segc);
}
void tre_for() {
keepseg(segb); keepseg(segc); keepseg(segg);
remseg(sega); remseg(segd);
addseg(segf);
}
void for_fiv() {
keepseg(segf); keepseg(segc); keepseg(segg);
remseg(segb);
addseg(sega); addseg(segd);
}
void fiv_six() {
keepseg(segc); keepseg(segd); keepseg(segf); keepseg(segg);
remseg(sega);
addseg(sege);
}
void six_svn() {
keepseg(segc);
remseg(segd); remseg(sege); remseg(segf); remseg(segg);
addseg(sega); addseg(segb);
}
void svn_eit() {
keepseg(sega); keepseg(segb); keepseg(segc);
// remseg(); // none
addseg(segd); addseg(sege); addseg(segf); addseg(segg);
}
void eit_nin() {
keepseg(sega); keepseg(segb); keepseg(segc); keepseg(segf); keepseg(segg);
remseg(segd); remseg(sege);
// addseg(); // none
}
void nin_zro() {
keepseg(sega); keepseg(segb); keepseg(segc); keepseg(segf);
remseg(segg);
addseg(segd); addseg(sege);
}
void test() { // cycle through servo/WS2812 segments
int servo90degrees = 180; // milliseconds for 90 degree servo move
for (int i = 0; i < SEGMENTS; i++) { // number of segments
for (int j = 0; j < 3; j++) { // three WS2812 per segment
led[i * 3 + j] = CRGB(0, 0, 255); // blu loaded to buffer
}
FastLED.show(); // display buffer
FastLED.clear(); // clear buffer
servo[i].write(armup); // move servo UP
delay(servo90degrees); // servo takes 2ms per degree to move. 90deg * 2ms/deg = 180ms
servo[i].write(armdown); // move servo DOWN
delay(servo90degrees);
}
FastLED.show();
}
/*
- NEXT to do:
- Four digits
- RTC (clock with "blinking" colon)
- two PCAS9685 (16 channel PWM mux, daisy-chained, two "digits" per mux)
- https://github.com/NachtRaveVL/PCA9685-Arduino
- keep track of which of ten digit (0..9) is in each of four positions (HH:MM)
- 12vdc power supply for Arduino VIN
- 5V/5A BEC/buck converter for SERVOES and first PCA9685A
- Not as genius as this cam-driven model: https://hackaday.io/project/187684-eptaora
*/GRN - KEPT SEG
RED - REMOVED SEG
BLU - ADDED SEG
BLK - UNCHANGED
a
f
e
d
c
g
b
EACH SERVO HORN
IS ATTACHED TO A
ROD (Ø1mm) THEN TO A
"SEGMENT" (see code)