This example shows how to create a 24-hour time clock on the LAB-X1 using Timer2/PR2 match - with buttons to increment hours, minutes, reset the time to 12:00, and reset the Timer2 tick counter.
Also shown is how to use the 16F1934 IOCBF interrupt flags to recognize button presses in the background. I.E. you don't need to poll port pins to detect a change, and no interrupts required.
Code:
' Name : T246_1934X.pbp
' Compiler : PICBASIC PRO Compiler 2.6
' Assembler : MPASM
' Target PIC : 40-pin 16F1934 or similar
' Hardware : LAB-X1 Experimenter Board
' Oscillator : 4MHz external crystal
' Keywords : LCDOUT
' Description : PICBASIC PRO program to demonstrate using Timer2 for a
' 24 hour format clock. Time is shown on the LCD as Time = 11:14 with
' hours : minutes. The keypad is used to increment hours, minutes, reset
' the time to 12:00, and reset the Timer2 tick counter.
'
' Note: Open the 16F1934.INC file in your PBP directory, and comment out the default
' __config settings.
ASM
__config _CONFIG1, _FOSC_XT & _WDTE_SWDTEN & _PWRTE_ON & _MCLRE_ON & _BOREN_ON & _IESO_ON & _FCMEN_ON
__config _CONFIG2, _PLLEN_OFF & _LVP_OFF & _VCAPEN_OFF & _STVREN_ON & _BORV_25
ENDASM
' Define LCD pins
Define LCD_DREG PORTD
Define LCD_DBIT 4
Define LCD_RSREG PORTE
Define LCD_RSBIT 0
Define LCD_EREG PORTE
Define LCD_EBIT 1
' setup vars for clock
Time Var Word ' accumulates TMR2 to PR2 match counts
Minutes Var Byte ' minutes
Hours Var Byte ' hours
Match Var PIR1.1 ' TMR2 to PR2 match interrupt flag bit
IocFlag Var INTCON.0 ' portb int-on-change flag bit
Gosub Init ' jump to hardware initialization routine
Lcdout $fe,1,"Time = ", #Hours DIG 1,#Hours DIG 0,":",#Minutes DIG 1,#Minutes DIG 0
' setup & start TMR2 after Lcdout
T2CON = %01110110 ' set 1:16 prescale, 1:15 postscale, TMR2 on
Main:
' every 60mS the TMR2IF flag is set, and this routine is entered.
' Plenty of time to do other stuff.
If Match = 1 Then ' has TMR2 matched PR2? (should happen every 60mS)
Match = 0 ' yes. clear TMR2 to PR2 match flag bit PIR1.1
Time = Time + 1 ' increment 60mS count
If Time = 1000 Then ' has 60 seconds (1000*60mS) passed?
Time = 0 ' yes. clear count
Minutes = Minutes + 1 ' increment Minutes
If Minutes = 60 Then ' roll-over from 59 to 0
Minutes = 0 ' zero Minutes count
Hours = Hours + 1 ' and increment Hours count
If Hours = 24 Then ' roll-over from 23 to 0
Hours = 0 ' zero Hours count
Endif
Endif
' Update time on LCD every 60 seconds
Lcdout $fe,$87,#Hours DIG 1,#Hours DIG 0,":",#Minutes DIG 1,#Minutes DIG 0
Endif
Endif
' test for key press
If IocFlag Then ' if keys SW13, 14, 15 or 16 were pressed,
Gosub GetKeys ' get the button/buttons pressed
Endif
Goto Main
' ===========\ Get Keypad Switch Presses /=========== '
GetKeys:
Pause 500 ' crude debounce for key press
' SW13 increments Hours
If IOCBF.4 Then ' IOCBF.4 = 1 when low edge detected on RB4
While PORTB.4 = 0 ' wait for key release
Wend '
Hours = Hours + 1 : Time = 0
If Hours = 24 Then Hours = 0
Endif
' SW14 increments Minutes
If IOCBF.5 Then ' IOCBF.5 = 1 when low edge detected on RB5
While PORTB.5 = 0 ' wait for key release
Wend '
Minutes = Minutes + 1 : Time = 0
If Minutes = 60 Then Minutes = 0
Endif
' SW15 zeros Time "tick" counter
If IOCBF.6 Then ' IOCBF.6 = 1 when low edge detected on RB6
While PORTB.6 = 0 ' wait for key release
Wend '
Time = 0
Endif
' SW16 resets clock to 12:00
If IOCBF.7 Then ' IOCBF.7 = 1 when low edge detected on RB7
While PORTB.7 = 0 ' wait for key release
Wend '
Hours = 12 : Minutes = 0 : Time = 0
Endif
IOCBF = 0 ' reset all int-on-change bits on exit
IocFlag = 0
' Update LCD on each change
Lcdout $fe,$87,#Hours DIG 1,#Hours DIG 0,":",#Minutes DIG 1,#Minutes DIG 0
Return
Init:
ANSELA = 0 ' porta all digital
ANSELB = 0 ' portb all digital
ANSELD = 0 ' portd all digital
ANSELE = 0 ' porte all digital
OPTION_REG.7 = 0 ' enable PORTB pullups
PORTB = 0 ' RB3 low
TRISB = %11110111 ' RB3 = 0 for output to keys 13, 14, 15, 16
WPUB = %11110000 ' weak pull-ups on for ----> RB4, 5, 6, 7
IOCBP = 0 ' positive edge disabled
IOCBN = %11110000 ' negative edge int-on-change enabled for keys
TRISD = 0 ' PORTD all outputs
INTCON = 0 ' not using interupts. Just monitoring int flag bits
Time = 0 ' clear TMR2 to PR2 match counter
Hours = 10 ' set clock starting hour to 10 here
Minutes = 16 ' set clock starting minutes to 16 here
' TMR2 increments from 0 until it matches the value in the PR2 register.
' The match automatically resets Timer2 and sets the Timer2 interrupt flag
' bit PIR1.1.
PR2 = 249 ' 0 to 249 = 250. 250*16*15*1uS=60mS
Match = 0 ' clear PIR1.1 match flag bit
Pause 100 ' Wait for LCD to start
Return ' Return to caller
End
Bookmarks