First Project Help Needed (Single Digit, Seven Seg Display,

New to Arduino and new to programming, but having fun learning.

I am trying to build a single digit seven segment arduino clock without external hardware. I know the limitations of this, but it is a coding challenge and uses stuff that I have.

My code is probably pretty ugly, but for minutes < 9 and seconds < 20 it works. I haven’t tried to take minutes above 9 yet, but I would assume that would run into the same problems that I am running into with seconds. Currently I flash the display twice for minutes and twice for seconds. The script runs about every 6 seconds and I get: 0-1, 0-6, 1-2, 1-8, 1-2-4, 1-2-3-0, 1-2-3-6, 1-2-3-4-2.

Please help. Both changes to current code and code the way that it should be written are appreciated.

#include <Time.h>  

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message 
 int data = 2; 
int clock = 3;
int latch = 4;
 int ledclear = B00000000;
 int number0 = B10110111;
 int number1 = B00010100; 
 int number2 = B10101101;
 int number3 = B10011101;
 int number4 = B00011110;
 int number5 = B10011011;
 int number6 = B10111010;
 int number7 = B00010101;
 int number8 = B10111111;
 int number9 = B00011111;
 int value[10];
 
void setup()  {
    pinMode(data, OUTPUT);
  pinMode(clock, OUTPUT);  
  pinMode(latch, OUTPUT);
value[0] = number0; 
value[1] = number1;
value[2] = number2;
value[3] = number3;
value[4] = number4;
value[5] = number5;
value[6] = number6;
value[7] = number7;
value[8] = number8;
value[9] = number9;

  Serial.begin(9600);
  setSyncProvider( requestSync);  //set function to call when sync required
  Serial.println(" for sync message");
}

void loop(){    
  if(Serial.available() ) 
  {
    processSyncMessage();
  }
 
  if(timeStatus()!= timeNotSet)   
  {
    digitalWrite(13,timeStatus() == timeSet); // on if synced, off if needs refresh  
    digitalClockDisplay();  
  }
  delay(3000);
}

void digitalClockDisplay(){

  // digital clock display of the time
  Serial.print(hour());
  
  
  printDigits(minute());
 int k = minute();
   if( k < 10 )
  {
  digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, value[0]);
  digitalWrite(latch, HIGH);
 
   delay(400);
      digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, ledclear);
  digitalWrite(latch, HIGH);
  delay(200);
    digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, value[k]);
  digitalWrite(latch, HIGH);
    }
     delay(400);
      digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, ledclear);
  digitalWrite(latch, HIGH);
    delay(200);
  printDigits(second());
   int val = second();
 int units = val;



   if( units < 10 )
  {
  digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, value[0]);
  digitalWrite(latch, HIGH);
 
   delay(400);
      digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, ledclear);
  digitalWrite(latch, HIGH);
  delay(150);
    digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, value[val]);
  digitalWrite(latch, HIGH);
  }
  else
  while(units >= 10){
int tens = tens + 1;
units = units - 10;
    digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, value[tens]);
  digitalWrite(latch, HIGH);
  delay(400);
  digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, ledclear);
  digitalWrite(latch, HIGH);
  delay(150);
   digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, value[units]);
  digitalWrite(latch, HIGH);
  }
    
delay(400);

   digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, ledclear);
  digitalWrite(latch, HIGH);
  delay(400);
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.println(); 
   
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void processSyncMessage() {
  // if time sync available from serial port, update time and return true
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    char c = Serial.read() ; 
    Serial.print(c);  
    if( c == TIME_HEADER ) {       
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        c = Serial.read();          
        if( c >= '0' && c <= '9'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
        }
      }   
      setTime(pctime);   // Sync Arduino clock to the time received on the serial port
    }  
  }
}

time_t requestSync()
{
  Serial.print(TIME_REQUEST);  
  return 0; // the time will be sent later in response to serial mesg
}

not sure how the code works as I cannot find the Time.h library. But I can make some suggestions if you want to learn some new tricks with C++/C. Forgive me if I sound patronising, I don’t mean to be.


Firstly, if you want to print the current time to the Serial port, you might find this more effective:

char time[10]; //somewhere to store the full time
sprintf(time,"%d:%02d:%02d",hour(),minute(),second());
Serial.print(time);

How it works:

The first line creates an array of 10 characters called time. The array will be used to store a string (e.g. “Hello” would be an example of a string).

The second is a function called “sprintf” which can be used to add numbers to a string. In this case you want it to be the time, for example “12:00:49”. Lets break it down into bits.

Firstly there is the hour, which is a number returned by hour(). We want to tell sprintf that hour() should go first, and to do that we say %d - which means a number (more about that later).

Next there is the character ‘:’, which is easy - just write that character. And so on. Minutes and seconds are also numbers so they can be %d too. So, the time would become “%d:%d:%d”.

Now for the code. This is how it works:

sprintf(destination, “string”, variable1,variable2,…);

destination - is an array where it is saved too - in this ‘time’

“string” - is what we are making. So: “%d:%d:%d” as was worked out above

variables - are what the %d symbols represent. The first %d is replaced by the value stored in the first variable, and so on with the second, third etc. or however many there are. In this case the first %d matches up with hour(), the second with minute() and the third with second().

There is a slight problem though. You want your minutes and seconds to have a 0 in front if they are less than ten. But this can be fixed by telling sprintf how the number should look.

In the code I used the following: %02d . Basically this is the %d from before, just with 02 in the middle. If the number is less than two digits (the 2), it will pad it with zeros (the 0) until it is two digits.

It works for other combinations aswell %03d would be a number padded with 0s to be 3 digits.

Finally, Serial.print(time) just prints the string stored in the array named ‘time’ to the serial port.


I have just noticed something in your code which may be the cause of your problem.

There is a section which reads:

if(units < 10){
....
}else
while(units >= 10){
   int tens = tens + 1;
   ....
}
delay(400);

There are two things about this, one is a misunderstanding of scope, the other is formatting which will result in something you might not expect.

Though technically it works and will compile, you have used some formating which can be a bit confusing. You have used “else” without curly brackets, which means that everything that follows until a semicolon is reached. This means that the while(){} loop and delay(400); are included in the else. I think this is what you meant to put:

if(units < 10){
  ....
}else{
  while(units >= 10){
     int tens = tens + 1;
     ....
  }
}
delay(400);

Note the extra { after the else, and } before the delay.

The second is one of variable ‘scope’. In C++ when you create a variable inside a funtion or a loop (such as while(){} ), it is only valid in that function, and is deleted at the end. This can be very useful as it creates what is called a ‘local variable’, however in the case of your while() loop it will cause you a big problem.

...
  while(units >= 10){
    int tens = tens + 1;
    ...
  }
...

Here, the variable ‘tens’ is created at the start of the loop, but deleted at the end, just before it loops back to the start, which means ‘tens’ will always be equal to 0+1 and not keep incrementing as I believe you want it too. To fix that, you need to define it just outside the while() loop, so that it is not destroyed at the end.

Like this:

if(units < 10){
  ...
} else {
  int tens = 0;
  while(units >= 10){
    tens++; //means the same as: tens = tens + 1; or also the same as tens += 1;
    ...
  }
}
delay(400);

Which means initially it will be 0, then at the start of each loop it gets one bigger. So if units == 30 say, then at the end tens would be 3.

It would be also possible to get the same result simply with this:

if(units < 10){
  ...
} else {
  int tens = units/10;
  units = units%10;

  digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, value[tens]);
  digitalWrite(latch, HIGH);
  delay(400);
  digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, ledclear);
  digitalWrite(latch, HIGH);
  delay(150);
  digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, value[units]);
  digitalWrite(latch, HIGH);
}
delay(400);

As ‘tens’ is an integer, then any remainder when dividing by 10 will be ignored.

As you also want to display the units at the same time, you can use the modulo operation:

units = units % 10;

Which means ‘units’ equals the remainder when ‘units’ is divided by 10.

e.g:

34 % 10 = 4

Hope this helps! And have fun :slight_smile:

Thank you!

:slight_smile:

Not patronizing at all. Informative, helpful, and kind. I thank you, and my arduino thanks you (I call her Betty). I will post again when it is done.

Done and it works! Oh happy day.

I think this took 4 nights to finish (yes you can laugh), and I still might not have been able to without the help of @TCWORLD. Oh well, time for the next project.

http://youtu.be/EO9ynufwI5Q