PDA

View Full Version : an easy way to add timer?



peterdeco1
- 29th July 2004, 11:12
Hello Melanie & Everyone. Up until now when I wanted to run a program for a specific time I would simply count a variable:
high portb.0
pause 1000
low portb.0
pause 1000
let X = X + 001
if X >= 10 then XXXXXX
This program will flash an LED 10 times and jump to a different loop. However, is there a way, an EASY way, to substitute the last 2 lines with a "backround timer" that will automatically jump to XXXXXX after say 5 minutes or whatever regardless of what the PIC is currently doing? Thank you. - Peter

Dwayne
- 29th July 2004, 20:36
Hello Peterdeco1,

PC1>>high portb.0
pause 1000
low portb.0
pause 1000
let X = X + 001
if X >= 10 then XXXXXX
This program will flash an LED 10 times and jump to a different loop. However, is there a way, an EASY way, to substitute the last 2 lines with a "backround timer" that will automatically jump to XXXXXX after say 5 minutes or whatever regardless of what the PIC is currently doing?<<

Ouch.. this is called multi-tasking, and PICS do not multi-task. I was trying to think of something like the PWM, which can put out a signal while other things are goin on in the chip.

I would like to see if anyone comes up with a idea...

Dwayne

CocaColaKid
- 29th July 2004, 20:59
This sounds like something the timer and interrupt could be used for. How to actually do it though is totally greek to me.

Melanie
- 4th August 2004, 13:19
Watch this space... I have a topical example of timer/interrupt usage that I'll post shortly... just as soon as I shoot a couple of awkward clients first...

Melanie
- 6th August 2004, 20:35
Finally...

"How to actually do it though is totally greek to me."

It's Athen's Olympics time... and we do need to go Greek...

see Olympic Timer in the Code examples section...

www.picbasic.co.uk/forum/showthread.php?s=&threadid=632

Re Multi-tasking.

Usually you need multiple or parallel processors to do multitasking. Most computers give the illusion of multitasking through a process of time-slicing - ie devoting a portion of the overall CPU time to a given job, then switching to another task. If done fast enough then you have your multi-tasking illusion (typical example is Microsoft Windows).

Actually PICs do genuinely multitask quite well. They're able to sample an ADC channel, perform multiple Timer functions, execute PWM trains, catch data in the USART and perform Analogue Comparisons all genuinely simultaneously whilst your program is doing something completely different. It's called using the features provided within your PIC and the secrets of exploiting these multitasking features are... in the Datasheet.

Melanie

peterdeco1
- 8th August 2004, 10:33
WOW Melanie! I downloaded your Olympic Timer. You're program is a work of art and is lightyears ahead of my question about a backround timer. I wish I knew a fraction of what you know about PBP (I think I said this before). Here is a simple program using a PIC16F818. It is transferring data from porta to portb.0. The problem is if I make it count time (let X = X + 001 : pause 1000 : if X = 60 then loopXXX : goto begin) I lose the data transfer during pause time, even if pause time is reduced to milliseconds. Is there an EASY way I can make it jump to loop XXX after 1 minute?

OSCCON = $60 'set int osc to 4mhz
ADCON1 = 7 ' set inputs to digital
TRISA = %11111111 'porta inputs
TRISB = %00000000 'portb outputs

begin:
let portb.0 = porta.0
goto begin
***AFTER 1 MINUTE JUMP TO LOOPXXX***
loopXXX:
let portb.0 = porta.1
goto loopXXX

Thanks everyone for your input (pun intended!) - Peter

Melanie
- 8th August 2004, 11:25
Well, just take the Olympic Timer as an example and strip it out and refit it to your requirements (after all that's why I created it)... First let's take that interrupt handler and rebuild it to toggle a Flag every minute instead of keeping track of actual Minutes, Hours and Overflow which are unnescessary for your needs....



'
' Timer Interrupt Handler
' =======================
TickCount:
Gosub SetTimer
Hundredths=Hundredths+1
If Hundredths>99 then
Hundredths=0
Seconds=Seconds+1
If Seconds>59 then
Seconds=0
MinuteFlag=MinuteFlag^1
endif
endif
Resume

The SetTimer subroutine can be simplified to junk the Calibration value like so...


'
' Subroutine Loads TMR1 values
' ============================
SetTimer:
T1CON.0=0
TMR1RunOn.Highbyte=TMR1H
TMR1RunOn.Lowbyte=TMR1L
TMR1RunOn=TMR1Preset+TMR1RunOn
TMR1H=TMR1RunOn.Highbyte
TMR1L=TMR1RunOn.Lowbyte
T1CON.0=1
PIR1.0=0
Return

Finally we lose our entire Main program body, Reset Code, Calibration Set-Up, and all the unnescessary subroutines, EEPROM settings etc etc leaving us just your desired application... and if you notice the main body is pretty much the exact code that you've written... so in effect you were already 99.9% of the way to your own solution...


'
' Software Defines
' ----------------
Hundredths var BYTE
MinuteFlag var BIT
Seconds var BYTE
TMR1RunOn var WORD

'
' Software Constants
' ------------------
TMR1Preset con $D910

'
' Start Program
' =============

'
' Initialise Processor
' --------------------
' Put your TRIS and Register initialisation statements here

MinuteFlag=0
Hundredths=0
Seconds=0
'
' Initialise TMR1 Interrupts
' --------------------------
Gosub SetTimer
On Interrupt goto TickCount
PIE1.0=1
INTCON.6=1
INTCON.7=1
'
' Main Program Loop
' =================
Enable

Begin:
let portb.0 = porta.0
If MinuteFlag=1 then goto LoopXXX
goto begin
loopXXX:
let portb.0 = porta.1
goto loopXXX

Disable

Just remember that no command in your Main Program Loop can exceed 10mS execution time otherwise you will lose your timing integrity (program won't die, but you won't get a 1 Minute timing interval for the Flag to toggle, it'll be 1 Minute plus the number of 10mS interrupt ticks you've missed).

If accuracy in your minutes is important to you, adjust the TMR1Preset constant. Increase the value to speed up by 100uS per minute, Decrease the value to slow down by 100uS per minute (at 4MHz clock).

See... easy peasy... don't be afraid to take any of my code and trash it into anything that you need... it's posted for you to learn from.

Melanie

Melanie
- 8th August 2004, 11:52
Just a final note... I estimate the Interrupt Handler to take less than 100uS to execute once every 10mS (with a 4MHz PIC). If your application still loses data, then there are only two options...

1. Go to a faster PIC

Naturally all the Interrupt timings will be shot and will have to be recalculated for a new value for TMR1Preset - but that's no big deal... should take less than a minute out of your life to do that...

2. Rehash the SetTimer and TickCount Subroutines

Rather than have one interrupt every 10mS, engaging TMR1's prescaler we have a potential interrupt range of 1uS through to 524.288mS... so we can redesign the routines to interrupt every 500mS (only 120 times in a minute) rather than every 10mS (6000 times in a Minute).

Melanie