- Loops:
Loops are the cheesiest way to handle timing on the pic. They
are dependent on clock speed, so they make for hard-to-maintain
code; if you go from a 10 MHz clock to an 8 MHz clock, you have to
change all the while values appropriately. But if you did use loops
for timing, it would look like:
// generate a 4 us pause (if you have a 10 MHz crystal)
int i;
for (i = 0; i < 100; i++)
;
Be warned, too, that an int is only 8 bits in CCS, so this
loop will go forever:
// you might think this pauses for 12 us, but really it loops forever!
int i;
for (i = 0; i < 300; i++)
;
-
delay_us(), delay_ms()
The "right" way to handle timing for little pauses is with delay_xx.
This makes use of the preprocessor directive DELAY, so porting to a different
crystal is cake. Examples:
// pause for 20 milliseconds
delay_ms(20);
// pause for 200 microseconds
delay_us(200);
// if you are using constants, you can use a 16 bit argument
// (variable arguments are limited to 8 bits... just another
// charming "feature" of PICC)
delay_ms(1000); // 1 second delay
i = 1000;
delay_ms(i); // 1000 % 256 = 232 millisecond delay
- Timer0 and Interrupts
For more complicated programs (like ones that time something, while
doing something, the name of the game is interrupts.
On the 16F84, these interrupts are conveniently generated by timer zero.
To make things confusing timer0 is also called counter0 and RTCC. In PICC,
you can get access to it by including the code:
struct {
short int RBIF;
short int INTF;
short int T0IF;
short int RBIE;
short int INTE;
short int T0IE;
short int PEIE;
short int GIE;
} INTCON;
#byte INTCON= 0x0B
This makes a structure called INTCON. Whenever timer0 rolls over,
INTCON.T0IF is set to 1. So if you set it to zero, and then look at
it and it's one, you know something happened.
The other important functions for making this work are
set_rtcc(int val) which sets the timer, and
setup_counters(RTCC_INTERNAL, RTCC_DIV_xxx) which
sets the prescaler.
See beeper.c for an example.
The tricky part is the line
TMR0 = 256 + 2 - NTICS;
The magic +2 is in there because after you change the counter value it
takes two ticks before it starts running again.
- Watchdog Timer
The Watchdog Timer is key to low power programming. It is also designed for
mission critical programs. If it is not reset in about 18 milliseconds,
it will power cycle the PIC, unless the PIC is sleeping, in which case instead
of cycling the power, it makes the chip wake up. The key functions to making
this work are:
restart_wdt();
sleep();
and don't forget to have a #fuses wdt at the beginning.
A perfect application of the precise timing the pic is the analog hack,