Monday, September 17, 2012

Millisecond ticker

The last post was about making a background millisecond ticker and I can confirm that it works well. A quick test with a 500ms test that keeps alternating an LED give a 1Hz flash rate that seems to keep time with the tick of our clock, though I haven't tested it for very long. The millisecond timer will run for almost 50 days before it rolls over (32bit, unsigned integer) - if I wanted something to run longer I'd have to think of the best way to reset it to zero seamlessly (ideas are welcome).

I think I'll throw in another interrupt too to see how multiple interrupts get handled and too try to find any pit falls.

A picture of breadboard is here

and the existing code is below:

/****************************************
 * Description: dabbling with timers
 *
 * File: bresenham.c
 * Author: Chris Hill
 * Created: September 2012
 *
 * Using Bresenham's Algorithm to create a
 * millisecond ticker
 *
 ****************************************/

#include
#include

#pragma config BOREN = OFF, CPD = OFF, DEBUG = OFF, WRT = OFF, FOSC = XT, WDTE = OFF, CP = OFF, LVP = OFF, PWRTE = ON

#define _XTAL_FREQ 4000000

/***** GLOBAL VARIABLES *****/

#define manual_LED sPORTB.RB1
#define regular_LED sPORTB.RB2
#define manual_btn PORTBbits.RB3

volatile uint32_t millis;   // millisecond counter, volatile because intrtn touches it

union {
    uint8_t port;
    struct {
        unsigned RB0 : 1;
        unsigned RB1 : 1;
        unsigned RB2 : 1;
        unsigned RB3 : 1;
        unsigned RB4 : 1;
        unsigned RB5 : 1;
        unsigned RB6 : 1;
        unsigned RB7 : 1;
        };
    } sPORTB;

void main() {
    uint32_t nxtchange;
    // initialisation

    millis=0;       // set the ticker to zero.
    nxtchange=500;  // set the next change point in milliseconds

    //configure port & shadow
    TRISB = 0b11111001;
    PORTB=0;
    sPORTB.port=0;

    OPTION_REGbits.T0CS=0;      // timer not counter
    OPTION_REGbits.PSA=0;       // use prescaler
    OPTION_REGbits.PS2=0;
    OPTION_REGbits.PS1=0;
    OPTION_REGbits.PS0=0;       // prescaler = 1:2

    INTCONbits.T0IE=1;          // timer0 interrupts on
    ei();                       // global interrupts are go
    for (;;) {
        if (millis>nxtchange) {
            regular_LED=~regular_LED;   // change the LED setting
            nxtchange+=500;     // ready for the next changeover
        }
        if (manual_btn) {       // test switch to check chip is working
            manual_LED=0;
        } else {
            manual_LED=1;
        }
        PORTB=sPORTB.port;  // write out the port
    }
}

// ******* interrupt routine ********
interrupt void intrtn() {
    /*
     * interrupts all come here.
     * First decide what caused the interrupt,
     * then respond to it
     */

    // here timer0 is only interrupt
    static uint16_t icount=0;   // counts the timer clicks

    icount+=512;

    if (icount>1000) {          // past a millisecond
        ++millis;
        icount-=1000;           // this preserves any error, which eventually smoothes out
    }
    INTCONbits.T0IF=0;          // turn off int flag
}

No comments:

Post a Comment