Posts Tagged ‘microchip’

After writing about the PIC hardware PWM module it occurred to me that a little more information about the onboard timers would be in order.  Just about every PIC has a timer and many have several.  The PIC16F777 that we I used in the hardare PWM article has three of them called TMR0, TMR1, TM2

The three timers are similar to each other in many ways but are different in some respects.  Below is a list of each of the timer features from the datasheet.

TRM0

  • 8-bit timer/counter
  • Readable and writable
  • 8-bit software programmable prescaler
  • Internal or external clock select
  • Interrupt on overflow from FFh to 00h
  • Edge select for external clock

TMR1

  • 16-bit timer/counter which consists of two 8-bit registers
  • Readable and writable (TMR1H:TMR1L)
  • 4-bit software programmable prescaler
  • Internal or external clock select

 

TMR2

  • 8-bit timer/counter
  • Readable and writable
  • 4-bit software programmable prescalerInternal or external clock select
  • Prescale options include 1:1, 1:4, 1:16
  • Postcale options include 1:1, 1:2, 1:3, 1:16
  • Internal clock only
  • Output (before prescaler) is fed to the SSP module for an optional shift clock.
  • Can be set to automatically compare it to a value you determine.

Each of the timers can be configured separately and can be used for different purposes within your application.  One of the nice things about these is that they run on their own in the background while your code is off doing something else.  They “tap you on the shoulder” in the form of an interrupt to remind you to go and do something.  You can also read them or reset them at any time.  These timers are essentially binary counters that start at a value you determine and keep running until you shut them off.  If you’re not familiar with a binary counter it looks much like this…

clock pulse 1  00000000
clock pulse 2  00000001
clock pulse 3  00000010
clock pulse 4  00000011
clock pulse 5  00000100
clock pulse 6  00000101

and so on

The counter keeps increasing after every clock pulse until it “overflows”.  Overflows means that when the counter is all 1′s and another 1 is added, there is no place for the carry bit to go.  This generates and interrupt and the timer is reset to all 0′s again.

Now lets write a little routine that uses one of our timers to blink an LED at 1 second intervals.  We’re going to use the CCS compiler for this example and once again use the PIC16F777.  We’ll use TMR1 for this task and take I’ll take a moment to point out a couple of things before we get to coding.

- TMR1 counts from 0 to 65535

- On the next count it resets back to zero and sets a bit in the TMR1IF (Timer 1 Interupt Flag) on the PIR1 register.

- If we run the internal clock at 20Mhz we know that the program counter and the pulses that drive the clock are equal to 1/4 of the internal clock speed of each clock count.  That means that the TMR1 clock runs a 20Mhz/4=5Mhz.

- A little more math and we find that each clock pulse take 1/5Mhz seconds to comple.  That’s .2us for each count of TMR1

- Another piece we need is how long until the timer overflows.  From what we know so far it’s .2us x 65536 = 0.0131

- Since the last piece resulted in such a short time until overflow, we could probably use a prescaler to slow it down a bit. Using the 1:8 prescale which divides our clock we get 5Mz/8 = 625KMz which is 1.6us per count of TMR1.  With that we have 1.6us x 65536 = 0.104856s wich is how long it takes to overflow the clock.

Now, with that information we know that if it takes 0.104856s to overflow the clock.  If we let the clock overflow 10 times we will have taken up 1.04856s.  Well that’s pretty close to what we wanted but lets say we had to get that close to 1s.  What could we do?  Well, remember that TMR one is writable.  That means we can preload a value into TMR to get us a little close.  I’m not going to show all the math on this part but if you solve this equation …

clock cycles = (0.1s)/((20Mhz)(1/4)(1/8)) = 62500

You’ll see that if we could overflow the clock after 62500 cycles rather than 65536 we would have consumed exactly .10 seconds.  So the value we need to preload in is (65335-62500) = 3035.

The code that puts it all together… 

