I am trying to figure out how to use a overflow interrupt on TMR1 to semi accurately measure pulses per time period for a future project.
The posted program was made to signal a TMR1 interrupt after 100ms, and update Sec, Min, and Hours.
Additionally, the program was designed to start at a specific time so I could track the microcontroller time versus real time.
The program loses about 14min per hour.
Some of the code came from suggestions found on the GCBASIC forums.
I have racked my brains, and studied the forums trying to figure out why there is so much difference between the microcontrollers time and real time.
' This is a program to test the accuracy of the internal timer1
' Hardware configuration
#chip 16F684, 4
#config osc = int
' LCD connection settings
#define LCD_IO 2 'Set up the LCD to use 4 bit operation
' Define the 2 LCD Clock and Data Lines
#define LCD_DB PORTC.2
#define LCD_CB PORTC.1
Dim Counter As Word
Hour = 8: Min = 30: Sec = 0: Counter = 0
'Clock pulse frequency is 4/4 = 1 MHz
'Divided by 1 by prescaler (PS1_1/2), timer incremented at frequency of .5 MHz
' = every 2 us
' If cleared, timer overflows after 65536 * 2 us = every 131.072 ms
' Timer will overflow after 131.072 ms
' We need it to overflow after 31.072, so the timer must have a value loaded into it
' Need to load TMR1H, TMR1L with value that they will have after 31.072 ms - then it will count to 131.072, taking 100.00 ms
' Value = 65536 * (31.071 / 131.072) = 15535.5
' High byte of this is 60, low byte is 175 (60 * 256 + 175 = 15535)
' So, we need to set TMR1H to 60 and TMR1L to 175.
' If you're not comfortable with high and low bytes, put 3035 into a word variable (say TempVar)
' Then, set TMR1L to TempVar, and TMR1H to TempVar_H - this makes the compiler split the number up
' Set up Timer1
InitTimer1 Osc, PS1_1/2
StartTimer 1
On Interrupt Timer1Overflow Call IncTime
TMR1L = 0 'Need to do this according to the PIC datasheet
TMR1H = 60
TMR1L = 175
do 'Main part of Program
cls
Print HOUR
Locate 0,2: Print ":"
Locate 0,3: Print Min
Locate 0,5: Print ":"
Locate 0,6: Print Sec
Wait 300 ms
Loop
SUB IncTime
'Increment the counter
Counter ++
If Counter = 10 Then '10 x 100ms 1sec
Sec ++
Counter = 0
End If
If Sec = 60 Then
Min ++
Sec = 0
End If
If Min = 60 Then
Hour ++
Min = 0
End If
If Hour = 12 Then
Hour = 0
End If
End Sub
Can anybody tell me what I am doing wrong?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi,
The 16F84 has only a 8 bits Timer0 and you can't use Tmr1H and Tmr1L!
So , you can try another PIC or if you don't , you must use Timer0 .
Then Timer0 overflow after 256 pulses or 256µS with a 4Mhz cristal .
So , to use TMR0 interrupt , you must preload Timer0 with 6 .
Then ,Timer0 will overflow every 250 µS . With a 1/16 prescaller , then it'll owerflow every 250 * 16 = 4000 µs or 4 ms
For one second (= 1000 ms) , Timer0 will overflow 1000 /4 = 250 times .
Each time Timer0 will overflow , you'll must write :
Timer0=6
Counter +
if Counter>=250 then
sec +
counter=0
end if
And so on
Regards
GC
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Oops , I 'm sorry , I 've read 16F84 , but it was 16F684 !!
So , you can use Timer1 .
But , to have One second interrupt ., you can do :
With 1/2 prescaller , Timer1 must be preloaded to 65536-50000= 15536 because 50000 ( 50000µs=50ms *2=100ms)
Then you can do the same thing as in previous exemple
Timer1 must overflow 10 times to have one second delay
and you have to preload TImer1H=60 , Timer1L=176 at each interrupt
So , it seams that your code is correct, but I think you must put ( TImer1H=60 , Timer1L=176) in sub IncTime , because these values must be preloaded after each interrupt , but if you leave them in main program , Timer1 will be reloaded even is there is no interrupt
Regards
GC
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I realize that I was very tired yesterday , indeed my last explanation wasn't good . lol
Because , if you lose about 14 mn , it's evident that TMR1 isn't preloaded each time interrupt occurs , and TMR1 starts again with it's complete value : 65536 . Because 15536/ 65535 =23.7 and 14mn/60mn=23,3 !!
So , your program is correct . I think you must only put ( Timer1H=60 , Timer1L=176) in sub IncTime and your problem will be solved.
Regards
GC
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I am trying to figure out how to use a overflow interrupt on TMR1 to semi accurately measure pulses per time period for a future project.
The posted program was made to signal a TMR1 interrupt after 100ms, and update Sec, Min, and Hours.
Additionally, the program was designed to start at a specific time so I could track the microcontroller time versus real time.
The program loses about 14min per hour.
Some of the code came from suggestions found on the GCBASIC forums.
I have racked my brains, and studied the forums trying to figure out why there is so much difference between the microcontrollers time and real time.
Can anybody tell me what I am doing wrong?
Hi,
The 16F84 has only a 8 bits Timer0 and you can't use Tmr1H and Tmr1L!
So , you can try another PIC or if you don't , you must use Timer0 .
Then Timer0 overflow after 256 pulses or 256µS with a 4Mhz cristal .
So , to use TMR0 interrupt , you must preload Timer0 with 6 .
Then ,Timer0 will overflow every 250 µS . With a 1/16 prescaller , then it'll owerflow every 250 * 16 = 4000 µs or 4 ms
For one second (= 1000 ms) , Timer0 will overflow 1000 /4 = 250 times .
Each time Timer0 will overflow , you'll must write :
Timer0=6
Counter +
if Counter>=250 then
sec +
counter=0
end if
And so on
Regards
GC
GC,
I am a little confused, according to the 16f684 spec sheet there is a 16 bit TMR1 with the capacity to set Tmr1H and Tmr1L.
http://ww1.microchip.com/downloads/en/devicedoc/41202c.pdf
Is GCBASIC not set up to utilize the TMR1 features in the 16F684?
I will try your suggestion in regards to using TMR0.
Thanks for your help
Oops , I 'm sorry , I 've read 16F84 , but it was 16F684 !!
So , you can use Timer1 .
But , to have One second interrupt ., you can do :
With 1/2 prescaller , Timer1 must be preloaded to 65536-50000= 15536 because 50000 ( 50000µs=50ms *2=100ms)
Then you can do the same thing as in previous exemple
Timer1 must overflow 10 times to have one second delay
and you have to preload TImer1H=60 , Timer1L=176 at each interrupt
So , it seams that your code is correct, but I think you must put ( TImer1H=60 , Timer1L=176) in sub IncTime , because these values must be preloaded after each interrupt , but if you leave them in main program , Timer1 will be reloaded even is there is no interrupt
Regards
GC
I realize that I was very tired yesterday , indeed my last explanation wasn't good . lol
Because , if you lose about 14 mn , it's evident that TMR1 isn't preloaded each time interrupt occurs , and TMR1 starts again with it's complete value : 65536 . Because 15536/ 65535 =23.7 and 14mn/60mn=23,3 !!
So , your program is correct . I think you must only put ( Timer1H=60 , Timer1L=176) in sub IncTime and your problem will be solved.
Regards
GC