Gym Interval Timer

    Someone at work was looking for a Gym Time Interval sequencer, and originally the request started out as a flashing LED to indicate what time interval was currently active, and from there it grew to a programmable application with audible features!

    The original request could have been simply done with a  555 timer and a handful of discrete components, it could also have been "time adjustable" with this method, but actual time frames would not be known unless a crude rotary switch approach was taken for a couple of 'preset' times. The solution: a PIC micro of course.

  • The features desired for the project;
  • Flashing LED's to indicate what interval is currently active
  • Buzzer to sound for a programmable time frame at the end of the intervals
  • Both interval and the buzzer time frames are programmable and are stored in the PIC's EEPROM for automatic selection on next power-on
  • Pause feature

    Due to the amount of user data required for the project, I chose to use a keypad rather then a couple of switches. Now, with a little help with some programming, the user can enter data easily and quickly. The program itself does have a couple of "Spency" tricks to it, but it is fairly simple at the end of the day. The first step is to setup the Timer 2 peripheral of the PIC, as it forms the back bone for the timing.

    From there, The program checks if the user has ever entered data before, it achieves this by checking a specific EEPROM address for the value "170". This EEPROM byte is only written too when the program updates the interval settings, without it being set indicates the interval settings are not user defined (i.e. nothing has ever been written before)

    Now the program enters a continuous loop, where each interval is serviced. The flashing is achieved by simply checking the milliseconds register for a value above 500 or less. The buzzer is serviced when the time remaining is equal too or less then the buzzer user set time frame. 

    I used some extremely bright 5mm LED's. They run at 100mA and produce about 13 lumens (much brighter then 'bright' 20000mcd LED's). I prefer using these LED's for projects that need high brightness as they are easy to work with in the 5mm round package. As you can see, I used some 5mm LED holders in the final design:

 

    The box, keypad, PCB and switch were also brought from Core Electronics. The light can easily be diffused to a larger surface area by using any white container, I used a measuring cup in the above images as an example. I didn't drill in any permanent fixture for diffusing as I wasn't sure on the end lighting requirements and the environment it would be in - its an easy mod to add on though.

    The wiring diagram is shown below. I had to add a heatsink to the 7805 voltage regulator as it did heat up to about 60 degrees C with a 9-12 volts on the input.

 

    And finally the program itself. The single line LCD's I used reference the first 8 characters as line 1 and the second 8 characters as line 2 (just in case your wondering why it writes to line 2 here and there). Also, the internal oscillator library module is a User Library I made to ensure the PIC is running at 8Mhz from the get go, as other Includes initializations are serviced before the main program, leaving the PIC at a dismal 32Khz without it.

Device = 18F2520
Clock = 8
Config OSC = INTIO67

#option KEYPAD_PORT = PORTB
#option LCD_DATA = PORTC.4
#option LCD_RS = PORTC.0
#option LCD_EN = PORTC.1
Include "INTOSC8.bas"
Include "LCD.bas"
Include "convert.bas"
Include "Keypad12.bas"
Include "EEPROM.bas"

Dim TMR2IE As PIE1.1,         // TMR2 interrupt enable
    TMR2IF As PIR1.1,         // TMR2 overflow flag
    TMR2ON As T2CON.2,        // Enables TMR2 to begin incrementing
    mS As Word,               // mS register
    S As Word,                // Second register
    EEPROMvr As Byte          // EEPROM Verify Byte
    
    
Dim 
    Interval_1 As Word,
    Interval_2 As Word,
    Time_LED_1 As PORTA.1,
    Time_LED_2 As PORTA.2,
    Buzzer As PORTA.0,
    LastS As Word,
    Buzzer_Time As Word
    
Interrupt TMR2_Interrupt()
    Save(0)                   // Back up system variables
    If TMR2IF = 1 Then        // Check if the interrupt was from TMR2
        TMR2IF = 0            // Clear the TMR2 interrupt flag
        mS = mS + 4           // Increment the mS counter
        If mS = 1000 Then
            mS = 0
            S = S + 1
        EndIf
    EndIf                     //
    Restore                   // Restore system variables
End Interrupt

Private Sub TMR2_Initialize()
    TMR2ON = 0                // Disable TMR2
    TMR2IE = 0                // Turn off TMR2 interrupts    
    T2CON.0 = 1               //  00 = Prescaler is 1
    T2CON.1 = 0               //  01 = Prescaler is 4
            	              //  1x = Prescaler is 16 
    PR2 = 249                 // TMR2 Period register PR2   
    T2CON.3 = 1               //  0000 = 1:1 postscale
    T2CON.4 = 1               //  0001 = 1:2 postscale
    T2CON.5 = 1               //  0010 = 1:3 postscale...
    T2CON.6 = 0               //  1111 = 1:16 postscale    
    TMR2 = 0                  // Reset TMR2 Value    
    TMR2IE = 1                // Enable TMR2 interrupts
    TMR2ON = 1                // Enable TMR2 to increment
    mS = 0
    Enable(TMR2_Interrupt)
