Arduino WordClock Code issues

Hi there,

I'm working in an arduino based wordclock.

I worked a lot on the code. I set the correct time in the RTC DS1307 module.

Yet as a coding newbie I need your help !

#include "Wire.h"
#define DS1307_ADDRESS 0x68

#include <Adafruit_NeoPixel.h>
#define RGBLEDPIN    6
#define N_LEDS 114 // 11 x 10 grid + 4 aux coins

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(N_LEDS, RGBLEDPIN, NEO_GRB + NEO_KHZ800);

uint32_t WHITE = pixels.Color(255, 255, 255); // Défini la couleur

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//          WORDS
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void LEDSOFF() {
    for(int i=0;i<N_LEDS;i++){
       pixels.setPixelColor(i, pixels.Color(0,0,0)); 
      pixels.show();
 }
}
void showILEST() // = IT IS
{
  pixels.setPixelColor(1, WHITE);
  pixels.setPixelColor(2, WHITE);

  pixels.setPixelColor(4, WHITE);
  pixels.setPixelColor(5, WHITE);
  pixels.setPixelColor(6, WHITE);
}

void showVINGT() // =TWENTY
{
  pixels.setPixelColor(90, WHITE);
  pixels.setPixelColor(91, WHITE);
  pixels.setPixelColor(92, WHITE);
  pixels.setPixelColor(93, WHITE);
  pixels.setPixelColor(94, WHITE);
}

void showVINGTCINQ()
{
  showVINGT();
  pixels.setPixelColor(95, WHITE);
  pixels.setPixelColor(96, WHITE);
  pixels.setPixelColor(97, WHITE);
  pixels.setPixelColor(98, WHITE);
  pixels.setPixelColor(99, WHITE);
}

// I Removed a lot of functions to fit in the post but you have the idea

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//          Appel de l'heure enregistrée sur la DS1307 / Call Hours and minutes from DS1307
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}

void printDate(){

  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);

  byte zero = 0x00;
  Wire.write(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time

}

void isPast()
  { boolean (minute > 30 = true)  
  }

    
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//          Light leds regarding hours and minutes
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void AfficheLeds() {
    LEDSOFF(); 
    {
      showILEST();
    
  
     if(minute < 5 and hour == 1 ) {
        showHEURE();
        } else if(minute < 5 and (hour != 12 || hour != 0 || hour != 1) ){
          showHEURES
          
      } if(minute == 1) {
        showPLUSUN();
      } else if(minute == 2) {
        showPLUSDEUX();
      } else if(minute == 3) {
        showPLUSTROIS();
      } else if(minute == 4) {
        showPLUSQUATRE();  
      } else if(minute == 5)  {
        showCINQ();
        
      } else if(minute == 6)  {
        showPLUSUN();
        showCINQ();

same idea till 29

      } else if(minute == 30 and (hour != 12 || hour != 0 )) {
        showETDEMIE();
        } else {
          showETDEMI();
          
same idea till 59 

      } else if(minute == 59) {
        showMOINS();
        showPLUSUN();
      }

      if(hour == 0) {
        if(isPast) {
          showMINUIT();
        } else {
          showUNE();
        }
      } else if(hour == 12) {
        if(isPast) {
          showMIDI();
        } else {
          showUNE();
        }
      } else if(hour == 1 || hour == 13) {
        if(isPast) {
          showUNE();
        } else {
          showDEUX();
        }
      } else if(hour == 2 || hour == 14) {
        if(isPast) {
          showDEUX();
        } else {
          showTROIS();
        }
      }  IDEM JUSQU'A MINUIT
   
       else if(hour == 23) {
        if(isPast) {
          showONZE();
        } else {
          showMINUIT();
        }
      }
    }

    pixels.show(); // cela actualise l'affichage des leds Leds LightON
}


void setup(){
  Wire.begin();
  pixels.begin();
}

void loop(){
  printDate();
  delay(1000);
  AfficheLeds();
}

The main issue I'm facing is that some functions are not recognised

I was thinking that I could reuse "minute" et "hour" as I defined them with "int"

I have the correct time in the serial.

error: 'minute' was not declared in this scope
error: 'hour' was not declared in this scope

int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time

The second point is : I cant define a function who is telling that minutes are > 30. If this function "is Past" I will reuse it in the time to words definition (eg I can write 20 to 10 even if hours in the serials are 9)

void isPast()
  { boolean (minute > 30 ; true) 
  }

As "minute" is not defined I can't work on the function structure. I know it's incorrect...

The "if else" part is not correct but I'll see later to fix it.

Thanks for your help

Louison

It may good for you to have a quick look at a c/c++ tutorial on functions.
You probably want something like the following (which could be more compact at the risk of obscuring how it works):

boolean isPast( int paramMinute ) {

   boolean returnValue ;

   if ( paramMinute > 30 ) {
     returnValue = true ;
   }
   else {
     returnValue = false ;
   }

   return returnValue ;
}

You have to be careful also about using the same variable name for different things. If you make an error, the compiler may not spot it, but you'll get odd results. Also look at c/c++ scope rules, which covers this point.

Yes I red some C/C++ function tutorial but It's difficult to write at my current level...

Thanks for your help.

The fact is still the same problem I guess about defining "hour" and "minutes" at the beginning will help me with the isPast function.

In your function paramMinute = minute but as it's not defined It will not work. Correct ?

In your function paramMinute = minute but as it's not defined It will not work. Correct ?

It is correct that paramMinute does not have a value, until it the function isPast() is called. You can say in your code:

if( isPast(59) ) {
// do something because 59 is passed to the function and is greater than 30
}

The variables second and minute are defined as local to your function printDate(). Their values are not known outside of that function. If you want to use these values elsewhere, then you can define them as global by moving them outside the function definition.

void printDate(){

  // Reset the register pointer
 . . .

  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
 . . .

}

6v6gt:
The variables second and minute are defined as local to your function printDate(). Their values are not known outside of that function. If you want to use these values elsewhere, then you can define them as global by moving them outside the function definition.

I tried to move it as you said, it seems working :slight_smile:

byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}

int minute = bcdToDec(Wire.read());
int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time


void printDate(){

  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);

  byte zero = 0x00;
  Wire.write(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.read());
  minute ;
  hour ;

}

Now I will work on the isPast function. The code that you post is interesting but it's not really adapted to what I need to do (I think)

To give you an exemple:

if(hour == 0) {
        if(isPast) {
          showONEHOUR();
        } else {
          showMIDNIGHT();
        }

showMIDNIGHT and showONEHOUR are function already written. Basically they switch ON some specific leds.

So in this case I'd like to create the function "isPast" in the way that isPast = true with minute > 30

So in the code above when hour == 0 and isPast is correct it will light One Oclock (like a quarter to 1) if it's not correct it will light Midnight (like Midnight past 20)

Is it clear ?

Edit :

I thought about an other structure :

int isPast = (minute > 30);

if(hour == 0) {
        if(isPast = true) {
          showONEHOUR();
        } else {
          showMIDNIGHT();
        }

[/code]

Could it be correct ?

The function isPast() which I produced was based on your logic in the first post, but in correct c/c++. I suspected as I was writing it that it might not do anything useful, but it served as a good example of a function.

Anyway, I see what you are trying to do. You are creating a clock which uses the French rules for identifying the time but your program uses English names internally for things like midnight.

Your latest piece of code here:

int isPast = (minute > 30);

if(hour == 0) {
        if(isPast = true) {
          showONEHOUR();
        } else {
          showMIDNIGHT();
        }  
}

does not need/use a function. It is simply setting a variable.

You could rewrite it more simply as:

if(hour == 0) {
        if(minute > 30 true) {
          showONEHOUR();
        } else {
          showMIDNIGHT();
        }  
}

6v6gt:
Anyway, I see what you are trying to do. You are creating a clock which uses the French rules for identifying the time but your program uses English names internally for things like midnight.

You are totally right. In fact the code I posted here was lightly modified for english speakers better understanding.

I was thinking about using this function too :

boolean isPast()
  { return (minute > 30 ? true:false) 
  }

void AfficheLeds() {
    LEDSOFF(); 
    {
      showILEST();

if(hour == 0) {
        if(isPast() == true) {
          showONEHOUR();
        } else {
          showMIDNIGHT();
        }

I think the logic is the same. Correct ?

Yes, but check it does you want. And if you want to make it even more compact :

void AfficheLeds() {
    LEDSOFF();
    {
       showILEST();

       if(hour == 0) {
           ( minute > 30 ) ? ( showONEHOUR(); ) :  (showMIDNIGHT(); ) ; 
       }
       . . .

Maybe you can find something of help in the code posted in #4 of this thread.

Thanks Riva.

Thanks a lot 6v6gt for the information regarding functions, variables and to make me understand the logic of reducing the size of the function !

See you !

maybe consider making things a bit easier. I did my word clock like this:

declaring the "Words" like this:

const uint8_t word_IT[8] = {0,1}; // these are the Pixels that represent the words
const uint8_t word_IS[8] = {3,4};
const uint8_t word_FIVE[8] = {26,27,28,29};
const uint8_t word_TEN[8] = {10,11,12};
const uint8_t word_QUARTER[8] = {19,20,21,22,23,24,25};
const uint8_t word_TWENTY[8] = {13,14,15,16,17,18};
const uint8_t word_HALF[8] = {6,7,8,9};
const uint8_t word_MINUTES[8] = {30,31,32,33,34,35,36};
const uint8_t word_PAST[8] = {48,49,50,51};
const uint8_t word_TILL[8] = {37,38};

const uint8_t word_HOUR[13][8] = {               // these are the Pixels that represent the Numbers/Hours
  { NULL, NULL, NULL},       //ZERO NOT USED
  { 44, 45, 46},             //ONE
  { 52, 53, 54},             //TWO
  { 39, 40, 41, 42, 43},     //THREE
  { 56, 57, 58, 59},         //FOUR
  { 61, 62, 63, 64},         //FIVE
  { 75, 76, 77},             //SIX
  { 70, 71, 72, 73, 74},     //SEVEN
  { 65, 66, 67, 68, 69},     //EIGHT
  { 78, 79, 80, 81},         //NINE
  { 82, 83, 84},             //TEN
  { 85, 86, 87, 88, 89, 90}, //ELEVEN
  { 98, 99,100,101,102,103}, //TWELVE
};

const uint8_t word_OCLOCK[8] = { 91, 92, 93, 94, 95, 96};

and lite them like this:

void updateTimePanel(uint8_t theHour, uint8_t theMinute)
{
  // this block just calls some animation effects every 15 mins...
  static uint8_t priorMinute = 61;
  if (theMinute != priorMinute && (priorMinute == 59 || priorMinute == 14 || priorMinute == 29 || priorMinute == 44))
  {
    uint8_t skitChoice = random(0, 4);
    displayEffect[skitChoice]();
  }
  priorMinute = theMinute;
  // here are the meaty bits
  clearPixels();
  liteTheWord(word_IT);
  liteTheWord(word_IS);
  if (theMinute < 33)
  {
    liteTheWord(word_HOUR[theHour]);
  }
  else
  {
    if (theHour < 12)
    {
      theHour++;
    }
    else
    {
      theHour = 1;
    }
    liteTheWord(word_HOUR[theHour]);
  }
  if (theMinute < 3)
  {
    liteTheWord(word_OCLOCK);
  }
  else if (theMinute < 8)
  {
    liteTheWord(word_FIVE);
    liteTheWord(word_PAST);
  }
  else if (theMinute < 13)
  {
    liteTheWord(word_TEN);
    liteTheWord(word_MINUTES);
    liteTheWord(word_PAST);
  }
  else if (theMinute < 18)
  {
    liteTheWord(word_QUARTER);
    liteTheWord(word_PAST);
  }
  else if (theMinute < 23)
  {
    liteTheWord(word_TWENTY);
    liteTheWord(word_MINUTES);
    liteTheWord(word_PAST);
  }
  else if (theMinute < 28)
  {
    liteTheWord(word_TWENTY);
    liteTheWord(word_FIVE);
    liteTheWord(word_PAST);
  }
  else if (theMinute < 33)
  {
    liteTheWord(word_HALF);
    liteTheWord(word_PAST);
  }
  else if (theMinute < 38)
  {
    liteTheWord(word_TWENTY);
    liteTheWord(word_FIVE);
    liteTheWord(word_TILL);
  }
  else if (theMinute < 43)
  {
    liteTheWord(word_TWENTY);
    liteTheWord(word_TILL);
  }
  else if (theMinute < 48)
  {
    liteTheWord(word_QUARTER);
    liteTheWord(word_TILL);
  }
  else if (theMinute < 53)
  {
    liteTheWord(word_TEN);
    liteTheWord(word_TILL);
  }
  else if (theMinute < 58)
  {
    liteTheWord(word_FIVE);
    liteTheWord(word_TILL);
  }
  else
  {
    liteTheWord(word_OCLOCK);
  }
  myPixels.setPixelColor(97, myPixels.Color(mailColor.red, mailColor.green, mailColor.blue));
  myPixels.show();
}

and...

void liteTheWord(const uint8_t* word)
{
    for(uint8_t i = 0; i < sizeof(word)*2; i++)
    {
      if(isDay)
      {
        timeColor = briteWhite;
      }
      else
      {
        timeColor = dullGray;
      }
      myPixels.setPixelColor(word[i], myPixels.Color(timeColor.red, timeColor.green, timeColor.blue));
    }
}

Thanks for the idea :slight_smile:

My code seems working so I'm very happy!

Anyways I still have a little bug

Right now my leds are blinking so I checked and when I add a delay(5000) they blink every 5 seconds.

What I'd like to do is to create a delay that is linked to the seconds.

I mean we can tell the leds to blink every time the minutes change (so when seconds == 0)

I tried something but it's not working...

void NEWMINUTE() {
  if (second == 0)
  delay(60000);
}

void loop(){
  printDate();
  delay(1000);
  LUMINOSITE();
  AfficheLeds();
  delay(NEWMINUTE());

Thanks for your help !

Louison

Delays() will block everything. Look at the code for "blink without delay" example which is available in the Arduino IDE ( File --> Examples --> 02. Digital) to see a better way of doing this using millis().

I checked this example already but it's not really adapted because it's not enough accurate.

It creates an interval of x seconds after what the leds have to blink.

In my case I just want the leds to blink when seconds = 0. Like this the time is set when every minutes start.

I tried also

void loop(){
  printDate();
  delay(1000)
  LUMINOSITE();
  AfficheLeds();
  delay(second == 1);

but it's not working...

instead of

delay(second == 1);

maybe:

delay(1000); // milliseconds