PDA

View Full Version : Expanding Timer1 counting range



sycluap
- 13th January 2008, 11:53
I use Timer1 as a free running timer, using 4Mhz clock and 16F877A MCU. I do not know how to extend the timer range as it is from 0 to 65536 microsecond using 4Mhz clock.

Can anyone teach me to extend the timer range from 0 to 5 seconds?

Thanks in advance.

Acetronics2
- 13th January 2008, 12:39
Hi,

Hardw.solution : Just use the external TMR1 clock with a 32,768 Hz Xtal ... easily gives 1 count per ms !!!

SoftW.Solution : increment a variable for each overflow ( interrupts using or polling the overflow bit TMR1IF )

Also See Darrel's posts about instant interrupts ... The Hardw solution is described here !!!

Alain

sycluap
- 13th January 2008, 14:02
I am using 4MHZ, 16F877a, Timer1, setting TMR1H = $00 and TMR1L = $00. Tried to activate the timer as free running timer. Previously used to capture the timer time from 0 - 65536 microseconds (full range). Now that I am trying to extend the timer range and to respond to 1ms interval, I change the TMR1H = $FC and TMR1L = $18, with the codes below to capture the timer1 overflow.

Looping:
While PIR1.0=0
Wend
PIR1.0=0
TimerOverflow=TimerOverflow+1
LCDOUT $FE,$C0,DEC5 TimerOverFlow
If ButStop = 1 Then goto StopTimer
Goto Looping

But I am unable to get in 1ms interval. Can anyone guide me on this?

Acetronics2
- 13th January 2008, 14:20
You just need to preload Timer 1 with a value "not so far" from 65536 - 1000 ... no more free running timer usable !!!

it will overflow for 1000 counts = 1 ms ...

"not so far" mean you have to add the time to reload the timer and do what you want to the "64536" value ...

See Steve's ( Mr E !!! ) calculator here : http://www.mister-e.org/pages/utilitiespag.html


I also forgot you could use the "compare" function of the CCP module ... and poll the CCPIF bit !

Alain

sycluap
- 13th January 2008, 14:23
Yeah, I did make TMR1H = $FC, TMR1L=$18, which is obtained from 65536-1000. But the timer does not give me 1ms interval. I do not know what is wrong. Below is my program:

'MAIN PROGRAM
'------------
ResetTimer:
GoSub SetReg
LCDOUT $FE, 1
Timer1H = 0
Timer1L = 0
Result = 0
TimerOverflow = 0

Main:
LCDOUT $FE, $80, "Test Mode 1"
LCDOUT $FE, $C0, "Visual Response Test"
If ButStart = 1 Then goto StartTimer
Goto Main

StartTimer:
LCDOUT $Fe, 1
LCDOUT $FE, $80, "Calculating..."
T1CON.0=1

Looping:
While PIR1.0=0
Wend
PIR1.0=0
TimerOverflow=TimerOverflow+1
LCDOUT $FE,$C0,DEC5 TimerOverFlow
If ButStop = 1 Then goto StopTimer
Goto Looping

StopTimer:
T1CON.0 = 0
LCDOUT $Fe, 1
GoSub GetValue

DisplayResult:
Result = TimerOverflow
LCDOUT $FE,$C0, dec5 Result
If ButStart = 1 Then goto StartTimer
If ButReset = 1 Then goto ResetTimer
goto DisplayResult


'SUBROUTINES
'===========
'Reset Timer1 Register to Start from 1ms interval
'-------------------------------------------------------
SetReg:
TMR1H = $FC
TMR1L = $18
Return

Is there anything wrong with the program that cause the Timer unable to display 1ms interval timing on LCD?

Acetronics2
- 13th January 2008, 16:13
Your LCD display is unable to show time for EACH ms ... the LCDOUT command needs much more thant 1 ms - OR you should use LED Display ...

With that way of programming You might have enough time to refresh the display between two interrupts ...

Here, to be accurate ... you just can display exact time ONLY once timer stopped !!!


