Friday, November 16, 2012

Just too easy

One of the really nice things about Arduino is the way it connects to a PC. You can plug a simple USB cable between a laptop and the Arduino and it powers the board, allows the programs to be downloaded into the board and allows the board and the laptop to exchange info.

If you want an Arduino to control something mobile, then a wire to a laptop is a bit limiting. Plugging in to download a program change is OK, but sending commands or receiving feedback means that limiting cable. Except it doesn't.

I bought a little board with a 5V bluetooth module on it for a few pounds from Ebay. There are four connections, VCC & ground go where you would expect, Tx plugs onto the Rx pin (0) and Rx plugs onto Tx pin (1). You have to power it from the coax (or VIN) to release the transmit and receive pins from the USB connection. The coax works well with a 9V battery. A short sketch to read incoming characters and the on-board LED was switched with commands over bluetooth using the BlueTerm Android app. It worked first time.

I'd like to experiment some more with bluetooth, and I might write an Android app to make the phone end a bit more slick or purpose-made. The freedom from cables is wonderful.

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.

Wednesday, August 29, 2012

Hello World for PIC

When testing out a new programming language the simplest program is to write out "Hello World". Making an LED light when a switch is closed must be similar for a micro controller. My first foray into PIC coding in C was to respond to three switches with three LEDs and it worked well. What I'm impressed by is the simplicity of the code and how easy it was to put that code into the PIC ready for use.

The code is here:

/*************************************************
 * Description: switch on LEDs with switches
 *
 * File: switches.c
 * Author: Chris Hill
 * Created: August 2012
 *
 ************************************************/

#include
#include

__CONFIG(FOSC_XT & WDTE_OFF & PWRTE_ON & CP_OFF & BOREN_OFF & LVP_OFF & CPD_OFF & WRT_ON);

/***** GLOBAL VARIABLES *****/
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;


#define SW1 PORTBbits.RB7
#define SW2 PORTBbits.RB6
#define SW3 PORTBbits.RB5

#define sLED1 sPORTB.RB2
#define sLED2 sPORTB.RB1
#define sLED3 sPORTB.RB0

void main() {

    // initialisation
    TRISB = 0b11111000;

    for (;;) {
        sLED1 = SW1 ? 1 : 0;
        sLED2 = SW2 ? 1 : 0;
        sLED3 = SW3 ? 1 : 0;

        PORTB=sPORTB.port;
    }
}



It looks quite long at first sight, but it is simple enough, most of the complexity coming from a union to create a shadow for PORTB. This allows the shadow PORTB to be addressed as an eight bit integer or as individual bits. I like to use the shadow for ports because it helps with the read-modify-write problem of I/O ports. There no need to debounce the switches, the LEDs would just flash so fast that no one would notice.

The compiler makes accessing registers in various banks much easier, such as TRISB, makes everything a bit more readable and so less prone to errors - though perhaps professional assembler programmers might not agree. The resulting code is 47 words long out of 4096 available in the PIC16F873, so room to grow.

The hardware layout to test this was set up on bread board, rather randomly set up as a temporary test. I used an external crystal - I usually do - so I needed to connect two 33pF capacitors between GND and the crystal and pins 8 & 9, hook up +5v to pin 20, two GND pins 8 & 19 and connect the MCLR (pin 1) to +5v. You need this for every circuit so it it easy enough to leave it on a bread board ready for the next circuit. This is not quite as plug and go as an Arduino, but not too hard either. If I build something I want to make more permanent then something on Veroboard is easy to make too.

Overall I think the PicKit 3 and the XC8 C compiler from Microchip has encouraged me to dabble again micro controller electronics. So what next?

Monday, August 27, 2012

PicKit 3

I've had a long lay off from electronics, but the bug has bitten again. I wanted to drive some small motors at variable speeds. The way I would have tried in the past would have been to try using pulse width modulation from a Microchip PIC pin to create the pulses to drive a motor. The motor draws too much current to drive directly from a PIC pin, but a transistor or a half bridge would be fine, either using the PIC pin to control the motor.

I dug out the PIC chips I could find and looked on-line for datasheets etc. I found some PIC16F873 chips - t'Interweb informs me that these are out-of-date, but I thought I'd have a go anyway.

In the past I would have used Microchip's MPLAB to create the code for the PIC chip. The code would have been PIC assembler for their mid-range chips. I would then have copied the compiled code (as a hex file) to a program supplied by Velleman that used their K8084 PIC programmer to write it out to the chip. I never used the assembler enough to get properly familiar with it, so it was always an error-prone struggle that put me off a bit. All of this software expected to run on Windows which I am very happy to have moved away from onto Linux, so there is a another problem. Lastly the Velleman board connects with a serial cable (not USB) and it seems that a USB to Serial converter does not work with it.

I have since discovered Arduino. It uses USB, can be powered by the USB, has a C compiler that run in an IDE on Linux and works very well. Uploading the code to the Arduino is simple via the USB connection and the serial connection allows communication between the PC and the board. Arduino is easy to use and seems very popular, it does seem to be a bit of a one-size-fit-all. The chip usually comes pre-installed on a board with the external connections presented around the edges. Arduino is more expensive than a PIC and there are hundreds of PIC devices to choose from. I think the idea of using a PIC and Arduino in suitable places seems interesting too.

While I was looking at all of this I noticed that Microchip have ditched their in-house development platform and moved to Netbeans. This is an IDE I have used before. It works well so I thought I'd try it out. A download and install later and I could now assemble PIC code on my Linux PC, so the first Windows hurdle was overcome. Then I discovered that the Velleman PIC programmer didn't work - I think some of my soldering of the kit has let go. I looked for what the modern way of programming PICs (even my old ones) would be and discovered PicKit3. It is a programmer and debugger from Microchip which integrates nicely with the new Netbeans IDE, which they now call MPLabX. I found also that there are clones of PicKit 3 available so I ordered one from a Chinese company. It came with a Zero Insertion Force board for a range of chip sizes to plug into the PicKit 3 so plain PIC chips can be programmed.

So all that remained was to find a C compiler for PIC chips. As I looked through the literature on-line I discovered that Microchip have just released a new compiler called XC-8 for the mid-range PIC chips, like mine. The basic option is free. I have just downloaded it and installed it on my laptop into MPLabX, so now I need to try it.