Go Down

Topic: Stopwatch with Pause/Lap  6 digit 7 seg LED. HELP! (Read 125886 times) previous topic - next topic

David_Rudla

I have to look to braces here. It is probably problem... But how I spoke - I am also newbie.  ::)

David_Rudla

And one more thing - please change this in declaration:
Code: [Select]

volatile byte hundredths= 0;
volatile byte tenths = 0;
volatile byte ones_seconds = 0;
volatile byte tens_seconds = 0;
volatile byte ones_minutes = 0;
volatile byte tens_minutes = 0;
volatile byte ones_hours = 0;
volatile byte tens_hours = 0;

Warren Reeve

Quote
And one more thing - please change this in declaration:

Done.  :)

Warren Reeve

Quote
Well, keep chugging away. You can add a test in the main display part to skip that set of shiftouts while EEPROM_Reading is high for example, or only allow memory readback while time is not running. I am going out to see a robot competition, keep thinking about what you want to occur & when and how you could make that happen.

Hi Robert, just to let you know I still have our code intact as it was last and I have created another sketch for David.
Quote
You can add a test in the main display part to skip that set of shiftouts while EEPROM_Reading is high for example, or only allow memory readback while time is not running.

Not sure how to do this or exactly what you mean?  
Quote
keep thinking about what you want to occur & when and how you could make that happen

Objective: I would want to be able to go up and down through the lap times that have been saved.
How?: Maybe while the time is running it is not the best time to scroll through the times?? Maybe it would be best to only allow scrolling after the unit has been reset and showing 00:00:00?

I was thinking Robert that when I ran the sketch before it only showed me the last recorded time.. is this because we scrolled 'up' from the highest address meaning we should have started at the first address? Just a thought?  :-/

David_Rudla

#124
Jan 17, 2011, 05:42 pm Last Edit: Jan 17, 2011, 05:43 pm by David_Rudla Reason: 1
Hi Warren, at this time should be run, but I do not know how to buttons should be run, please test it. And write diferencies between both versions. Should be the same.... And there is again two parts of code...  :)

Code: [Select]

#include <EEPROM.h>

// Variables
unsigned long currentmicros = 0;
unsigned long previousmicros = 0;
unsigned long interval = 10000;
unsigned long elapsedmicros = 0;

volatile byte hundredths= 0;
volatile byte tenths = 0;
volatile byte ones_seconds = 0;
volatile byte tens_seconds = 0;
volatile byte ones_minutes = 0;
volatile byte tens_minutes = 0;
volatile byte ones_hours = 0;
volatile byte tens_hours = 0;

byte copy_hundredths= 0;
byte copy_tenths = 0;
byte copy_ones_seconds = 0;
byte copy_tens_seconds = 0;
byte copy_ones_minutes = 0;
byte copy_tens_minutes = 0;
byte copy_ones_hours = 0;
byte copy_tens_hours = 0;

// Variables for work with EEPROM
int value;
int EEPROM_address = 0;
byte byte_to_read = 0;
byte byte_to_write = 0;
byte EEPROM_writing =0;
byte EEPROM_reading =0;
byte EEPROM_read =0;

// start_pausetime, end_pausetime used for button debounce
unsigned long start_pausetime = 0;  
unsigned long end_pausetime = 0;
unsigned long elapsed_pausetime = 0;

// Table for 7segments - numbers light up different segments of a digit
int segdisp[10] = {63,6,91,79,102,109,125,7,127,111 }; //segment references using 74HC595 Shift Registers

// Hardware setup:
// Displays:
byte latchpin = 8; // connect to pin 12 on the 74HC595
byte clockpin = 12; // connect to pin 11 on the 74HC595
byte datapin = 11; // connect to pin 14 on the 74HC595

// Buttons and states
volatile byte memory_up_button_state = 0;
byte memory_up_button = 10;

volatile byte reset_button_state = 0;
byte reset_button = 2;

volatile byte pause_button_state = 0;
byte pause_button = 6;

// Flags
volatile byte paused = 0;
volatile byte started = 0;
volatile byte time_update = 0;