see How Darrel's "Elapsed timer Demo " works ... and you will be able to see "intermediate time"

http://www.picbasic.co.uk/forum/showthread.php?t=190&highlight=Elapsed+timer


Alain

PS: you can read the ms "on the fly" .... Wooowww !!! you got a fantastic pair of eyes !!!
LOL ...

sycluap
- 13th January 2008, 16:31
The additional line of code after the clear overflow flag is to test the timer whether the timing is accurate or not. Let's say of ms can't be seen, but at least for the seconds can be seen accurately right? Previously the coding was to display the final value directly on the LCD after Stop button is pressed. Conclusion is, I wonder the 1ms interval can be achieved or not.

From my codes structure, is achieving 1ms interval timing possible? Is there any modification need to be carried out besides displaying final timing value on LCD, in order to achieve 1ms interval timing?

skimask
- 13th January 2008, 19:14
Your LCD display is unable to show time for EACH ms ... the LCDOUT command needs much more thant 1 ms - OR you should use LED Display ...

Actually, most of the LCDs I've got, usually the 16x2, are able to handle a commandus of around 100 and a dataus of 50 (the best one I've got will do commandus = 50 and dataus = 27, well below that datasheet values).
So, assuming you don't have too much to display, theoretically, you could refresh one complete line on a 16x2 LCD inside of 1ms...assuming that is :)

(and I knew this thread was coming)

sycluap
- 14th January 2008, 02:06
Is that mean the culprit for unable to get 1ms interval timer is the LCD display? What is I just make it display the final value upon stop button is pressed? Can this solve the problem?

skimask
- 14th January 2008, 02:31
Is that mean the culprit for unable to get 1ms interval timer is the LCD display? What is I just make it display the final value upon stop button is pressed? Can this solve the problem?

Are you completely incapable of doing any 'out of the box' thinking? Kick your brain into gear! Just because the LCD takes longer than 1ms to display (which is not necessarily true, but at default settings is true), doesn't mean the PIC can't keep counting until you stop it from counting and then displaying the result when it is done counting.
What are you counting that supposedly requires microsecond accuracy anyways?

sycluap
- 14th January 2008, 02:39
Not that I can't think out of the box, but I've asked around and tried whatever is possible, to display counting in LCD, not to display in LCD, to display only the final value, etc, but i still can't manage to get the timer to display in 1ms timing interval. I know that the PIC can continue counting by itself, but, even I try to make it display only the final value, but it still can't display the accurate readings.

Sorry for asking questions that might consider too easy for some others, but I am totally new in this. I need the timer to measure the human response time.

MY CODE:

'MAIN PROGRAM
'------------
ResetTimer:
GoSub SetReg
LCDOUT $FE, 1
Timer1H = 0
Timer1L = 0
MicroThousandths = 0
Thousandths = 0
Hundredths =0
Seconds = 0

Main:
LCDOUT $FE, $80, "Test Mode 1"
'LCDOUT $FE, $C0, "Visual Response Test"
If ButStart = 1 Then goto StartTimer
Goto Main

StartTimer:
LCDOUT $Fe, 1
LCDOUT $FE, $80, "Calculating..."
T1CON.0=1

Looping:
While PIR1.0=0
Wend
PIR1.0=0
Thousandths=Thousandths+1
If Thousandths>9 Then
Thousandths=0
Hundredths=Hundredths+1

If Hundredths>99 Then
Hundredths=0
Seconds=Seconds+1
Endif
Endif

If ButStop = 1 Then goto StopTimer
Goto Looping

StopTimer:
T1CON.0 = 0
LCDOUT $Fe, 1
GoSub GetValue

DisplayResult:
LCDOUT $FE, $80, "Time Elapsed"
LCDOUT $FE,$C0, dec2 Seconds, ".", dec2 Hundredths, ":", dec Thousandths
If ButStart = 1 Then goto StartTimer
If ButReset = 1 Then goto ResetTimer
goto DisplayResult


'SUBROUTINES
'===========
'Get value from Timer1 Register
'------------------------------
GetValue:
Timer1H=TMR1H
Timer1L=TMR1L
Return

