IAN LANG ELECTRONICS

If you get stuck analysing the code for the counter, click below for the solution.

So, let's go through that code chunk by chunk. In the first instance we set our variables up like this:

int uparray []= {126,12,182,158,204,218,250,14,254,222};

int hour=0;

int minu=0;

int tenmin=0;

long timesec = 60000;

The array uparray contains the decimal digits that, when translated to binary, will cause the shift registers to make their various pins either high or low, thus switching on or off the segments of the LED displays to which those pins are attached; high means the segment is on and low means the segment is off.

The next three variables will count the values of the hour, tens of minutes and minutes respectively.

The next variable is timesec. This is set as a long, because the values concerned (60,000) would cause an overspill on type int. 60000 is the value because we are counting in milliseconds. 60,000 mS is of course sixty seconds, and sixty seconds is equal to one minute.

A note upon this value: In the prototyping stages it is hard to account for the processing time required to go through the code. Over eighteen hours, my clock seemed to lag the computer clock. Working it back, this approximated to a processing time of 50 mS lost, thus delaying the change, and so you may find that you need to change the value of timesec to something like 59950 to make the clock  more accurate over the long term. A test will determine the optimum value for your clock, if you run over 24 hours and the clock shows no lag then all is well. Raising the value of timesec will cause the clock to run more slowly, whereas lowering it will cause the clock to run more quickly.

Quite a lot now happens in void setup:

void setup () {

for (int t=2;t<13;t++){

pinMode (t,OUTPUT);

digitalWrite(4, LOW);

shiftOut(2,3, MSBFIRST,126);

digitalWrite(4, HIGH);

digitalWrite(7, LOW);

shiftOut(5,6, MSBFIRST,126);

digitalWrite(7, HIGH);

digitalWrite(8, LOW);

shiftOut(9,10, MSBFIRST,126);

digitalWrite(8, HIGH);

}

}

As you can see, the first thing we need to do is to set all the pins between 2 and 12 of the Arduino board (these are of course the digital input/output pins) to be outputs. If we do not, we may not supply enough current to the shift registers to enable them to work. The danger is that if we set any pin as an output and then short it to ground we may damage that pin, and so check your wiring before applying power. The setting is achieved by a simple for/next loop switching each pin in turn.

The next lines go:

pinMode (t,OUTPUT);

digitalWrite(4, LOW);

shiftOut(2,3, MSBFIRST,126);

digitalWrite(4, HIGH);

digitalWrite(7, LOW);

shiftOut(5,6, MSBFIRST,126);

digitalWrite(7, HIGH);

digitalWrite(8, LOW);

shiftOut(9,10, MSBFIRST,126);

digitalWrite(8, HIGH);

For each shift register in turn we set the latch low, output the data, and set the latch high. The result of this is that the three LED devices attached to the shift register will show the figure 0.

The loop contains three distinct parts:

void loop (){

minu=minu+1;

delay (300);

digitalWrite(10, LOW);

shiftOut(8,9, MSBFIRST,uparray[minu]);

digitalWrite(10, HIGH);}

This one allows you set the minutes by pressing the button attached to A0

hourdisp();

delay(100);}

whereas this one allows you to set the hour,

mindisp ();

and this one moves the minutes on by one minute.

The whole thing depends for its operation on the function mindisp ( ) which is as below:

void mindisp(){

digitalWrite(10, LOW);

shiftOut(8,9, MSBFIRST,uparray[minu]);

digitalWrite(10, HIGH);

if (millis ()-timethen>timesec){

minu = minu +1;

timethen=millis();}

if (minu>9){minu=0; tenmindisp ();}

}

The value of minu is the unit value of minutes currently needing to be displayed. Therefore minu is an integer in the range 0-9 and can be changed either by pressing the button attached to A0 or automatically when the timer millis () (which is built in to your ATMega chip) when, having the last time millis was referenced subtracted from the current value, is greater than timesec, the value of which we gave at the beginning of the run as 60000. If this condition is true, minu is incremented by 1, and the current time of millis is referenced as timethen.

