' Resettable timer
'
' TMR0 used for timekeeping
' RB0 is the button input (start/stop)
' MCLR will reset the time


' ---------------------------------------------------------------
' LCD Variables required by <libs\interface\4BitLCD.bas>

Dim LCD_D4 @ PORTD.0 As Boolean, LCD_D4_DIR @ TRISD.0 As Boolean
Dim LCD_D5 @ PORTD.1 As Boolean, LCD_D5_DIR @ TRISD.1 As Boolean
Dim LCD_D6 @ PORTD.2 As Boolean, LCD_D6_DIR @ TRISD.2 As Boolean
Dim LCD_D7 @ PORTD.3 As Boolean, LCD_D7_DIR @ TRISD.3 As Boolean
Dim LCD_E  @ PORTA.1 As Boolean, LCD_E_DIR  @ TRISA.1 As Boolean
Dim LCD_RW @ PORTA.2 As Boolean, LCD_RW_DIR @ TRISA.2 As Boolean
Dim LCD_RS @ PORTA.3 As Boolean, LCD_RS_DIR @ TRISA.3 As Boolean

Include <libs\interface\4BitLCD.bas>	' load the LCD library


' --------------------------------------------------------------
' Hardware definitions
Dim btn@PORTB.0 As Boolean	' The button is at PORTB Bit 0


' Global variables
Dim run_mode 		As Boolean	' 1 = run mode
Dim T0Overflows 	As uByte	' keeps track of TMR0 overflows
Dim elapsedSeconds 	As uByte	' timer variable
Dim elapsedMinutes 	As uByte	' timer variable
Dim elapsedHours 	As uByte	' timer variable
Dim updateDisplayFlg 	As Boolean	' signal the Display Task to update the display
Dim buttonState 	As Boolean	' holds the state of the button on the last pass 



' The program starts here
Sub main()
    Call init()			' initialize everything here
	
    While 1
        clrwdt			' clear the watchdog timer
        Call buttonCheck()	' react to a button press
        Call updateDisplay()	' update the display
    End While
	
End Sub

' handel a TMR0 interrupt
Sub isr() IntHigh

    If TMR0IF=1 Then
        TMR0IF=0		' clear the interrupt flag
	   
        If run_mode=1 Then	' do not update the time if we are not in run mode
	   
            T0Overflows = T0Overflows + 1
		   
            If T0Overflows > 61 Then		 	' 61 overflows in 1S
                T0Overflows = T0Overflows - 61		' remove 100mS worth of overflows
		   		
                updateDisplayFlg=1			' it's time to update the display
                elapsedSeconds = elapsedSeconds+1	' add to the seconds
		   		
                If elapsedSeconds=60 Then
                    elapsedSeconds=0			' seconds overflowed
                    elapsedMinutes=elapsedMinutes+1	' add to the minutes
					
                    If elapsedMinutes=60 Then
                        elapsedMinutes=0		' minutes overflowed
                        elapsedHours=elapsedHours+1	' add to the hours
                    End If	   				   			
                End If
            End If	   
        End If
    End If
	
End Sub


' if the user has pressed the button, then toggle the running mode
' of the timer.  Also wait for the user to release the button before
' registering another button press.
Sub buttonCheck()

    If buttonState=0 Then
    ' the button was not previously pressed
        If button(1)=1 Then	' did the user press the button?
            btg run_mode	' yes so toggle the running mode
            buttonState=1	' the button is currently pressed
        End If
    Else
        ' the button was previously pressed
        If button(0)=1 Then buttonState=0	' the button has been released
    End If
End Sub

Sub init()
    ' Timer0 Configuration:
    ' Timer0: ON
    ' 8 Bit Read/Write Mode
    ' Clock Source: Internal instruction cycle
    ' Edge Select: High to Low
    ' Prescaler: ON
    ' Prescale Value: 1:64
    ' Time/Bit:  64u S
    ' Overflow: 16.384m S
    ' Overflows/Second: 61.03516
    T0CON=0xD5
	  
    ADCON1=0x87			' ADC off
	  
    Call LCDinit()		' initialize the LCD
	  
    ' Interrupt configuration:
    RCON = RCON And 127
    TMR0IF=0: TMR0IE=1 		' Timer 0 Interrupt enabled
    GIE=1
	
    ' initialize variables
    run_mode=0			' not in run mode to start
    T0Overflows=0		' no overflows yet
    elapsedSeconds=0		' reset the timer
    elapsedMinutes=0		' reset the timer
    elapsedHours=0		' reset the timer
    updateDisplayFlg=1		' force an LCD update to begin with
    buttonState=0		' button has not yet been pressed

End Sub

Sub updateDisplay()
    Dim s(10) As String
	
    If updateDisplayFlg=1 Then
        updateDisplayFlg=0		' reset the flag
		
        Call LCDcls()
        Call str(elapsedHours,s): Call LCDputs(s): Call LCDputc(":")
        Call str(elapsedMinutes,s): Call LCDputs(s): Call LCDputc(":")
        Call str(elapsedSeconds,s): Call LCDputs(s)
				
    End If
End Sub

' Return 1 if the selected state is true
'
' Parameters:
'	WREG	The value (or button state) to look for

Function button(WREG As uByte)
    Dim val As uByte
	
    val=WREG
	
    Repeat 5	' check 5 times
        If PORTB.0<>val.0 Then
            val=0: return	' return FALSE
        End If
		
        delayms(10)		' wait for 10 milliseconds
		
    End Repeat	

    val=1	' the button is in the requested position	
	
End Function val