Google+ Followers

Wednesday, October 16, 2013

37. A Yacht Race Timer in the Making

4000 page views!!
Yacht races generally use flag signals and have a set routine for the starting sequence:
  • Postponement signal - only used if the start is running late.  The postponement flag, if used, is removed at T0 minus 6 minutes
  • Class warning flag displayed - at T minus 5 minutes. Often 2 classes start together, so two flags are raised
  • Preparatory signal flag displayed - at T minus 4 minutes
  • Preparatory signal removed - at Tminus 1 minute
  • Start - class flag is removed at time T0
  • Change seamlessly from count-down mode to count-up mode

It is also necessary to record the finishing time of each yacht.  The times required are times relative to time T0, but it is also necessary for the Race Officer to know the time of day (for obvious reasons).  There are of course, lots and lots of other signals which can be involved, but the above sequence alone would be great.

Many attempts have been made by others to automate such a system, and if the resulting devices are easy to use, and reliable, they would be a great help to Race Officers.  However, they can be expensive, and races tend to be run using wrist-watches, and writing down the finish times (usually on soggy paper).  

Unless there are two or three people involved, it's impossible to raise and lower flags to the nearest second, sound a horn and record boat identities and finishing times, all at the same time.  A smart octopus would be useful.

In the absence of an intelligent octopus, any automated gadget needs to be easy to use, and cheap (don't forget - it could conceivably be dropped overboard!).  Remember all this is happening on board the Committee Boat (a motor boat which has a 12 V DC supply available).

So here's yet another attempt to make a gadget for this task - while trying to keep it simple - the YRT (yacht race timer).  The Arduino can be a good timing device - there are no other programs running to cause interrupt problems - and it lends itself to driving other devices including lights, relays, horns etc.  I did a quick check on the Arduino's timing accuracy, and found it to be 0.13 per cent fast.  This is acceptable for the purpose of recording times of up to a couple of hours (just a few seconds out), as the yacht racing times are all relative to one another.

I got myself an LCD screen (£5.89, delivered, from Amazon), which is the 20 column x 4 row version of the Hitachi HD44780 compatible system, and which I thought would be more useful for this task than the 16 column x 2 row version.  The characters are represented by 5 pixel x 8 pixel images.  There are different sizes of these displays available.

Here's the circuit (this one shows the 16 x 2 character display, but the connections to the 20 x 4 display are the same).  Note that not all 16 pins of the LCD display are required:
Arduino Pin 6 is pulled down to GND with a 10 kΩ resistor, and sent "High" when the breadboard button is pressed.  The 10 kΩ trimmer is used to adjust the brightness of the LCD screen's backlight, which requires its own power supply.

Here's a video of my work in progress, with ideas as usual pinched from lots of other sources which I have tried to reference here.  At the beginning of the video I use the Arduino's reset button to start the procedure from the beginning, and later the time-capturing button on the breadboard.  Please note that the timing sequence has been speeded up by a factor of 100 to prevent boredom setting in, so you have to concentrate to see what's going on:



In line 69 of the code below, the number of count-down (negative value) seconds is set, and if that time exceeds 6 minutes, the first signal it gives is the 6 minute, followed by the 5 minute, 4 minute, one minute and then the T0 signal. 

I thought it would be nice (ie useful) to have a visual indication of the state of the major flags, so I made some custom characters to represent:
1 flag down:2 flags up:1 flag up:and 2 flags down:.

These characters appear on the top left of the LCD display at the appropriate time.  

Making custom characters was enabled using the extremely useful page at http://omerk.github.io/lcdchargen/ which generates the code for any symbols you can dream up within 5 x 8 pixels.  Buzzers or relays, LEDs and lights can easily be added, but haven't yet been included in this version.

The time in the video is running so fast, 100 times normal,  that it's not easy to see what's going on, but the postponement flag coming down is the first.  If there is no postponement, then the first signal would be the 5-minute one.  

The symbols eventually line up as  but without the first one, as the postponement flag down symbol is intentionally written over by the next symbol (2 class flags up).  This allows the Race Officer to visually check that the critical flags he has been flying, are down after the start of the race.

The main timer on the right of the LCD screen shows hours, minutes and seconds from T0.  This is given as a negative time if it's before T0.   As the time passes through the critical 6, 5, 4, 1 and 0 minutes, the above characters are displayed to remind the Race Officer that he should have already carried out those operations.  These symbols could of course be displayed in advance with an audible warning to give him prior notice to raise or lower the flags.

Then comes the push button (on the breadboard).  When the button is pressed, as the first boat crosses the start/finish line, the time (from T0) at which it was pressed is displayed on the 3rd row (row 2) starting at position zero (first column).  This indicates the boat's finish time.  The next finish time is recorded on the fourth row, below.  Subsequent presses of the button over-write all previous ones on the fourth row, leaving the first finishing time on the 3rd row still visible.  

This gives the Race Officer time to write down the times (or they could easily be stored in an array in the Atmega 328 chip's memory).  The first finishing time is a useful one to have continuously displayed, as other rules of sailing come into play if any of the other boats finish out of time (eg more than 30 minutes after the first finisher).  The Racing Rules of Sailing are more complicated than Arduino programming!

Here is the code as it currently stands:
1:  /*  
2:   LiquidCrystal Arduino Library - Timing  
3:     
4:   Demonstrates the use a 20 column x 4 row LCD display. The LiquidCrystal  
5:   library works with all LCD displays that are compatible with the   
6:   Hitachi HD44780 driver.   
7:     
8:   This sketch prints count-down / count-up times to the LCD - and more!  
9:     
10:   The circuit:  
11:   * LCD RS pin to digital pin 12  
12:   * LCD Enable pin to digital pin 11  
13:   * LCD D4 pin to digital pin 5  
14:   * LCD D5 pin to digital pin 4  
15:   * LCD D6 pin to digital pin 3  
16:   * LCD D7 pin to digital pin 2  
17:   * LCD R/W pin to ground  
18:   * Variable (eg 10K) resistor:  
19:   * ends to +5V and ground  
20:   * wiper to LCD VO pin (pin 3)  
21:     
22:   Library originally added 18 Apr 2008 by David A. Mellis  
23:   library modified 5 Jul 2009 by Limor Fried (http://www.ladyada.net)  
24:   example added 9 Jul 2009 by Tom Igoe  
25:   modified 22 Nov 2010 by Tom Igoe  
26:   modified October 2013 by KC  
27:    
28:   http://www.arduino.cc/en/Tutorial/LiquidCrystal  
29:  */  
30:  // include the library code:  
31:  #include <LiquidCrystal.h>  
32:    
33:  // initialize the library with the numbers of the interface pins  
34:  LiquidCrystal lcd(12, 11, 5, 4, 3, 2);  
35:    
36:  // array of bits defining pixels for 8 custom characters  
37:  // pixel=1 : on and pixel=0 : off  
38:  // see Custom Character Generator at http://omerk.github.io/lcdchargen/  
39:   byte oneflagdown[8] =   
40:    {0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01100, 0b01100};  // 1 flag down  
41:   byte twoflagsup[8] =    
42:    {0b11011, 0b11011, 0b01010, 0b01010, 0b01010, 0b01010, 0b01010, 0b01010};  // 2 flags up  
43:   byte oneflagup[8] =   
44:    {0b01100, 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100};  // 1 flag up  
45:   byte twoflagsdown[8] =   
46:    {0b01010, 0b01010, 0b01010, 0b01010, 0b01010, 0b01010, 0b11011, 0b11011};  // 2 flags down  
47:  // also see Arduino Cookbook 2nd ed by Michael Margolis  
48:   int inPin = 6;  
49:   int outPin = 13;   // the number of the output pin (LED)  
50:   int reading;  
51:   long debounce = 200; // debounce delay in milliseconds  
52:   int i = 2;      // for lots more on button bounce, see http://arduino.cc/en/Tutorial/Debounce  
53:      
54:  void setup() {  
55:   // set up the LCD's number of columns and rows:   
56:   lcd.begin(20, 4);         // 20 columns & 4 rows  
57:   lcd.createChar(1, oneflagdown);  // create first custom character  
58:   lcd.createChar(2, twoflagsup);  // create second custom character  
59:   lcd.createChar(3, oneflagup);   // create third custom character  
60:   lcd.createChar(4, twoflagsdown); // create fourth custom character  
61:   lcd.clear();   
62:   // Print the header on the LCD  
63:   lcd.print("   YRT   h: m: s");// for "Yacht Race Timer"  
64:   pinMode(inPin, INPUT);  
65:  }  
66:    
67:  void loop() {  
68:   int seconds;  
69:   int time = -405; // countdown seconds before time zero  
70:   // print the time since reset (at 'int time' seconds):  
71:   int sec0 = millis()/1000;  
72:   int secs = sec0 + time;  
73:   lcd.setCursor(0, 0);   
74:   if (secs == -360)   
75:    lcd.write(1);      // display first character at 6 minutes (1 flag down)  
76:   if (secs == -300)  
77:    lcd.write(2);      // display second character at 5 minutes (2 flags up)  
78:    lcd.setCursor(1, 0);     
79:   if (secs == -240)  
80:    lcd.write(3);      // display third character (1 flag up)  
81:    lcd.setCursor(2, 0);    
82:   if (secs == -60)   
83:    lcd.write(1);      // display first character (1 flag down)  
84:    lcd.setCursor(3, 0);     
85:   if (secs == 0)   
86:    lcd.write(4);      // display fourth character (2 flags down)  
87:   clockDisplay(12, 1, secs);// display the running time from time zero  
88:    
89:   reading = digitalRead(inPin);  
90:   if (reading == HIGH)   // if the button is pressed  
91:    {  
92:    delay(debounce);    // in case the button bounces  
93:    clockDisplay(0, i, secs);  
94:    i++;          // move on to next line for next time  
95:    }  
96:  }  
97:    
98:  void clockDisplay(int x, int y, int s){  
99:   // display hours, mins, secs from time zero, at required position  
100:   // x can be 0 to 12, (positions across LCD screen), y can be 0 to 3 (lines down screen)  
101:   int mins = s/60;  
102:   int hrs = mins/60;  
103:   int secs = s - (mins*60);  
104:   mins = mins - (hrs*60);  
105:   lcd.setCursor(x,y);  
106:   if (s > 0)  
107:    lcd.print("+");  
108:   else if (s < 0)  
109:    lcd.print ("-");  
110:   else  
111:    lcd.print (" "); // could sound a buzzer or flash a light .. THEY'RE OFF!!  
112:   lcd.setCursor(x+1, y);  
113:   lcd.print(abs(hrs));  
114:   lcd.print (":");  // trailing colon  
115:   lcd.setCursor(x+1, y);  
116:   lcd.print(abs(hrs));  
117:   lcd.print (":");  // trailing colon  
118:   lcd.setCursor(x+3, y);  
119:   if (abs(mins)<10) // include a leading zero  
120:    lcd.print("0" + String(abs(mins)));  
121:   else   
122:    lcd.print(abs(mins));  
123:   lcd.print (":");  // trailing colon  
124:   lcd.setCursor(x+6, y);  
125:   if (abs(secs)<10) // include a leading zero  
126:    lcd.print("0" + String(abs(secs)));  
127:   else   
128:    lcd.print(abs(secs));  
129:  }  
130:    

I have mentioned some suggestions above which I will probably continue to develop.  

Things to further think about include:
  • the power supply - direct from the Committee Boat's 12V supply, or connected in parallel with a set of re-chargeables which can re-charge while powering the YRT.  The recommended input voltage to the Arduino is 7 V - 12 V, with input voltage limits of 6 V to 20 V, so to be safe, voltage regulation would be advisable.
  • encasing the unit if it ever reaches fruition (including waterproofing).
  • further button control to enter the count-down time, re-display (and even download) the array of finishing times.
  • add a real-time clock (RTC) with its own coin battery, so that the device can actually display the correct time of day, even if it has been switched off and on again since the last time it was used.  The RTC may provide a more accurate source of time (a possible factor of 10 in the accuracy) than the Arduino's millis() function (line 71 of the code, above).
The temptation at this stage is to start incorporating lots of bells and whistles which could, if not curtailed, rather over-egg the pudding!!


Thursday, October 10, 2013

36 The 4-digit 7-segment LED

This is something I wanted to do for a long time, and as I am waiting for some parts (from China, again) and as I have a spare Arduino, I thought I would knock this up.  The project comes from Nathan Siedle, at http://www.hobbytronics.co.uk/arduino-countdown-timer.  Nathan's permission to use this work, is covered by what he describes as "beerware" - if you use it and you bump into him some time, you buy him a beer!  What a great license arrangement - this should be made into formal legislation!

Nathan warns that this method does not use current limiting resistors, so be careful you don't blow your display!  The code makes use of Pulse Width Modulation (PWM) to limit the current to the segments, and Persistence of Vision allows you to see the segments illuminated without being aware of the pulsing.  PWM is possible using certain Arduino pins, and in this case, Arduino Pins 6, 9, 10 and 11 are utilised.  These would normally be used with analogWrite() to get PWM, but Nathan uses digitalWrite() with a delay:

 149: delayMicroseconds(DISPLAY_BRIGHTNESS);

I think this is called Bit-banging, using a software technique rather than the available hardware capability, and this can be done on any of the Arduino's data pins - it doesn't have to be on the PWM pins 3, 5, 6, 9, 10 and 11 (which have the symbol ~ in front of them on the Arduino board).


The details of the display are as follows:
This model is a white light display, while mine is green.  These can be bought for less than £2 from most suppliers.  There are 8 pins (number 1 is the first one on the left that you can see above, and as with most chips, the numbers are sequential in an anti-clockwise direction). 

There are actually 35 LEDs in all, including 4x7 digits, a colon, an upper point  - apostrophe for use as an am/pm indicator if used in a clock) and a lower point for each digit.  These are annotated here:

The 35 LEDs are connected to the 16 pins as follows:



The common anodes of the digits DIG1, DIG2, DIG3 and DIG4 (minus the decimal points - DP) are connected to the PWM inputs of the Arduino.  The points L1 & L2,(colon) L3 (apostrophe) and decimal points DP1DP2DP3 and DP4 can be, but in this case, are not, connected.  So the display's pins 4 & 12 (colon common anodes and common cathodes respectively),  7 (decimal point common cathodes), 9 & 10 (apostrophe cathode and anode, respectively) are not used in this project.  Be careful here if you're tempted to connect them up, as the PWM requirements are unknown (to me).

Because these other features are not being used, Nathan's code has only programmed the digits with the characters 0 to 9, without decimal points, apostrophe and colon.  Note that there are some redundant lines of code which have been commented out.  The code, which also describes the wiring, is here:


1:    
2:  /*  
3:   6-13-2011  
4:   Spark Fun Electronics 2011  
5:   Nathan Seidle  
6:     
7:   This version modified by www.hobbytronics.co.uk as a countdown timer  
8:   Ideal as a simple egg timer or other timer. Easily add a buzzer  
9:     
10:   This code is public domain but you buy me a beer if you use this   
11:   and we meet someday (Beerware license).  
12:     
13:   4 digit 7 segment display:  
14:   http://www.sparkfun.com/products/9483  
15:   Datasheet:   
16:   http://www.sparkfun.com/datasheets/Components/LED/7-Segment/YSD-439AR6B-35.pdf  
17:    
18:   This is an example of how to drive a 7 segment LED display from an ATmega   
19:   without the use of current limiting resistors.  
20:   This technique is very common but requires some knowledge of electronics   
21:   - you do run the risk of dumping too much current through the segments   
22:   and burning out parts of the display. If you use the stock code you should   
23:   be ok, but be careful editing the brightness values.  
24:     
25:   This code should work with all colors (red, blue, yellow, green) but the   
26:   brightness will vary from one color to the next because the forward voltage   
27:   drop of each color is different. This code was written and calibrated for the  
28:   red color.  
29:    
30:   This code will work with most Arduino's but you may want to re-route some of  
31:   the pins.  
32:    
33:   7 segments  
34:   4 digits  
35:   1 colon  
36:   =  
37:   12 pins required for full control   
38:     
39:   */  
40:    
41:  int digit1 = 11; //PWM Display pin 1  
42:  int digit2 = 10; //PWM Display pin 2  
43:  int digit3 = 9; //PWM Display pin 6  
44:  int digit4 = 6; //PWM Display pin 8  
45:    
46:  //Pin mapping from Arduino to the ATmega DIP28 if you need it  
47:  //http://www.arduino.cc/en/Hacking/PinMapping  
48:  int segA = A1; //Display pin 14  
49:  int segB = 3; //Display pin 16  
50:  int segC = 4; //Display pin 13  
51:  int segD = 5; //Display pin 3  
52:  int segE = A0; //Display pin 5  
53:  int segF = 7; //Display pin 11  
54:  int segG = 8; //Display pin 15  
55:    
56:  int start_num=9999; // Number to countdown from  
57:  unsigned long time;  
58:    
59:  void setup() {          
60:   pinMode(segA, OUTPUT);  
61:   pinMode(segB, OUTPUT);  
62:   pinMode(segC, OUTPUT);  
63:   pinMode(segD, OUTPUT);  
64:   pinMode(segE, OUTPUT);  
65:   pinMode(segF, OUTPUT);  
66:   pinMode(segG, OUTPUT);  
67:    
68:   pinMode(digit1, OUTPUT);  
69:   pinMode(digit2, OUTPUT);  
70:   pinMode(digit3, OUTPUT);  
71:   pinMode(digit4, OUTPUT);  
72:     
73:   pinMode(13, OUTPUT);  
74:  }  
75:    
76:  void loop() {  
77:     
78:   //long startTime = millis();  
79:   if((millis()/1000) < start_num){  
80:    displayNumber(start_num -(millis()/1000));  
81:   }  
82:   else {  
83:    // reached zero, flash the display  
84:    time=millis();  
85:    while(millis() < time+200) {  
86:     displayNumber(0); // display 0 for 0.2 second  
87:    }  
88:    time=millis();    
89:    while(millis() < time+200) {  
90:     lightNumber(10); // Turn display off for 0.2 second  
91:    }  
92:   }   
93:   //while( (millis() - startTime) < 2000) {  
94:   //displayNumber(1217);  
95:   //}  
96:   //delay(1000);   
97:  }  
98:    
99:  //Given a number, we display 10:22  
100:  //After running through the 4 numbers, the display is left turned off  
101:    
102:  //Display brightness  
103:  //Each digit is on for a certain amount of microseconds  
104:  //Then it is off until we have reached a total of 20ms for the function call  
105:  //Let's assume each digit is on for 1000us  
106:  //If each digit is on for 1ms, there are 4 digits, so the display  
107:  //is off for 16ms.  
108:  //That's a ratio of 1ms to 16ms or 6.25% on time (PWM).  
109:  //Let's define a variable called brightness that varies from:  
110:  //5000 blindingly bright (15.7mA current draw per digit)  
111:  //2000 shockingly bright (11.4mA current draw per digit)  
112:  //1000 pretty bright (5.9mA)  
113:  //500 normal (3mA)  
114:  //200 dim but readable (1.4mA)  
115:  //50 dim but readable (0.56mA)  
116:  //5 dim but readable (0.31mA)  
117:  //1 dim but readable in dark (0.28mA)  
118:    
119:  void displayNumber(int toDisplay) {  
120:  #define DISPLAY_BRIGHTNESS 500  
121:    
122:  #define DIGIT_ON HIGH  
123:  #define DIGIT_OFF LOW  
124:    
125:   long beginTime = millis();  
126:    
127:   for(int digit = 4 ; digit > 0 ; digit--) {  
128:    
129:    //Turn on a digit for a short amount of time  
130:    switch(digit) {  
131:    case 1:  
132:     digitalWrite(digit1, DIGIT_ON);  
133:     break;  
134:    case 2:  
135:     digitalWrite(digit2, DIGIT_ON);  
136:     break;  
137:    case 3:  
138:     digitalWrite(digit3, DIGIT_ON);  
139:     break;  
140:    case 4:  
141:     digitalWrite(digit4, DIGIT_ON);  
142:     break;  
143:    }  
144:    
145:    //Turn on the right segments for this digit  
146:    lightNumber(toDisplay % 10);  
147:    toDisplay /= 10;  
148:    
149:    delayMicroseconds(DISPLAY_BRIGHTNESS);   
150:    //Display digit for fraction of a second (1us to 5000us, 500 is pretty good)  
151:    
152:    //Turn off all segments  
153:    lightNumber(10);   
154:    
155:    //Turn off all digits  
156:    digitalWrite(digit1, DIGIT_OFF);  
157:    digitalWrite(digit2, DIGIT_OFF);  
158:    digitalWrite(digit3, DIGIT_OFF);  
159:    digitalWrite(digit4, DIGIT_OFF);  
160:   }  
161:    
162:   while( (millis() - beginTime) < 10) ;   
163:   //Wait for 20ms to pass before we paint the display again  
164:  }  
165:    
166:  //Given a number, turns on those segments  
167:  //If number == 10, then turn off number  
168:  void lightNumber(int numberToDisplay) {  
169:    
170:  #define SEGMENT_ON LOW  
171:  #define SEGMENT_OFF HIGH  
172:    
173:   switch (numberToDisplay){  
174:    
175:   case 0:  
176:    digitalWrite(segA, SEGMENT_ON);  
177:    digitalWrite(segB, SEGMENT_ON);  
178:    digitalWrite(segC, SEGMENT_ON);  
179:    digitalWrite(segD, SEGMENT_ON);  
180:    digitalWrite(segE, SEGMENT_ON);  
181:    digitalWrite(segF, SEGMENT_ON);  
182:    digitalWrite(segG, SEGMENT_OFF);  
183:    break;  
184:    
185:   case 1:  
186:    digitalWrite(segA, SEGMENT_OFF);  
187:    digitalWrite(segB, SEGMENT_ON);  
188:    digitalWrite(segC, SEGMENT_ON);  
189:    digitalWrite(segD, SEGMENT_OFF);  
190:    digitalWrite(segE, SEGMENT_OFF);  
191:    digitalWrite(segF, SEGMENT_OFF);  
192:    digitalWrite(segG, SEGMENT_OFF);  
193:    break;  
194:    
195:   case 2:  
196:    digitalWrite(segA, SEGMENT_ON);  
197:    digitalWrite(segB, SEGMENT_ON);  
198:    digitalWrite(segC, SEGMENT_OFF);  
199:    digitalWrite(segD, SEGMENT_ON);  
200:    digitalWrite(segE, SEGMENT_ON);  
201:    digitalWrite(segF, SEGMENT_OFF);  
202:    digitalWrite(segG, SEGMENT_ON);  
203:    break;  
204:    
205:   case 3:  
206:    digitalWrite(segA, SEGMENT_ON);  
207:    digitalWrite(segB, SEGMENT_ON);  
208:    digitalWrite(segC, SEGMENT_ON);  
209:    digitalWrite(segD, SEGMENT_ON);  
210:    digitalWrite(segE, SEGMENT_OFF);  
211:    digitalWrite(segF, SEGMENT_OFF);  
212:    digitalWrite(segG, SEGMENT_ON);  
213:    break;  
214:    
215:   case 4:  
216:    digitalWrite(segA, SEGMENT_OFF);  
217:    digitalWrite(segB, SEGMENT_ON);  
218:    digitalWrite(segC, SEGMENT_ON);  
219:    digitalWrite(segD, SEGMENT_OFF);  
220:    digitalWrite(segE, SEGMENT_OFF);  
221:    digitalWrite(segF, SEGMENT_ON);  
222:    digitalWrite(segG, SEGMENT_ON);  
223:    break;  
224:    
225:   case 5:  
226:    digitalWrite(segA, SEGMENT_ON);  
227:    digitalWrite(segB, SEGMENT_OFF);  
228:    digitalWrite(segC, SEGMENT_ON);  
229:    digitalWrite(segD, SEGMENT_ON);  
230:    digitalWrite(segE, SEGMENT_OFF);  
231:    digitalWrite(segF, SEGMENT_ON);  
232:    digitalWrite(segG, SEGMENT_ON);  
233:    break;  
234:    
235:   case 6:  
236:    digitalWrite(segA, SEGMENT_ON);  
237:    digitalWrite(segB, SEGMENT_OFF);  
238:    digitalWrite(segC, SEGMENT_ON);  
239:    digitalWrite(segD, SEGMENT_ON);  
240:    digitalWrite(segE, SEGMENT_ON);  
241:    digitalWrite(segF, SEGMENT_ON);  
242:    digitalWrite(segG, SEGMENT_ON);  
243:    break;  
244:    
245:   case 7:  
246:    digitalWrite(segA, SEGMENT_ON);  
247:    digitalWrite(segB, SEGMENT_ON);  
248:    digitalWrite(segC, SEGMENT_ON);  
249:    digitalWrite(segD, SEGMENT_OFF);  
250:    digitalWrite(segE, SEGMENT_OFF);  
251:    digitalWrite(segF, SEGMENT_OFF);  
252:    digitalWrite(segG, SEGMENT_OFF);  
253:    break;  
254:    
255:   case 8:  
256:    digitalWrite(segA, SEGMENT_ON);  
257:    digitalWrite(segB, SEGMENT_ON);  
258:    digitalWrite(segC, SEGMENT_ON);  
259:    digitalWrite(segD, SEGMENT_ON);  
260:    digitalWrite(segE, SEGMENT_ON);  
261:    digitalWrite(segF, SEGMENT_ON);  
262:    digitalWrite(segG, SEGMENT_ON);  
263:    break;  
264:    
265:   case 9:  
266:    digitalWrite(segA, SEGMENT_ON);  
267:    digitalWrite(segB, SEGMENT_ON);  
268:    digitalWrite(segC, SEGMENT_ON);  
269:    digitalWrite(segD, SEGMENT_ON);  
270:    digitalWrite(segE, SEGMENT_OFF);  
271:    digitalWrite(segF, SEGMENT_ON);  
272:    digitalWrite(segG, SEGMENT_ON);  
273:    break;  
274:    
275:   case 10:  
276:    digitalWrite(segA, SEGMENT_OFF);  
277:    digitalWrite(segB, SEGMENT_OFF);  
278:    digitalWrite(segC, SEGMENT_OFF);  
279:    digitalWrite(segD, SEGMENT_OFF);  
280:    digitalWrite(segE, SEGMENT_OFF);  
281:    digitalWrite(segF, SEGMENT_OFF);  
282:    digitalWrite(segG, SEGMENT_OFF);  
283:    break;  
284:   }  
285:  }  


And here's the result of my version which counts down from 9999 seconds and then flashes the display:


Thanks Nathan - clever stuff - there's a pint of Guinness for you when we meet at my local pub!  (This is now known locally as a GuinnessWare License).