Because the greatest range of minu must not exceed 9, if minu + 1 is greater than 9, minu is reset to 0 and the function tenmindisp () is called. This increments the tens of minutes display by 1 and does so in the following manner:

void tenmindisp(){

tenmin = tenmin+1;

if (tenmin>5){tenmin=0;hourdisp();}

digitalWrite(7, LOW);

shiftOut(5,6, MSBFIRST,uparray[tenmin]);

digitalWrite(7, HIGH);

}

First the count tenmin is incremented by 1. The count is then checked to see that it does not exceed 5, because the greatest number that the minutes in total are to display is 59, and then back to 00.

If the count is greater than 5, the function hourdisplay () is called to increment the hour by 1, and we shall look at that next.

Lastly, the result of the calculation is displayed in the lines:

digitalWrite(7, LOW);

shiftOut(5,6, MSBFIRST,uparray[tenmin]);

digitalWrite(7, HIGH);

The function hourdisplay increments the hour by one if the minute display exceeds 59, as explained above.

It does so in the following manner:

void hourdisp (){

hour=hour+1;if(hour>9){hour=0;}

digitalWrite (11,LOW);digitalWrite (12,LOW);

hour=1;}

digitalWrite (11,HIGH);digitalWrite (12,HIGH);}

digitalWrite(4, LOW);

shiftOut(2,3, MSBFIRST,uparray[hour]);

digitalWrite(4, HIGH);

We need to switch on and off our last display, the tens of hours, to show 10,11,and 12 o'clock. We do this by two if statements. The first is for when the switch is pressed to adjust the hour setting, the second to do it automatically on the count. Then it is just simply a case of putting out the display as before:

digitalWrite(4, LOW);

shiftOut(2,3, MSBFIRST,uparray[hour]);

digitalWrite(4, HIGH);

Were this to be a 24 hour clock, we would have to have another shift register or more free pins to make the display show 0,1 & 2, but as it is only 12, we need only two pins from the Arduino board to activate segments b and c.

The very same circuit can be used as a digital counter. Here is the code:

int uparray []= {126,12,182,158,204,218,250,14,254,222};

int unitdisp;

int tendisp;

int hundisp;

int checkflag=0;

void setup () {

for (int t=2;t<13;t++){

pinMode (t,OUTPUT);

reset();

}}

void loop (){

else{  units ();}

}

void units (){

checkflag=1;

unitdisp = unitdisp+1;}

if (unitdisp==10){unitdisp=0;tens();}

digitalWrite(10, LOW);

shiftOut(8,9, MSBFIRST,uparray[unitdisp]);

digitalWrite(10, HIGH);

checkflag=0;}

}

void tens(){

tendisp=tendisp+1;

if (tendisp==10){tendisp=0;hundreds();}

digitalWrite(7, LOW);

shiftOut(5,6, MSBFIRST,uparray[tendisp]);

digitalWrite(7, HIGH);

}

void hundreds(){

hundisp=hundisp+1;

if ( hundisp==10){reset();}

digitalWrite(4, LOW);

shiftOut(2,3, MSBFIRST,uparray[hundisp]);

digitalWrite(4, HIGH);

}

void reset () {

unitdisp=0;

tendisp=0;

hundisp=0;

digitalWrite(4, LOW);

shiftOut(2,3, MSBFIRST,uparray[hundisp]);

digitalWrite(4, HIGH);

digitalWrite(7, LOW);

shiftOut(5,6, MSBFIRST,uparray[tendisp]);

digitalWrite(7, HIGH);

digitalWrite(10, LOW);

shiftOut(8,9, MSBFIRST,uparray[unitdisp]);

digitalWrite(10, HIGH);

}

Pressing the button attached to A0 will now increment the display by 1 and the button to A1 will reset the display to 000. I'll leave you to work out how the code works as an exercise, but there is one line here that's new:

Putting two conditionals like this together is called a boolean operator and notice the && joining them. The code stipulated by this if statement will only be executed if both statements are true. It saves having nested conditionals such as we've used hereto and cuts down on code length. On to the next project, then.

Ian Lang September 2011

# A Basic Digital Clock , 7 Segment Display

Go Back <Previous page Solution