#include <16F777.h>
#fuses INTRC,NOWDT,NOPROTECT
#use delay(clock=2000000)
unsigned int counter = 0;
setup_port_b (ALL_DIGITAL);
#int_timer1

void timer1_isr() {
disable_interrupts(INT_TIMER1); //Turn off interrupts
set_timer1(3035);                                 //Load preset
counter = counter +1;                           //Increment Counter
clear_interrupt(INT_TIMER1);
enable_interrupts(INT_TIMER1);  //Enable the TMR1 Interrupt
}

void main(void){
 SET_TRIS_B( 0×00 );                       //Set Port B to all Outputs
 setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);  //Timer with internal clock and 1:8 prescaler
 enable_interrupts(GLOBAL);
 enable_interrupts(INT_TIMER1);

test: 
if (counter == 10){
 counter = 0;                                              //Reset the counter
 OUTPUT_TOGGLE(PIN_B1);
}

goto test; 

We start out telling the CCS compiler which device we’re using and set some of the config bits.  We also set port B to all outputs, initalize the variable COUNTER, and declare out timer1 interrupt.  The main part of the program sets up the timer with the internal clock and the prescaler we talked about.  The interrupt is enabled and then we begin the testing of the variable COUNTER.  Remember that the TMR1 clock is running all the time now that we’ve set it up.  The test loop checks to see if we’ve overflowed it 10 times.  We know how many times it overflowed because we’ve set up an interrupt routine which increments COUNTER each time if overflows.  When COUNTER reaches ten, we toggle B1.  So with an LED and appropriately sized resister on B1 we would see the LED light up for 1s and then turn off for 1s.

In CCS there are simpler ways of accomplishing this task of lighting the LED for 1s on and 1s off.  We could use the delay function build into CCS to simplify our code.  We only did it this way to demonstrate how the TMR1 operates. Hopefully I’ve shed a little light into the world of PIC timers using CCS and you can feel comfortable using them in your designs.

The majority of devices in the PIC12 and PIC16 Midrange devices use this instruction set. It’s very similar to the 12 Bit PIC Instruction Set but the increased opcode width allows 128 registers and 2048 words of code to be directly addressed.

Opcode (binary) Mnemonic Description
00 0000 0000 0000 NOP No operation
00 0000 0000 1000 RETURN Return from subroutine, W unchanged
00 0000 0000 1001 RETFIE Return from interrupt
00 0000 0110 0010 OPTION Write W to OPTION register
00 0000 0110 0011 SLEEP Go into standby mode
00 0000 0110 0100 CLRWDT Reset watchdog timer
00 0000 0110 01ff TRIS f Write W to tristate register f
 
00 0000 1 fffffff MOVWF f Move W to f
00 0001 0 xxxxxxx CLRW Clear W to 0 (W = 0)
00 0001 1 fffffff CLRF f Clear f to 0 (f = 0)
00 0010 d fffffff SUBWF f,d Subtract W from f (d = f − W)
00 0011 d fffffff DECF f,d Decrement f (d = f − 1)
00 0100 d fffffff IORWF f,d Inclusive OR W with F (d = f OR W)
00 0101 d fffffff ANDWF f,d AND W with F (d = f AND W)
00 0110 d fffffff XORWF f,d Exclusive OR W with F (d = f XOR W)
00 0111 d fffffff ADDWF f,d Add W with F (d = f + W)
00 1000 d fffffff MOVF f,d Move F (d = f)
00 1001 d fffffff COMF f,d Complement f (d = NOT f)
00 1010 d fffffff INCF f,d Increment f (d = f + 1)
00 1011 d fffffff DECFSZ f,d Decrement f (d = f − 1) and skip if zero
00 1100 d fffffff RRF f,d Rotate right F (rotate right through carry)
00 1101 d fffffff RLF f,d Rotate left F (rotate left through carry)
00 1110 d fffffff SWAPF f,d Swap 4-bit halves of f (d = f<<4 | f>>4)
00 1111 d fffffff INCFSZ f,d Increment f (d = f + 1) and skip if zero
 
