Using a Watch Crystal and TMR0 with PIC16F84 Many applications don't really need high speed and there are advantages to a lower frequency crystal oscillator on the 16F84. Watch crystals are tiny cylinders about the size of a pencil lead and about 5/16th inch long. You can find one in an old broked LCD wristwatch or you can buy them new for under $1, (phanderson.com has them for $0.50). The frequency is 32.768 kHz. They are usually more accurate than the normal 4 mHz crystals you would use. One real advantage is in timers that require accurate time intervals. Timer zero, (TMR0), is a register which updates constantly on the '84 at the crystal frequency divided by four. If you use a 4 mHz crystal this is every microsecond. The watch crystal is 122 times slower. Instruction periods that take 1 usec with the 4 mHz crystal are 122 usec with the watch crystal. TMR0 increments up to 255, then rolls over to zero and keeps on going. As it rolls over, it sets a bit in the INTCON register called T0IF, (Timer zero interrupt flag). It is up to you to clear this flag if you want to catch a change the next time TMR0 rolls over. This is course part of the interrupt scheme on the '84, but you don't have to use interrupts to use T0IF. Interrupts are great if you are trying to do many things at once. If you aren't, you can just sit in a loop and wait for T0IF to change. It will be 256 crystal freq/4 periods since the last time; 256 usec for 4 mHz, 256 * 122 = 31,232 usec for the watch crystal. Either way you can do a couple of hundred instructions worth of stuff before you even start looking for a T0IF change. Now, here is the clever part. Multiply 31,232 by 32 and what do you get? 999,432 ... actually 1,000,000 usec, (I left off some decimal places on the 122). You get exactly 1 second! The '84 also has prescalar that can be assigned to either the watch dog timer, (WDT), or TMR0. When assigned to TMR0 it extends the normal period by 1:2, 1:4, 1:8,....... 1:256. This is done by setting the three lowest bits in the OPTION register. The pattern for a ratio of 1:32 is B'100'. Bit 3 of OPTION determines who gets to have the prescalar, (1 for WDT, 0 for TMR0). Bit 7 of OPTION controls port B pull-ups. Normally you want it to be 0 to enable pull-ups. All the preceding can be set up with two instructions: movlw B'00000100' ; set the bit pattern option ; load OPTION register With a 32.768 kHz crystal then, every second T0IF in INTCON will be set, (if not already set). A N second delay subroutine would look like this: nsec ; enter with # seconds in W clrf TMR0 ; restart the timer at 0 clrflg bcf INTCON, T0IF ; make sure T0IF is clear btfss INTCON, T0IF ; skip if T0IF set ... goto $ -1 ; else wait until it is addlw H'FF' ; subtract 1 from W btfss STATUS, Z ; is W zero yet? Z=1 means yes goto clrflg ; clear T0IF and wait again ; ( note TMR0 just rolls over and keeps going ) return O.K., so its not super exact. There are a couple of instruction cycles getting in and out of the subroutine and a few added to the last time through. But, these are added to 256 * N * 32 cycles. Not far off. Also, the crystal isn't exact and the frequency actually depends slightly on the capacitors attached. I use 33pf caps, but that just happed to be what I had. I think anything 10-50pf or so will work. I use a solderless breadboard and haven't had problems. Another advantage of the lower frequency is that the PIC draws less current. This is especially important if you are running off batteries. I use three AA cells and the PIC itself draws 80 microamps or less. This is a normal 4 mHz PIC. It draws even less with 2 cells and still works, ( yes, I know it is out of spec). I guess if you really want low draw you should get the 200 kHz version which is listed at 15 microamps at 32 kHz. Here is a short program to blink a LED: ; PIC16F84 with 32.768 kHz crystal and two 33pf caps. ; Pin 18 (RA1) has a LED attached through 1K resistor cathode to gnd ; Blinks LED on and off at 3 second intervals LIST P=16F84 ; tells which processor is used INCLUDE "p16f84.inc" ; defines registers and bits, look it over! __CONFIG _PWRTE_ON & _LP_OSC & _WDT_OFF ; note the _LP_OSC statement org 0 ; start a first location movlw 0 ; all outputs tris PORTA ; fast and easy way tris PORTB movlw B'10000100' ; prescalar to TMR0 and set 1:32, no pull-ups option ; load OPTION register loop bsf PORTA, 1 ; high on pin 18 movlw 3 ; 3 second delay call nsec bcf PORTA, 1 ; low on pin 18 movlw 3 ; 3 second delay call nsec goto loop ; do it forever ; (insert code for nsec from above at this location ) end