End Sub    

Function WaitForKey() As Byte
    Result = 0
    While Result = 0                  // Wait for a key press
        Result = Keypad12.Value       //  ...
    Wend
End Function

Function GetNewVal(Line As Byte) As Word
    Dim Counter As Byte
    Dim Key As Byte    
    LCD.Command(cmdCursorOn)
    Counter = 1
    For counter = 1 To 3      
        LCD.MoveCursor(Line,Counter)    
        Key = WaitForKey
        If Key <> 10 And Key <> 12 Then
            If Key = 11 Then 
                Key = 0
            EndIf
            Select counter
                Case 1 
                    Result = Key * 100
                Case 2
                    Result = Result + (Key * 10)
                Case 3
                    Result = Result + Key
            End Select
            LCD.WriteAt(Line,Counter,Convert.DecToStr(Key,1))     
        Else
            Dec(counter)
        EndIf 
        Keypad12.Debounce               
    Next
    LCD.Command(cmdCursorOff)
    LCD.Cls    
End Function

Sub Set_Times()
    LCD.Cls
    LCD.WriteAt(1,1,"Time 1: ")
    LCD.WriteAt(2,1, Convert.DecToStr(Interval_1,3), " Secs")
    Interval_1 = GetNewVal(2)
    LCD.WriteAt(1,1,"Time 2: ")
    LCD.WriteAt(2,1, Convert.DecToStr(Interval_2,3), " Secs")
    Interval_2 = GetNewVal(2)
    LCD.WriteAt(1,1,"Buzzer:")
    LCD.WriteAt(2,1, Convert.DecToStr(Buzzer_Time,3), " Secs")
    Buzzer_Time = GetNewVal(2)        
    EE.Write(0,Interval_1, Interval_2, Buzzer_Time, 170)        
End Sub

Sub Pause()
    TMR2ON = 0
    Buzzer = 0
    Keypad12.Debounce
    While Keypad12.Value = 0
    Wend   
    Keypad12.Debounce 
    TMR2ON = 1    
End Sub

// start of program...

// make PORTA all digital IO's
ADCON0.0 = 0
ADCON1 =  $0F

Low(Time_LED_1)
Low(Time_LED_2)
Low(Buzzer)
EEPROMvr = 0

// setup and enable TMR2
TMR2_Initialize               

// initialize the LCD
DelayMS(150)
LCD.Cls

// splash screen..
LCD.WriteAt(1,1, "Made By")
LCD.WriteAt(2,1, "Spency")
DelayMS(1500)
LCD.Cls

EE.Read(0, Interval_1, Interval_2, Buzzer_Time, EEPROMvr)

If EEPROMvr <> 170 Then   
   Buzzer_Time = 0
   Interval_1 = 0
   Interval_2 = 0
   Set_Times   
EndIf 

While True
Reset_Interval:
    S = 0
    WriteAt(1,1,"Time 1:")
    WriteAt(2,5,"Secs")      
    While S < Interval_1 
        If LastS <> S Then       
            WriteAt(2,1,DecToStr(Interval_1 - S,3))
            LastS = S
        EndIf
        If mS > 500 Then
            Time_LED_1 = 1
        Else
            Time_LED_1 = 0
        EndIf
        If Interval_1 - S <= Buzzer_Time Then
            Buzzer = 1
        EndIf  
        If  Keypad12.Value = 10 Then
            Pause
        ElseIf Keypad12.Value = 12 Then
            Break
        EndIf
    Wend
    Buzzer = 0
    Time_LED_1 = 0
    If Keypad12.Value = 12 Then
        Set_Times
        GoTo Reset_Interval
    EndIf    
    
    S = 0
    WriteAt(1,1,"Time 2:")
    WriteAt(2,5,"Secs")
    While S < Interval_2       
        If LastS <> S Then       
            WriteAt(2,1,DecToStr(Interval_2 - S,3))
            LastS = S
        EndIf
        If mS > 500 Then
            Time_LED_2 = 1
        Else
            Time_LED_2 = 0
        EndIf
        If Interval_2 - S <= Buzzer_Time Then
            Buzzer = 1
        EndIf
        If  Keypad12.Value = 10 Then
            Pause
        ElseIf Keypad12.Value = 12 Then
            Break
        EndIf       
    Wend
    Buzzer = 0
    Time_LED_2 = 0  
    If Keypad12.Value = 12 Then
        Set_Times
        GoTo Reset_Interval
    EndIf
Wend

 

Skip Navigation Links.

Collapse Site Tutorial IndexSite Tutorial Index
Expand 16F PIC Examples16F PIC Examples
Expand 18F PIC Examples18F PIC Examples
Expand Handy TipsHandy Tips