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

 | Site Tutorial Index |
|  | 16F PIC Examples |
|  | 18F PIC Examples |
|  | Handy Tips |