Wednesday, September 19, 2012

Extra interrupts

Once there is an interrupt routine, adding an extra interrupt is simple. In the last post there was only one thing causing an interrupt. There could have been any one of fourteen on a PIC16F873, so you need to check which interrupt has triggered, respond to it, reset the interrupt flag and return. I decided to add another to respond to the RB0 input. This pin can generate an interrupt on either a rising edge or a falling edge. I have tried both and it makes little difference, simply because I have a simple push switch that, like most switches, bounces. It switches on and off a few times as the button is pressed and even as the button is released. If a debounced switching system or real trigger such as a rotary encoder was being used then it would matter if the edge was rising or falling. The new interrupt routine is here:

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

    if (INTCONbits.T0IF) { // timer0 rolled
        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
    }
    if (INTCONbits.INTF) {  // RB0 input fired
        LEDoff=millis+2000;         // turn of secends from now
        INTCONbits.INTF=0;
    }
}


The great thing about now having a millisecond timer built-in is we can use it anywhere we want. Here I set a timer to the current millisecond+2000 and we can use that in the master loop to switch an LED on for two seconds.

        if (millis>LEDoff) {
            manual_LED=0;
        } else {
            manual_LED=1;
        }


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
}

Sunday, September 16, 2012

Timing using Bresenham's Algorithm

There are loads of reasons to time things, or wait for a specific time. If you want to wait for a specific time you can loop, doing nothing, until that time has elapsed. This can be useful, but it assumes the MCU is only doing one job. A better way it to count a time unit (such as a millisecond) in the background. Then you can get the current count, add the wait period and store the stop value, then keep checking in the main loop until the current count has exceeded the stored stop value. You will probably overshoot a little, but often this is OK. If you are trying to see if a button is pressed for, say, more than two seconds to respond to a long press, if you overshoot by a few micro seconds it makes no difference. If you are processing something regularly, such as displaying a timer, you can use the actual count time to check when the display should change. The nice thing is that you can use the count to test multiple wait or timer events independently. The snag is, how to build a reliable counter.

The PIC range have multiple timers, some of which get pressed into service for various jobs. Timer0 is always an 8 bit timer. It can either count external pulses (on a specific input pin) or increment each time the instruction cycle ticks. If an external crystal is used the instruction cycle runs at one quarter the crystal's frequency, so a 4MHz crystal means each instruction takes one one-millionth of a second and Timer0 will also increment at 1MHz. If the Timer0 is set running from zero, it will quickly reach 255 (in 255µs). At the next tick it will roll over to 0, so counting beyond 255 seems hard and 255µs is not that useful a length of time. The key is that as the timer rolls from 255 to 0, it can generate an interrupt.

An interrupt is a useful concept, when an interrupt is triggered the instruction the MCU is executing is finished, the address that the next instruction is at is stored (on the stack) and execution jumps to the interrupt address and continues there. When the interrupt code is complete it returns with a particular instruction which recovers the next address from the stack and jumps there to continue as if nothing has happened. Interrupt code must be short so as not to make everything else grind to a halt and it must not change the status registers so the original code really does continue unaffected. The XC-8 compiler for PICs handles the interrupt routine by letting you declare a function with the prefix interrupt. The function must be void and have no parameters and it shouldn't be called by anything else. XC-8 handles the saving and restoring of the status registers for you.

Now we have the means to use the Timer0 to generate ticks every 256µs (we need to set it up to do that) and that could be the basis of our count. Triggering an interrupt every 256µs is OK, if the code is very short, but it could be better if it was called less often - we are not going to be interested in approximately ¼ millisecond timing usually. Timer0 has a prescaler that is used as a divider to slowdown the rate at which the timer increments. If we use a prescaler of 4, the interrupt will fire every 1.024 milliseconds. We could use this as an approximation to a millisecond, and sometimes that is good enough. It would be possible to reset the Timer0 to count from a different number than 0, so counting from 250, four times gives exactly 1000, not 1024. This is fraught with problems, not least it adds a significant overhead to every interrupt routine, something to be avoided.

It would be acceptable to use a counter that is the number of 1024 ticks that have passed, but it is tempting to try to make a count in milliseconds. The counter and prescaler works in binary, so some sort of conversion is needed and a very neat one called Bresenham's Algorithm helps. This allows any difference between the counter and the target to be carried over and eventually smoothed out. To make the most of the prescaler we need to decide the resolution we want to count in. To count in 1ms units we need to use a prescaler that triggers the interrupt every 512µs, if we are happy to count in 2ms units we can use a prescaler that triggers every 1024µs.

The logic goes something like this:

volatile int millis;
millis=0;

...

// interrupt routine
interrupt void intrtn() {
    static int icount=0;
  
    icount+=512;
    if (icount>1000) {
        icount-=1000;
        ++millis;
    }
    // cleanup the interrupt stuff
}


So much for the theory, now lets see if I can make an LED flash at a reliable beat using this method ...

Driving motors works

Driving motors with PWM from midrange PICs works. There are 2 PWM outputs. They commandeer the Timer2 to control the signal timing. Working out what to set the timer bits to to get a given frequency and the duty cycle is a bit of arithmetic, but not too hard. I found a web site that helps you calculate it, plugging your required values in gives the required bit settings.

Using an Arduino is very, very much easier. There are six PWM outputs available and a single line of C code to set the duty cycle. The PWM frequency is fixed, so a less flexible. It is possible to change the frequency, but all the on-board timers get badly affected in the process.

If you want to drive more than two PWM with a PIC some of the PICF18 range have more PWM outputs. You could also output a simple signal on any pin controlling it yourself, but that would be a last resort for me, indeed I'd add another PIC first to get two more outputs.

Thursday, September 6, 2012

Driving Motors

I dug out a couple of small motors to try to drive. I have a 4 channel motor driver, L293D too. Micro controllers (MCU) cannot power a motor directly, the motor draws far too much current and would quickly destroy a micro controller in a puff of acrid smoke. Some sort of interface is needed that is controlled by the output of a MCU and switches the current needed by a motor. Motors come in a variety of voltages too, again the interface could handle this. There are a few options for the interface. One is to build your own using transistors to handle the difference in current and voltage but another is to use a dedicated chip, such as the L293D.

The L393D allows 2 motors to be connected, which can operate at up to 36V. They can each draw up to 600mA, which is not very much. There are motor drivers available that handle much bigger currents, but 600mA should do for now. The controller allows the motor to be driven in either direction too, which is useful.

The L293D has three control connections for each motor: enable, A and B. Enable lets the motor run, so if it is low the motor will not run. A and B determine the way the motor turns, if A or B is high and the other is low the motor will run in one direction depending which is high and which way round the motor is connected. If A and B are both low or both high the motor is braked to a halt, whereas if enable is made low when A or B (not both) is high then the motor coasts to a halt.

The chip has two supply pins, one logic supply should be the same as the micro controller and one to supply the motors. Keeping the two supplies separate is important, not only to prevent damage to the micro controller, but also because motors are very electrically noisy beasts. Some capacitors are often required across the motor connections to smooth out the spikes.

The L293D can respond to switching on and off at up to about 5kHz. If the enable pin is switched on and off quickly this will give the motor bursts of power with coasting in between. By varying the length of the pulse and the pause in between the speed the motor runs at can be controlled. This is ideal for Pulse Width Modulation from a MCU.