01 00 bbb fffffff BCF f,b Bit clear f (Clear bit b of f)
01 01 bbb fffffff BSF f,b Bit set f (Set bit b of f)
01 10 bbb fffffff BTFSC f,b Bit test f, skip if clear (Test bit b of f)
01 11 bbb fffffff BTFSS f,b Bit test f, skip if set (Test bit b of f)
 
10 0 kkkkkkkkkkk CALL k Save return address, load PC with k
10 1 kkkkkkkkkkk GOTO k Jump to address k (11 bits)
 
11 00xx kkkkkkkk MOVLW k Move literal to W (W = k)
11 01xx kkkkkkkk RETLW k Set W to k and return
11 1000 kkkkkkkk IORLW k Inclusive or literal with W (W = k OR W)
11 1001 kkkkkkkk ANDLW k AND literal with W (W = k AND W)
11 1010 kkkkkkkk XORLW k Exclusive or literal with W (W = k XOR W)
11 110x kkkkkkkk SUBLW k Subtract W from literal (W = k − W)
11 111x kkkkkkkk ADDLW k Add literal to W (W = k + W)

Here’s the instruction set for Microchip’s Baseline devices.  These include the PIC10 series as well as some of the PIC12 and PIC16.

Opcode (binary) Mnemonic Description
0000 0000 0000 NOP No operation
0000 0000 0010 OPTION Load OPTION register with contents of W
0000 0000 0011 SLEEP Go into standby mode
0000 0000 0100 CLRWDT Reset watchdog timer
0000 0000 01ff TRIS f Move W to port control register (f=1..3)
 
0000 001 fffff MOVWF f Move W to f
0000 010 xxxxx CLRW Clear W to 0 (a.k.a CLR x,W)
0000 011 fffff CLRF f Clear f to 0 (a.k.a. CLR f,F)
0000 10d fffff SUBWF f,d Subtract W from f (d = f − W)
0000 11d fffff DECF f,d Decrement f (d = f − 1)
0001 00d fffff IORWF f,d Inclusive OR W with F (d = f OR W)
0001 01d fffff ANDWF f,d AND W with F (d = f AND W)
0001 10d fffff XORWF f,d Exclusive OR W with F (d = f XOR W)
0001 11d fffff ADDWF f,d Add W with F (d = f + W)
0010 00d fffff MOVF f,d Move F (d = f)
0010 01d fffff COMF f,d Complement f (d = NOT f)
0010 10d fffff INCF f,d Increment f (d = f + 1)
0010 11d fffff DECFSZ f,d Decrement f (d = f − 1) and skip if zero
0011 00d fffff RRF f,d Rotate right F (rotate right through carry)
0011 01d fffff RLF f,d Rotate left F (rotate left through carry)
0011 10d fffff SWAPF f,d Swap 4-bit halves of f (d = f<<4 | f>>4)
0011 11d fffff INCFSZ f,d Increment f (d = f + 1) and skip if zero
 
0100 bbb fffff BCF f,b Bit clear f (Clear bit b of f)
0101 bbb fffff BSF f,b Bit set f (Set bit b of f)
0110 bbb fffff BTFSC f,b Bit test f, skip if clear (Test bit b of f)
0111 bbb fffff BTFSS f,b Bit test f, skip if set (Test bit b of f)
 
1000 kkkkkkkk RETLW k Set W to k and return
1001 kkkkkkkk CALL k Save return address, load PC with k
101 kkkkkkkkk GOTO k Jump to address k (9 bits!)
1100 kkkkkkkk MOVLW k Move literal to W (W = k)
1101 kkkkkkkk IORLW k Inclusive or literal with W (W = k OR W)
1110 kkkkkkkk ANDLW k AND literal with W (W = k AND W)
1111 kkkkkkkk XORLW k Exclusive or literal with W (W = k XOR W)