void setup()
{
 // Hardware setup:
 Serial.begin (115200);

 // Outputs
 pinMode(latchpin, OUTPUT);
 pinMode(clockpin, OUTPUT);
 pinMode(datapin, OUTPUT);

 // Inputs
 pinMode(memory_up_button, INPUT);
 digitalWrite (memory_up_button, HIGH); // enable pullup

 pinMode(pause_button, INPUT);
 digitalWrite (pause_button, HIGH); // enable pullup

 pinMode(reset_button, INPUT);
 digitalWrite (reset_button, HIGH); // enable pullup

 //First test of display:
////  Serial.println ("Test displays routine");
 Test_Display ();
}

//---------------------------- Main loop--------------------------------------------------------------------------------------------
void loop()
{
 //Memory Up Button Here
 memory_up_button_state = digitalRead (memory_up_button);
 if (memory_up_button_state == 0 | paused == 1)
 {
  //  Serial.println ("Memory up pressed");
   /* add in paused check, lets us finish reading after button goes back high
    if the lap times seem to read out/udpate more than once on a button push, may need to add in time check delay (ex. check
    millis, make sure 1000 goes by before button is read again) so don't get false read commands from button bouncing */

   EEPROM_reading = 1;
   value = EEPROM.read(EEPROM_address);

   if (EEPROM_reading == 1)
   {
    //  Serial.println ("Should be Read_from_EEPROM here:");
     Read_from_EEPROM ();
    //  Serial.println ("Should be Display here:");
     Display();
   }//End of EEPROM reading
 } // End of checking memory button state

 {//Reset Button Here
   reset_button_state = digitalRead (reset_button);
   if (reset_button_state == 0)
   {
    //  Serial.println ("Reset button pressed");
     paused = 1;
    //  Serial.println ("Should be Counters_to_zero here:");
     Counters_to_zero ();

     time_update = 0;
    //  Serial.println ("Should be Display here:");
     Display();
     started = 0;
     paused = 0;
   } // End of reset_button_state == 0

   {// If not started, read the pause button, set started flag once pressed
     pause_button_state = digitalRead (pause_button);
     if (pause_button_state == 0 & started == 0)
     {
       // Start - first time Pause button pressed, display running
       started = 1;
       start_pausetime = millis(); // start_pausetime, end_pausetime used for button debounce
      //  Serial.println ("Start - first time Pause button pressed, display running");
     }

     // when started flag is pressed, start counting in 10mS increments
     if (started == 1)
     {
       currentmicros = micros();  // read the time.
       elapsedmicros = currentmicros - previousmicros;

       if (elapsedmicros >= interval) // 10 milliseconds have gone by
       {
         previousmicros  = previousmicros + elapsedmicros;  // save the time for the next comparison
         time_update = 1; // set flag to shift out the new time
       }
       if (time_update == 1) // no updating if not at 10ms interval, skip this whole section
       {
         time_update = 0; // reset for next pass thru
        //  Serial.println ("Should be Count here:");
         Count();
       }
       if (paused == 0)
       {
         //not paused, update the display
        //  Serial.println ("Pause button pressed second time, display stopped");
         // counters are all updated now, just do the shiftout one time here:
        //  Serial.println ("Should be Display here:");
         Display ();
       }


       // read the pause button, set a flag if pressed, capture the time it was pressed, reset the lap time
       end_pausetime = millis();

       if (paused == 0 & (end_pausetime - start_pausetime > 500)) // not paused, debounced if had been (long time used due to crappy button)
       {
         pause_button_state = digitalRead(pause_button);
         //PAUSED HERE
         if (pause_button_state == 0)
         {
           paused = 1;
           start_pausetime =  end_pausetime;
           //MAKE COPPIES
           copy_hundredths= hundredths;
           copy_tenths = tenths;
           copy_ones_seconds = ones_seconds;
           copy_tens_seconds = tens_seconds;
           copy_ones_minutes = ones_minutes;
           copy_tens_minutes = tens_minutes;
           copy_ones_hours = ones_hours;
           copy_tens_hours = tens_hours;
           //WRITE THE COPPIES TO EEPROM
           if (EEPROM_writing == 1)
           {
            //  Serial.println ("Should be Write_to_EEPROM here:");
             Write_to_EEPROM ();
           } // End of EEPROM_writing == 1
           currentmicros = micros();  // read the time.
           previousmicros = currentmicros;
           elapsedmicros = currentmicros - previousmicros;
          //  Serial.println ("Should be Counters_to_zero here:");
           Counters_to_zero ();

         }// End of pause_button_state == 0
       } // End of not paused, debounced if had been (long time used due to crappy button)

       // read the pause button; unpause to let time display be shown
       end_pausetime = millis();
       if (paused ==1 & (end_pausetime - start_pausetime >500)) // sitting in paused state now, is debounced
       {
         pause_button_state = digitalRead (pause_button);
         if (pause_button_state == 0)
         {
           paused = 0;// back to unpaused
           start_pausetime = end_pausetime;
         } // End of pause_button_state == 0
       }// End of sitting in paused state now, is debounced
     }// End of when started flag is pressed, start counting in 10mS increments
   }// End of If not started, read the pause button, set started flag once pressed
 }// End of Reset Button Here

} // end of main loop
//---------------------------- End of main loop-------------------------------------------------------------------------------------


