Skip to content

Inconsistent LED colors #24

@NegativCut

Description

@NegativCut

Hi, I have six exixe-12 boards sharing the same bus (clock) and I am writing the same LED color codes to each but I get different colors on three of them.
Three of them are correct, no.1, 5 and 6 on the bus.
2,3 & 4 show different colors.
The components have been tested individually and work just fine and consistently.
Everything else is working okay (digits displaying and animation working).
Could this be a timing issue? I have added a delay of 50ms after writing the LED values to each in the hope that would fix.
Do I need to init each exixe?

My code.

`#include "exixe.h"
#include "RTClib.h" // RealTimeClock Library for DS3231

RTC_DS3231 rtc;

// Define parameters for nixies
int cs1 = 10;
int cs2 = 9;
int cs3 = 8;
int cs4 = 7;
int cs5 = 6;
int cs6 = 5;
int brightness = 55;
int overdrive = 0;

// Nixie tube objects
exixe my_tube1 = exixe(cs1);
exixe my_tube2 = exixe(cs2);
exixe my_tube3 = exixe(cs3);
exixe my_tube4 = exixe(cs4);
exixe my_tube5 = exixe(cs5);
exixe my_tube6 = exixe(cs6);

// RGB LED values
int red = 50;
int green = 20;
int blue = 50;

// Rotary encoder pins
#define REA_PIN 2 // D2
#define REB_PIN 3 // D3
#define RESW_PIN A0 // Switch on A0

unsigned long previousMillis = 0;
const long interval = 55000; // interval to change to date display
unsigned long lastFrameTime = 0;
const int frameInterval = EXIXE_ANIMATION_FRAME_DURATION_MS; // 33ms per frame
unsigned long lastLedRefresh = 0;
const int ledRefreshInterval = 1000; // Refresh LEDs every 1s

// Track digits and mode
int prev_digits[6] = {-1, -1, -1, -1, -1, -1};
int target_digits[6] = {0, 0, 0, 0, 0, 0};
bool isDateMode = false;

// Set mode variables
enum SetMode { NORMAL, SET_HOURS, SET_MINUTES, SET_SECONDS, SET_DAY, SET_MONTH, SET_YEAR };
SetMode currentMode = NORMAL;
int setValues[6] = {0, 0, 0, 1, 1, 0}; // Hour, min, sec, day, month, year (last 2 digits)
unsigned long switchPressTime = 0;
bool switchPressed = false;
unsigned long lastBlinkTime = 0;
bool blinkState = true; // Start with tubes on

volatile int encoderPos = 0;

void setup() {
Serial.begin(9600);

if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}

DateTime now = rtc.now();
Serial.print("Current RTC time before check: ");
printTime(now);

const uint32_t MIN_VALID_TIME = 1704067200; // 2024-01-01
if (now.unixtime() < MIN_VALID_TIME) {
Serial.println("RTC time is invalid or too old, setting to compile time...");
rtc.adjust(DateTime(F(DATE), F(TIME)));
Serial.println("RTC initialized to compile time!");
now = rtc.now();
Serial.print("New RTC time: ");
printTime(now);
} else {
Serial.println("RTC time is valid, no adjustment needed.");
}

pinMode(RESW_PIN, INPUT_PULLUP);
pinMode(REA_PIN, INPUT_PULLUP);
pinMode(REB_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(REA_PIN), encoderISR, CHANGE);

Serial.print("Final RTC time at setup end: ");
printTime(rtc.now());

my_tube1.spi_init();
my_tube1.clear(); delay(10);
my_tube2.clear(); delay(10);
my_tube3.clear(); delay(10);
my_tube4.clear(); delay(10);
my_tube5.clear(); delay(10);
my_tube6.clear(); delay(10);

my_tube1.set_led(red, blue, green); delay(50);
my_tube2.set_led(red, blue, green); delay(50);
my_tube3.set_led(red, blue, green); delay(50);
my_tube4.set_led(red, blue, green); delay(50);
my_tube5.set_led(red, blue, green); delay(50);
my_tube6.set_led(red, blue, green); delay(50);
}

void loop() {
DateTime now = rtc.now();
unsigned long currentMillis = millis();

// Handle switch press
bool currentSwitchState = digitalRead(RESW_PIN) == LOW;
if (currentSwitchState && !switchPressed) {
switchPressTime = currentMillis;
switchPressed = true;
} else if (!currentSwitchState && switchPressed) {
unsigned long pressDuration = currentMillis - switchPressTime;
switchPressed = false;
if (pressDuration < 500) {
if (currentMode == NORMAL) {
currentMode = SET_HOURS;
loadCurrentTime(now);
} else if (currentMode == SET_YEAR) {
saveAndExit();
} else {
currentMode = (SetMode)(currentMode + 1);
}
} else if (pressDuration > 1000) {
saveAndExit();
}
}

// Normal mode: update time/date
if (currentMode == NORMAL) {
if (!isDateMode) {
int hrs = now.hour();
int mins = now.minute();
int secs = now.second();
target_digits[0] = hrs / 10;
target_digits[1] = hrs % 10;
target_digits[2] = mins / 10;
target_digits[3] = mins % 10;
target_digits[4] = secs / 10;
target_digits[5] = secs % 10;
}

if (currentMillis - previousMillis >= interval && !isDateMode) {
  previousMillis = currentMillis;
  isDateMode = true;
  int yrs = now.year() % 100;
  int mth = now.month();
  int dys = now.day();
  target_digits[0] = dys / 10;
  target_digits[1] = dys % 10;
  target_digits[2] = mth / 10;
  target_digits[3] = mth % 10;
  target_digits[4] = yrs / 10;
  target_digits[5] = yrs % 10;
} else if (isDateMode && currentMillis - previousMillis >= 5000) {
  isDateMode = false;
}

if (currentMillis - lastLedRefresh >= ledRefreshInterval) {
  lastLedRefresh = currentMillis;
  my_tube1.set_led(red, blue, green);
  my_tube2.set_led(red, blue, green);
  my_tube3.set_led(red, blue, green);
  my_tube4.set_led(red, blue, green);
  my_tube5.set_led(red, blue, green);
  my_tube6.set_led(red, blue, green);
}

} else {
target_digits[0] = setValues[0] / 10;
target_digits[1] = setValues[0] % 10;
target_digits[2] = setValues[1] / 10;
target_digits[3] = setValues[1] % 10;
target_digits[4] = setValues[2] / 10;
target_digits[5] = setValues[2] % 10;
if (currentMode >= SET_DAY) {
target_digits[0] = setValues[3] / 10;
target_digits[1] = setValues[3] % 10;
target_digits[2] = setValues[4] / 10;
target_digits[3] = setValues[4] % 10;
target_digits[4] = setValues[5] / 10;
target_digits[5] = setValues[5] % 10;
}
adjustSetValue();
}

if (currentMillis - lastFrameTime >= frameInterval) {
lastFrameTime = currentMillis;
updateTubes(currentMillis);
}

if (currentMode == NORMAL) {
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.println(now.second(), DEC);
} else {
Serial.print("Setting: ");
Serial.println(currentMode);
}
}

void encoderISR() {
if (digitalRead(REA_PIN) == digitalRead(REB_PIN)) {
encoderPos--;
} else {
encoderPos++;
}
}

void adjustSetValue() {
static int lastPos = 0;
int delta = encoderPos - lastPos;
if (delta != 0) {
switch (currentMode) {
case SET_HOURS:
setValues[0] = (setValues[0] + delta + 24) % 24;
break;
case SET_MINUTES:
setValues[1] = (setValues[1] + delta + 60) % 60;
break;
case SET_SECONDS:
setValues[2] = (setValues[2] + delta + 60) % 60;
break;
case SET_DAY:
setValues[3] = constrain((setValues[3] + delta), 1, 31);
break;
case SET_MONTH:
setValues[4] = constrain((setValues[4] + delta), 1, 12);
break;
case SET_YEAR:
setValues[5] = (setValues[5] + delta + 100) % 100;
break;
default:
break;
}
lastPos = encoderPos;
}
}

void loadCurrentTime(DateTime now) {
setValues[0] = now.hour();
setValues[1] = now.minute();
setValues[2] = now.second();
setValues[3] = now.day();
setValues[4] = now.month();
setValues[5] = now.year() % 100;
}

void saveAndExit() {
DateTime newTime(2000 + setValues[5], setValues[4], setValues[3],
setValues[0], setValues[1], setValues[2]);
rtc.adjust(newTime);
currentMode = NORMAL;
Serial.println("Time saved!");
printTime(newTime);
}

void updateTubes(unsigned long currentMillis) {
exixe* tubes[6] = {&my_tube1, &my_tube2, &my_tube3, &my_tube4, &my_tube5, &my_tube6};

// Blink logic
if (currentMode != NORMAL && currentMillis - lastBlinkTime >= 500) {
lastBlinkTime = currentMillis;
blinkState = !blinkState;
Serial.print("Blink state: "); // Debug
Serial.println(blinkState);
}

for (int i = 0; i < 6; i++) {
bool shouldBlink = false;
if (currentMode == SET_HOURS && i < 2) shouldBlink = true;
else if (currentMode == SET_MINUTES && i >= 2 && i < 4) shouldBlink = true;
else if (currentMode == SET_SECONDS && i >= 4) shouldBlink = true;
else if (currentMode == SET_DAY && i < 2) shouldBlink = true;
else if (currentMode == SET_MONTH && i >= 2 && i < 4) shouldBlink = true;
else if (currentMode == SET_YEAR && i >= 4) shouldBlink = true;

if (prev_digits[i] != target_digits[i]) {
  tubes[i]->crossfade_init(target_digits[i], 15, brightness, overdrive);
  prev_digits[i] = target_digits[i];
}

if (currentMode != NORMAL && shouldBlink) {
  if (blinkState) {
    tubes[i]->show_digit(target_digits[i], brightness, overdrive); // Show digit
  } else {
    tubes[i]->clear(); // Off
  }
} else {
  tubes[i]->crossfade_run(); // Normal operation or non-blinking tubes
}

}
}

void printTime(DateTime dt) {
Serial.print(dt.year());
Serial.print('/');
Serial.print(dt.month());
Serial.print('/');
Serial.print(dt.day());
Serial.print(" ");
Serial.print(dt.hour());
Serial.print(':');
Serial.print(dt.minute());
Serial.print(':');
Serial.println(dt.second());
}`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions