Hello. I've developed this code on an Arduino UNO 4 WiFi to display the time on a single IV-4 VFD Tube. It works perfectly for days at a time and never fails. However, when I move it to a Nano it corrupts unless I comment out the first 2 steps of the animation sequence. It appears to loop forever picking up random corrupted data. This can be reproduced without being connected to my project. Just run the code on a NANO and look at the serial monitor. I hope I'm posting this in the correct place. Any advice gratefully received.
#include <Arduino.h>
#include <RTClib.h>
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <SPI.h>
#include <Wire.h>
TinyGPSPlus gps; // The TinyGPS++ object
RTC_DS3231 rtc;
const int RX_PIN = 9, TX_PIN = 10; // GPS Pins
const int rtc_address = 0x68;// I2C address of RTC module
int TimeSync = 11; // Sets the timesync pin to 5
int Adjust = 12;
int timezone = 10; // timezone offset
int W = 30; // Delay between each layer of the digit
int latchPin = 4; // connect to the ST_CP of 74HC595 (pin 3,latch pin)
int clockPin = 5; // connect to the SH_CP of 74HC595 (pin 4, clock pin)
int dataPin = 2; // connect to the DS of 74HC595 (pin 2, data pin)
SoftwareSerial gps_serial(RX_PIN, TX_PIN); // The serial interface to the GPS device
String gps_data; // I think i need this
// +++++++++++++ Segment definitions. Two bytes per digit. (16 segment digits)
byte SegDisplay[10][13] = {
{B00101110,B11110110,B00011110,B10001110,B01011101,B10011100,B11011100,B10101110,B00011100,B00011100,B00000000,B11111111,B11100011}, // A Seg
{B00110000,B10101011,B10110011,B00111011,B01111110,B00111010,B00111000,B11101111,B00111000,B00111110,B00000000,B11111111,B11101111}, // B Seg
{B01101111,B11110111,B01011111,B11001111,B01011101,B11011101,B11011101,B11101111,B01011101,B01011101,B00000000,B11111111,B11100011}, // C Seg
{B00110000,B10101011,B10110011,B00111011,B01111110,B00111010,B00111000,B11101111,B00111000,B00111110,B00000000,B11111111,B11100011}, // D Seg
{B11111111,B11111111,B11011111,B11011111,B11011101,B11011101,B11011101,B11111111,B11011101,B11011101,B00000000,B11111111,B11100011}, // E Seg
{B00110001,B10101011,B10110011,B00111011,B01111111,B00111011,B00111001,B11101111,B00111001,B00111111,B00000000,B11111111,B11100011}, // F Seg
{B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B00000000,B11111111,B11100011}, // G Seg
{B00110001,B10101011,B10110011,B00111011,B01111111,B00111011,B00111001,B11101111,B00111001,B00111111,B00000000,B11111111,B11100011}, // H Seg
{B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B00000000,B11111111,B11100011}, // I Seg
{B10111011,B10111011,B10111011,B10111011,B11111111,B10111011,B10111011,B11111111,B10111011,B10111111,B00000000,B11111111,B11100011} // J Seg
};
// Function "Shift2Bytes" that gets called 10 times in the main loop
void Shift2Bytes(byte Byte1, byte Byte2,int Delay)
{
// 1 set the latchPin to low potential, before sending data
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, Byte1);
// Send First Half of Digit
shiftOut(dataPin, clockPin, LSBFIRST, Byte2);
// Send Second Half of Digit
// set the latchPin to high potential, after sending data
digitalWrite(latchPin, HIGH);
// while (Serial.available() == 0) { };
// Serial.read();
// Serial.println("Key pressed! Exiting the loop.");
delay(Delay);
}
// Set RTC with GPS Function - Get NEMA String, make sure its valid data and extract hhmmss digits
void GPSSync(){
// Send the WiFi Symbol to the Tube. This will stay until GPS string is valid
Shift2Bytes(SegDisplay[1][12], SegDisplay[0][12], W);
delay(10000); // Time for the GPS to settle down (300000 for 5 minutes)
while (true) {
String gps_data = gps_serial.readStringUntil('\n');
Serial.println(gps_data); // Serial Monitor Heatbeat Only
int S = gps_data.substring(7, 9).toInt(); // Grabs the seconds string in advance and converts to Big S
if ((gps_data.startsWith("$GPGGA")) && (S != 0)) // Makes sure that $GPGGA is present and makes sure seconds is NOT zero
{ // If good above, do all this Now
int hh = gps_data.substring(7, 9).toInt(); // Extract Hour
int mm = gps_data.substring(9, 11).toInt(); // Extract Minutes
int ss = gps_data.substring(11, 13).toInt(); // Extract Seconds (again but diff variable)
hh = hh + timezone; // add the timezone offset. Need to automate this.
if (hh >= 24) hh = hh - 24; // Normalise so we dont get 33 o'clock for example
rtc.adjust(DateTime(gps.date.year(), gps.date.month(), gps.date.day(), hh, mm, ss)); // Need to also get Date info for auto DLS
break;
} // End get time set time
} // End check GPS for valid time loop
}
void setup() {
Serial.begin(9600);
gps_serial.begin(9600);
Wire.begin(); // Dont think i need this now
rtc.begin();
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // Only use if GPS breaks
// Define the Pin Funtions
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(TimeSync, INPUT_PULLUP); // Holds Pin 11 High waiting for ground contact
pinMode(Adjust, INPUT_PULLUP); // Holds Pin 12 High waiting for ground contact
} // End Setup
void loop() {
DateTime now = rtc.now();
char timeString[4]; // Convert the time and date values into strings
sprintf(timeString, "%02d%02d%02d%02", now.hour(), now.minute());
// Select the 4 timestring array values one digit at a time. This is the engine that steps through the timestring elements above.
// It's working with strings so later on I convert string -> char -> byte
for (int i = 0; i < 4; i++) // Loops 1 to 4 for each digit HHMM
{ //x
String the_number = String(timeString[i]); // looks at each of the 4 char/numbers in timestring and allocates them in turn to "the number"
{ // y
Serial.println(the_number[0]); // Should see the number digit displayed in IDE serial monitor
char x = the_number[0]; // convert the number[0] to a character variable named x
byte b = x - '0'; // convert x to a byte value called b for use below
// THIS SECTION Lights and unlights the Digit a layer at a time
// I have to comment out the first, or any 2 lines for it to work on a NANO. 9 Steps or more breaks the NANO
// Shift2Bytes(SegDisplay[9][b], SegDisplay[8][b], W); Commented out for NANO
// Shift2Bytes(SegDisplay[7][b], SegDisplay[6][b], W); Commented out for NANO
Shift2Bytes(SegDisplay[5][b], SegDisplay[4][b], W);
Shift2Bytes(SegDisplay[3][b], SegDisplay[2][b], W);
Shift2Bytes(SegDisplay[1][b], SegDisplay[0][b], 1000);
Shift2Bytes(SegDisplay[3][b], SegDisplay[2][b], W);
Shift2Bytes(SegDisplay[5][b], SegDisplay[4][b], W);
Shift2Bytes(SegDisplay[7][b], SegDisplay[6][b], W);
Shift2Bytes(SegDisplay[9][b], SegDisplay[8][b], W);
Shift2Bytes(SegDisplay[1][11], SegDisplay[0][11], 200); // Blank Display
} // End of individual digit / NANO loops here forever with corrupted values unless first two steps are commented out
} // End of block of 4 digits
delay(1600); // 1500 milliseconds blank time between each time display block is about right
} // END. Back to start to get new time