//---------------------------- Display on displays----------------------------------------------------------------------------------
void Display ()
{
//  Serial.println ("Display");
 digitalWrite(latchpin, LOW); // send the digits down to the shift registers!
 shiftOut(datapin, clockpin, MSBFIRST, segdisp[hundredths]); // print the hundredths digit
 shiftOut(datapin, clockpin, MSBFIRST, segdisp[tenths]);     // print the tenths digit
 shiftOut(datapin, clockpin, MSBFIRST, segdisp[ones_seconds]); // print the lower seconds digit
 shiftOut(datapin, clockpin, MSBFIRST, segdisp[tens_seconds]); // print the upper seconds digit
 shiftOut(datapin, clockpin, MSBFIRST, segdisp[ones_minutes]); // print the lower sinutes digit
 shiftOut(datapin, clockpin, MSBFIRST, segdisp[tens_minutes]); // print the upper minutes digit
 digitalWrite(latchpin, HIGH);
 if (tenths == 0 && hundredths == 0) // update on screen once a second
 {
   Serial.print (tens_hours, DEC);
   Serial.print (ones_hours, DEC);
   Serial.print (":");
   Serial.print ( tens_minutes, DEC);
   Serial.print (ones_minutes, DEC);
   Serial.print (":");
   Serial.print (tens_seconds, DEC);
   Serial.print(ones_seconds, DEC);
   Serial.print (".");
   Serial.println (tenths, DEC);
  //  Serial.println (hundredths, DEC);
 }// End of serial send
}

//---------------------------- End of Display on displays---------------------------------------------------------------------------

David_Rudla

Second part:
Code: [Select]


//---------------------------- Update counters--------------------------------------------------------------------------------------
void Count ()
{   // when started flag is pressed, start counting in 10mS increments
//  Serial.println ("Count");
 hundredths = hundredths +1;
 if (hundredths == 10)
 {
   hundredths = 0;
   tenths = tenths +1;
 }
 if (tenths == 10)
 {
   tenths = 0;
   ones_seconds = ones_seconds +1;
 }
 if (ones_seconds == 10)
 {
   ones_seconds = 0;
   hundredths = hundredths +3;   // Speed up the clock!
   tens_seconds = tens_seconds +1;
 }
 if (tens_seconds == 6)
 {
   tens_seconds = 0;
   hundredths = hundredths +6;   // Speed up the clock!
   ones_minutes = ones_minutes +1;
 }
 if (ones_minutes == 10)
 {
   ones_minutes = 0;
   tens_minutes = tens_minutes +1;
 }
 if (tens_minutes == 6)
 {
   tens_minutes = 0;
   ones_hours = ones_hours +1;  // not used in actual application, only here for stability test over longer time periods
 }
 if (ones_hours == 13) // not used in actual application, only here for stability test over longer time periods
 {
   ones_hours = 0;
   tens_hours = tens_hours +1;
 }
}


