Subscribe to EDN
RSS
Reprints/License
Print
Email

Use eight timers with PIC16Fxxx microcontrollers

Timers debounce switches and let you decide when lapses have expired.

Luis G Uribe C, Caracas, Venezuela; Edited by Martin Rowe and Fran Granville -- EDN, February 18, 2010

PDF

The need for timing in embedded programming often exceeds the small number of available hardware timers in microcontrollers. For example, the Microchip PIC16F84A has one timer, but you can create as many as eight timers with the Timers8.inc assembly code in Listing 2.

Use eight timers with PIC16Fxxx microcontrollers listing 1Often, you need a timer while waiting for some expected lapse to expire, which blocks your program until that time has elapsed. To accomplish that task, you can use a simple routine, such as Wait_on 2, .30, meaning that Timer 2 counts 300 msec. The time value is .30 ticks of 10 msec each. In this way, you can debounce input data (Listing 1).


Using Microchip's MPLab assembler, you can't guess whether a parameter is a constant value or a variable, so you need two macros, one for each kind of circumstance. In the following explanation, use K if time is a constant and use V for variables, such as Wait_onK or Wait_onV. The same library for the TBM (timebase module) on the MCHC9S08GP32 microcontroller from Freescale Semiconductor uses only one macro, Wait_on, under the CodeWarrior assembler. The function deals with both constants and variables.

The “tmr” always stands for a constant from zero to seven. It designates the number of the timer you apply to a situation. You must always multiply time by 10, so .1 is 10 msec. You can therefore use it with times from 10 to 2560 msec. Precision is plus or minus one tick. If you need to trigger an event with a 20-msec timer, you may end with 10 msec. So use 30 msec to be safe. At the high end of the scale, you will have 2560±1 msec, which is acceptable.

Read More
Design Ideas

Timers8.inc programs the TMR0 on the PIC16F84A. You can extend
beyond eight timers or use 16-bit variables, but remember that the PIC16F84A has only 68 bytes of RAM.

On some occasions, you need to start a timer but don't need to block your program to time-out; in this case, use the Setimer 7, .20 macro. You start Timer 7 to last 200 msec; doing so does not block your program. Whenever you need to know the status of your timers, test them using the TimeOut macro, TimeOut 2, Two_done, meaning that, if Timer 2 has expired, you will go to the “Two_done” label. Any of your main code labels will fit. Otherwise, your program will continue executing the next instruction in sequence.

Setimer comes in two versions. SetimerK 2, .20 sets Timer 2 to count 200 msec, using Constant time .20, and SetimerV 5, var sets Timer 5 to count, for example, 300 msec, using variable time var, which you should have previously loaded with .30.

You may need to employ timers in ISRs (interrupt-service routines)—for example, to debounce the interrupt pin. This situation is awkward because the routine to serve the external INT pin runs with general interrupts disabled, as usually happens in the PIC16F84A, but timer routines require you to enable interrupts. This microcontroller architecture makes it difficult to enable interrupts in ISRs. You may, however, use either ISRWait_onK or ISRWait_onV to accomplish your purpose, as in ISRWait_onK 7, 3.

This approach works in a similar way to its twin, the Wait_on macro, except that you can use the approach in any ISR—a nice added value for such an inexpensive microcontroller. Use it with care, however. Interrupt latency increases because you block the program in an ISR for several milliseconds with global interrupt disabled. If you choose to debounce your interrupt signal using programmed delays, you will probably encounter the same problem. If you use a specific timer number in the main program, don't use it in the ISR.

To use the Timers8.inc library, you must include the library file and define some variables outside the timer's code. To find the exact place to include the library and define variables, refer to the sample code. Look for &&& TMR0 &&&, which overemphasizes portions of the code. In particular, inspect the lines “CBLOCK” and “INCLUDE ”.

Follow this plan in your program: Use the macro Init8Timers to activate the hardware and set up the eight software timers. This macro defines eight variables, from Timer 0 to Timer 7, each using one unsigned byte. Each timer ticks once every 10 msec, covering a range of 10 to 2560 msec. You need not worry about these variables, though, because the macros will handle them. A 1-byte variable, TimerFlags, has bits that represent the ready state of timers zero through seven. You need not deal with this internal variable.

To initialize a timer from zero to seven, use the Setimer macro, as in SetimerK 2, .20 (set Timer 2 to count 200 msec using a constant time of .20) or SetimerV 5, var (set Timer 5 to count 300 msec using a variable time of .30, which you previously stored in var). Setimer macros are not self-blocking; they initialize the software timers and continue. This feature comes in handy when you plan to loop, asking for several events to time out and do not need one of them to block you.

To test whether one timer has expired, use the TimeOut macro after Setimer: TimeOut 2, Two_on. If Timer 2 has expired, go to Two_on; otherwise, execute the next instruction in the sequence. Wait_on combines these macros in one: Wait_onK 2, .30. Set Timer 2 to count 300 msec using a constant time of .30 and block until time-out. Alternatively, using Wait_onK 5, var, set Timer 5 to count 300 msec using a value of .30, which you previously stored in var. Wait_on macros are self-blocking; they initialize the software timers and wait until time elapses. You can use ISRWait_on in ISRs: ISRWait_onK 6, .35. Set Timer 6 to count 350 msec using a constant time of .35 and then block.


Alternatively, you can use ISRWait_onV 5, var. Set Timer 5 to count 2000 msec using a value of .200, which you previously stored in var. ISRWait_on macros are self-blocking. You can use them in ISRs to initialize the software timers and wait until time elapses. You must include an interrupt handler; see the IntHandler in Listing 2. The library also includes TMR0ISR, Timer 0's ISR, and the UpdTmr (update-timer) internal macro.

Each timer has a status bit, which helps when your variables have 16 bits, 24 bits, or more. When the driver detects that one multibyte timer variable reaches zero, it signals this situation by setting the timer's status bit. That action spares you several instructions when you need to later decide whether the timer is zero. You can also use these bits as semaphores. You may start a timer with Setimer, and the hardware may interrupt you in the middle of the start-up to update your data structures, causing lots of problems. The software in this code, however, avoids touching or updating variables if the status bit is 1. Setimer begins raising the status bit and then loads the variables. If Timer 0 interrupts, it does not interfere with your data because it skips the updating process if the status bit is on. When Setimer is done, it clears the status bit, and Timer 0's ISR will begin to update whenever a tick arrives.

This code doesn't stop a timer before a time-out because the need never arises. If Setimer uses zero as a value for the time, it lasts for 256 10-msec ticks. If you need a 1-msec tick, you can load Timer 0 with –0.125 instead of –0.39 and use a prescaler of 8 (b'00000010' in OPTION_REG) instead of 256 (b 00000111), which are the values this code uses. The exact time is 125×8=1000 µsec (1 msec). This approach provides a range of 1 to 256 msec.

RSS
Reprints/License
Print
Email
Canon Resource Center

Featured Company


Most Recent Resources

Advertisement
Related Content

No related content found.

  • 0 rated items found.
Advertisement

KNOWLEDGE CENTER

Datasheets.com Parts Search

185 million searchable parts
(please enter a part number or hit search to begin)
Featured Job On
Scroll for More Jobs
Advertisement
About EDN   |   Site Map   |   Contact Us   |   Subscription   |   RSS
© 2012 UBM Electronics. All rights reserved.
Use of this Web site is subject to its Terms of Use | Privacy Policy

Please visit these other UBM Canon sites

UBM Canon | Design News | Test & Measurement World | Packaging Digest | EDN | Qmed | Pharmalive | Appliance Magazine | Plastics Today | Powder Bulk Solids | Canon Trade Shows