In the previous post I wrote about using the PIC10F322 Interrupt.  In this post is the the complete code that will use timer0, to replace the __delay_ms() macro. 

Why would we want to replace the __delay_ms() macro?  

The macro has some limitations, great if you want to bang something out.  However, the macro uses a series of NOP instructions to work. Which can take up a lot of code space, depending on what you are doing. 

By using timer0 and interrupts we get around this problem and create a timer than can accept a variable – for example – if we wanted to read an analog value and update the timer – based on the analog input.  The macro will not work, but this will… 

And incase you are wondering… yes the next post will be on using the analog input functions of the PIC10F322.. 


And now for the code… 


#include <xc.h>
#include <stdint.h>

#pragma config FOSC = INTOSC  // Oscillator Selection 
#pragma config BOREN = ON    // Brown-out Reset
#pragma config WDTE = OFF    // Watchdog Timer
#pragma config PWRTE = ON    // Power-up Timer
#pragma config MCLRE = OFF   // MCLR Pin Function Select bit->MCLR pin function is digital input, MCLR internally tied to VDD
#pragma config CP = OFF      // Code Protection 
#pragma config LVP = OFF     // Low-Voltage Programming 
#pragma config LPBOR = ON    // Brown-out Reset Selection bits
#pragma config BORV = LO    // Brown-out Reset Voltage Selection
#pragma config WRT = OFF    // Flash Memory Self-Write Protection

//Used to calculate the delay time - Change depending on processor Speed
#define _XTAL_FREQ 8000000  //8 MHz (default after Reset)

//Function prototypes
void setup (void);
unsigned long millis(void);
void delay(uint32_t ms);

volatile unsigned long timer0_millis = 0;

//interrupt handler 
void __interrupt () isr_routine (void) {

//TMR0 = 8;
timer0_millis +=1;  //increase the counter by 1  
INTCONbits.TMR0IF = 0; //clear tmr0 irq flag


void main(void)
       LATAbits.LATA0 = 1; //turn on port A.0
       LATAbits.LATA0 = 0; //turn off port A.0

void setup (void)
    //Set Port A.0 as output
    TRISAbits.TRISA0 = 0;
    //Clear any analog and port settings
    ANSELA = 0x00;
    LATA = 0x00;
    /*Set TMR0 to use FOSC/4 At 8Mhz the timer with increment at 2Mhz
    That is 500us       
    TMR0 will overflow ever 128us. Which is faster than we want - I am aiming for 1ms.
    So lets use a prescaler to get it close
    Assign prescaler to TMR0 With prescaler of 8 we get  500ns * 256 * 8 = 1.024ms
    Then set the prescaler */
    OPTION_REGbits.PSA = 0;
    OPTION_REGbits.PS = 0b010; //prescaler of 8
    //To Start the timer we need to set the clock source to fosc/4 but first clear the timer just to make sure
    TMR0 = 0;    
    OPTION_REGbits.T0CS = 0;
    //Assign interrupt to timer 
    INTCONbits.TMR0IF = 0; //clear tmr0 irq flag
    INTCONbits.TMR0IE = 1; //enable tmr0 irq enable
    INTCONbits.GIE = 1; //enable global interrupts  

//Reads the MS variable
unsigned long millis(void)
	unsigned long m;
	// disable interrupts while we read timer0_millis or we might get an
	// inconsistent value (e.g. in the middle of a write to timer0_millis)
	INTCONbits.GIE = 0;
	m = timer0_millis;
    INTCONbits.GIE = 1;
	return m;

//Delay based on the number of MS
void delay(uint32_t ms)
    //Get the timer value as we go into the delay
	uint32_t start = millis();

    //We wait here until while current timer value, minus the start value, is less than the value we want
	while (millis() - start < ms){}



Something You Might Be Intrested In


10F32X Rapid Prototype Board

Make The PIC10F322 and other PIC10F Processors Breadboard Friendly for Quick and Easy Prototyping.

{Click to learn more}

PIC10F322 XC8 Interrupt Based Delay Timer