'Reset Timer1 Register to Start from 1ms interval
'-----------------------------------------
SetReg:
TMR1H = $FC
TMR1L = $18
Return

Now, what is wrong with my codes? Correct me please.

skimask
- 14th January 2008, 03:06
Not that I can't think out of the box......
Big hints for you back in post's #5 and #7.

skimask
- 14th January 2008, 03:38
I think you're way over-doing this in the first place.
So, what you want is a program to start counting when you hit one button, and stop counting when you hit a second button, and display the time interval between the 2 right?

some generic code (you fill in the crap with real code)


'Set up all variables, registers, timers, etc... No interrupts

'display start message

'wait for start button to be hit, if it's not hit, don't jump back to the lcdout display command

'takes time to display and might miss a button push in the meanwhile

'if the button is hit, reset tmr1 to zero and start the timer

'start a loop

'display the current count (which will take longer than 1ms, but the next bunch will take care of that, again, the problem with displaying stuff during a tight count is that you will miss the exact time that a button is pushed and the count could possibly be off by 1 or 2 ms)

'if the tmr1 value is above 1000, add 1 to the ms counter and subtract 1000 from tmr1 (3 from tmr1h and 232 from tmr1l, or subtract 4 from tmr1h and add 24 to a subcounter to cover the extra 24us. when that subcounter exceeds 1000, add another one to the ms counter

'check the stop button
'if the stop button is not pushed, jump back to the loop
'if the stop button is pushed, immediately save the tmr1 count, do the 'over 1000' math to keep the ms count and us count, and display the total

No, not real code, an outline as a guide.

Interrupts are nice, and DT interrupts and the Olympic timer are all you need, but apparently it's not enough to have almost 100% pre-written code made just for you.

This code is based on the fact that you keep timer1 BELOW a certain value and keep track of it as it counts UP. That way if you miss a count or two, you can always recheck it (i.e. tmr1 is 3000, you've missed 3ms, no biggie, just subtract 1000 from it 3 times and you're back on track). I built an OBD2 reader that's based off this to drive my virtual odometer, integrates time and speed. In the process of reading the OBD2 message, I miss a count here and there. No problem, just let the counter increase in the background and cover it up later. The intervals are short enough that I get a nice accurate reading (within 1/10 mile over a 263 mile drive 2 weeks ago) and long enough that the timer won't overflow in between readings.
Make any sense yet?

sycluap
- 14th January 2008, 04:27
Thanks for the guide. I have clearer idea now. Sorry for OVERDOING it. But at least Mr.Skimask and Mr.Acetronics is willing to help me out. Thanks.

dw_picbasic
- 3rd February 2014, 22:00
Hello sycluap,
In your code, where you have initiate time counting:

Looping:
While PIR1.0=0
Wend


It appears that you are allowing the timer1 to overflow and then checking to see if the button has been released. This leads me to assume that you don't care if the button is released during the time Timer1 takes to reach rollover.
If this is the case, then is the use of Timer1 really necessary?
If you don't need resolution under a uSec then you might consider using the PBP3 "pauseus" command to create the 1 uSec.
1) Start button is pressed
2) pauseus 1 (delay 1uSec)
3) count0 = count0 + 1
4) if count0 = 65535 then count1 = count1 + 1; count0 = 0
5) check button ( if still pressed loop again)

In this case, you can capture ( minimum 1 uSec - maximum 4294 seconds).
For the math, just use count1 value as a multiplier of 65535
So, then if count1 = 40 you have (65535*40) = 2.6214 seconds accumulated in count1
and then you just add count0 value to that to get the total.


for loop1 = 1 to count1
for loop2 = 1 to 5
micro_sec = micro_sec + 13107
while micro_sec > 999
milli_sec = milli_sec + 1
micro_sec = micro_sec -1000
wend
while milli_sec > 999
sec = sec + 1
milli_sec = milli_sec - 1000
wend
next
next
Lcdout $fe, 1, #sec,":",#milli_sec,":",#micro_sec