//---------------------------- End of update counters-------------------------------------------------------------------------------


//---------------------------- Function test of displays----------------------------------------------------------------------------
void Test_Display ()
{
//  Serial.println ("Test_Display");
 // loop to flash the displays, in pseudo code
 byte i=0;
 byte toggle=0;
 byte displaychar;
 while (i<26) // loop thru as many times as you want
 {
   toggle=1-toggle; // results in toggle = 1,0,1,0 ...
   if (toggle==1)
   {
     displaychar = 8;
   }
   else
   {
     displaychar = 11;
   }
   digitalWrite(latchpin, LOW); // send the digits down to the shift registers!
   shiftOut(datapin, clockpin, MSBFIRST, segdisp[displaychar]); // for digit 1
   shiftOut(datapin, clockpin, MSBFIRST, segdisp[displaychar]);
   shiftOut(datapin, clockpin, MSBFIRST, segdisp[displaychar]);
   shiftOut(datapin, clockpin, MSBFIRST, segdisp[displaychar]);
   shiftOut(datapin, clockpin, MSBFIRST, segdisp[displaychar]);
   shiftOut(datapin, clockpin, MSBFIRST, segdisp[displaychar]);
   digitalWrite(latchpin, HIGH);
   delay (100);
   i=i+1;
 }
 delay (500);
 digitalWrite(latchpin, LOW); // send the digits down to the shift registers!
 shiftOut(datapin, clockpin, MSBFIRST, segdisp[0]); // print the hundredths digit
 shiftOut(datapin, clockpin, MSBFIRST, segdisp[0]); // print the tenths digit
 shiftOut(datapin, clockpin, MSBFIRST, segdisp[0]); // print the lower seconds digit
 shiftOut(datapin, clockpin, MSBFIRST, segdisp[0]); // print the upper seconds digit
 shiftOut(datapin, clockpin, MSBFIRST, segdisp[0]); // print the lower sinutes digit
 shiftOut(datapin, clockpin, MSBFIRST, segdisp[0]); // print the upper minutes digit
 digitalWrite(latchpin, HIGH);
}

//---------------------------- End of Function test of displays---------------------------------------------------------------------


//---------------------------- Read from EEPROM---------------------------------------------------------------------
void Read_from_EEPROM ()
{
//  Serial.println ("Read_from_EEPROM");
 switch (byte_to_read)
 {
 case 1: // hundredths
   copy_hundredths = EEPROM.read(EEPROM_address);
   byte_to_read = byte_to_read+1; // increment for next digit
   EEPROM_address = EEPROM_address+1; // increment for next bye
   break;
 case 2: // copy_tenths
   copy_tenths = EEPROM.read(EEPROM_address);
   byte_to_read = byte_to_read+1; // increment for next digit
   EEPROM_address = EEPROM_address+1; // increment for next bye
   break;
 case 3: // copy_ones_seconds
   copy_ones_seconds = EEPROM.read(EEPROM_address);
   byte_to_read = byte_to_read+1; // increment for next digit
   EEPROM_address = EEPROM_address+1; // increment for next bye
   break;
 case 4: // copy_ones_minutes
   copy_ones_minutes = EEPROM.read(EEPROM_address);
   byte_to_read = byte_to_read+1; // increment for next digit
   EEPROM_address = EEPROM_address+1; // increment for next bye
   break;
 case 5: // copy_tens_minutes
   copy_tens_minutes = EEPROM.read(EEPROM_address);
   byte_to_read = byte_to_read+1; // increment for next digit
   EEPROM_address = EEPROM_address+1; // increment for next bye
   break;
 case 6: // tens_minutes
   ones_hours = EEPROM.read(EEPROM_address);
   byte_to_read = 1; // reset for next groupex.
   EEPROM_address = EEPROM_address+1; // increment for next group
   EEPROM_reading = 0; // all bytes read
   started = 0;
   paused = 0;
   break;

   EEPROM_address = EEPROM_address + 1;

   if (EEPROM_address == 512)
   {
     EEPROM_address = 0;
   }  // end of end-of-address check
 } // end if switch-case

} // end of EEPROM reading

//---------------------------- End of read from EEPROM---------------------------------------------------------------------

//---------------------------- Write to EEPROM---------------------------------------------------------------------
void Write_to_EEPROM ()
{
//  Serial.println ("Write_to_EEPROM");
 switch (byte_to_write)
 {
 case 1: // hundredths
   EEPROM.write (EEPROM_address, copy_hundredths);
   byte_to_write = byte_to_write+1; // increment for next digit
   EEPROM_address = EEPROM_address+1; // increment for next bye
   break;
 case 2: // copy_tenths
   EEPROM.write (EEPROM_address, copy_tenths);
   byte_to_write = byte_to_write+1; // increment for next digit
   EEPROM_address = EEPROM_address+1; // increment for next bye
   break;
 case 3: // copy_ones_seconds
   EEPROM.write (EEPROM_address, copy_ones_seconds);
   byte_to_write = byte_to_write+1; // increment for next digit
   EEPROM_address = EEPROM_address+1; // increment for next bye
   break;
 case 4: // copy_ones_minutes
   EEPROM.write (EEPROM_address, copy_ones_minutes);
   byte_to_write = byte_to_write+1; // increment for next digit
   EEPROM_address = EEPROM_address+1; // increment for next bye
   break;
 case 5: // copy_tens_minutes
   EEPROM.write (EEPROM_address, copy_tens_minutes);
   byte_to_write = byte_to_write+1; // increment for next digit
   EEPROM_address = EEPROM_address+1; // increment for next bye
   break;
 case 6: // tens_minutes
   EEPROM.write (EEPROM_address, copy_tens_minutes);
   byte_to_write = 1; // reset for next group
   EEPROM_address = EEPROM_address+1; // increment for next group
   EEPROM_writing = 0; // all bytes written
   break;
 } // End of switch
} // end of EEPROM writing

//---------------------------- End of write to EEPROM---------------------------------------------------------------------

//---------------------------- Counters to zero---------------------------------------------------------------------

void Counters_to_zero ()
{
//  Serial.println ("Counters_to_zero");
 hundredths= 0;
 tenths = 0;
 ones_seconds = 0;
 tens_seconds = 0;
 ones_minutes = 0;
 tens_minutes = 0;
 ones_hours = 0;
 tens_hours = 0;
}

//---------------------------- End of Counters to zero---------------------------------------------------------------------



Serial communication I used for debbuging because I have not 7 segments....

CrossRoads

Reading while time is not being updated would probably be good. You said originally something like you wanted to save the lap times and read them out at home.
If you now want to read them out trackside, that is certainly doable.
Reading them while the timer is not running is probably a little cleaner.

Your code is getting kind of long to keep posting here. Can you upload it somewhere where its all in 1 piece for easier vieiwing?

For readback, might be simpler to have another button, like a toggle switch; one side is memory readback, other side is normal operation.

When time is running, after the 10mS update, set the time_update flag to 1 show it is to be updated after the last digit update
if (paused ==0) {time_udpate =1;} // lets the display update

In the memory readout section, udpate the variables to be updated,
and set the same flag
if (time_running == 0 && eeprom_read_complete ==1) {time_update = 1;}

Put a change in your readout code:
{(if time_update == 1){  // doesn't matter who did the update
//do all the shiftouts
time_udpate = 0;  // clear for next time
}

So your code will have a few sections:
0. Add a new button, laptime/readback (can be momentary also, with a flag indicating which mode)
1. If laptime, Read the start/stop button, start time running/stop it.
2. If laptime, Read the lap button, no display updates with button is pressed, data saved to EEPROM, laptime reset to 0.
3. If readback, read the memory up button, when pushed read the EEPROM & display. If pushed again, update the address counter, read the next set, & display.

So you're pretty close, just need your logic squared away some.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Warren Reeve

#127
Jan 17, 2011, 09:02 pm Last Edit: Jan 17, 2011, 10:26 pm by warrenreeve Reason: 1
Hi Robert & David, not long in but will get round to things shortly. In the meantime Robert I have put your code and David's code on a web page here; http://www.warrenreeveracing.co.uk/stopwatch_code.htm
I haven't updated as yet but let me know if that page will be ok.  :)

[glow]EDIT:[/glow]
Hi David I have updated the code you gave me and the page above with your code.
Results are: It counts as normal, when you hit the pause button once nothing happens and it continues.. when you press the second time it restarts from 0. :-/

The memory up button does nothing.

Warren Reeve

#128
Jan 17, 2011, 11:19 pm Last Edit: Jan 17, 2011, 11:36 pm by warrenreeve Reason: 1
Just a quick note Robert, I notice that when the reset button is pressed (after doing some laps/pauses) and we are sitting on 00:00:00 if I then press the memory up button I will get the last lap time ONLY and because we are in reset mode there is no flickering. I tried to put in some code     memory_up_button = HIGH; and     memory_up_button = LOW; but it just didn't work. I knew it was wrong but thought I'd give it a shot. Basically I was trying to tell it to go LOW when running and HIGH when in Reset.
Although even when using memory up we only get 1 time.  :-/

I will keep tinkering here Robert but to be honest I'm not sure what I am doing.

[glow]EDIT[/glow]
Hi Robert, another note. I don't think the lap time is being written to eeprom because when I use the reset button on the Arduino and then use the memory up button again there is nothing to show.. is this because we are only 'floating' the result/lap time and also why we are only retrieving the last lap time?
Warren

CrossRoads

Warren,
Am looking into it.

I layed it out a little differently to make it easier to follow.
I'll send you the updated .pde file, code is split up with tabs.

Got it to compile, need to sprinkle in some print statements to check what its doing, then will burn it & try.
You can pull the file from here to try it.
http://www.crossroadsfencing.com/stopwatch

files are called:

stopwatch_17Jan.pde
a_presetup.pde
b_setup.pde
c_void_loop.pde
d_start_stop.pde
e_pause_memory_write.pde
f_memory_read.pde
g_reset.pde
h_dispay_update.pde

Put them all in a directory called stopwatch_17Jan.

Robert
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Warren Reeve

Quote
You can pull the file from here to try it.
http://www.crossroadsfencing.com/stopwatch

Hi Robert, I'm just about to head off to bed as it's almost midnight here.. I'm absolutely shattered  :-? Lol

I tried the link you gave but it doesn't exist?? I put .htm and .html after the link but still nothing there??
I will have a look tomorrow again. Really appreciate all the help.
Warren

CrossRoads

http://www.crossroadsfencing.com/stopwatch_17Jan/stopwatch_17Jan.pde

The code is there, not sure how to download it. PM with e-mail, I'll send it that way.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

David_Rudla

Hi Robert,
thanks for your great work. The code has been changed, and this one is easier to read. I have a question:
Are all key debounced?
And the second - because the routine of writing and reading EEPROM take much time, would not it be better to use interrapt timer 2 to count the time? Thanks for your reply and your patience with me

CrossRoads

David,
The code was kind of evolving with the new functionality & tweaking to make it work.
There's only 3 keys (start/pause, reset, memory read, not sure if debouncing got added for all 3 yet.
The reading/writing takes 3.3mS. The time was being updated every 10mS.
Writing one byte on 6 consecutive time updates seemed doable. I used an oscilloscope to took at how long it took to do the byte updates and the shiftouts to the shift registers - it was like 0.02mS and 0.8mS - leaving over 9mS for the code to deal with the EEPROM accesses.
The EEPROM reading will take place when the stopwatch is stopped, so no issue there either.
Does not seem to me that interrupts are needed.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Warren Reeve

#134
Jan 18, 2011, 10:17 am Last Edit: Jan 18, 2011, 10:21 am by warrenreeve Reason: 1
PM sent Robert. Thanks  :)

Also updated my email in the link below in contact info.

Go Up