Category Archives: Steppers

18F14K22 Accelerometer Analog to Digital Converter C Electronics Microcontrollers Motors PIC Steppers

18F14K22 Self-Balancing Platform

Well, it’s not finished but this is what I’m working on:

Balancing platform on a breadboard
Balancing platform on a breadboard

Ta-da.. yet another balancing something-or-rather.. except this one isn’t so great at it’s balance. This was a big old fail. I went wrong with steppers… I should have just used DC motors and maybe the next version I will. I used Pololu A4988 stepper motor drivers (A4988-based)  to control my steppers while attempting to use variable speed step resolution control. This worked okay but really while trying to drop holding current while balanced was a nightmare. Also the current usage was above what I consider useful… either backing the current limiting off to save some power (and your driver) then loosing control or you’re just cooking your motor driver and the current isn’t useful other than for a cute demonstration or a non-battery powered application.

I’m not dropping code, you can request it directly if you want it but it’s nothing magical. It has my own hacked up version of a PID loop. I didn’t use derivative. I think far too many cycles are wasted on it when PI will probably work for you. I haven’t fine tuned it because I’m unhappy with my results.

I was a little bummed out on past-Chas’ selection of an MMA7361 accelerometer;  I had gotten it from Sparkfun who-knows-how-long-ago. The link leads to the retired product. It’s just plain voltage output per axis. I must have still been shying away from I2C at the point? The board shown below:

Accelerometer break-out board
Accelerometer break-out board

For a micro I used a PIC 18F14K22 on the TAUTIC dev board with some AtomSoft breadboard goodies for troubleshooting, power and the serial interface (Breadboard Buddy).  <– that link will probably die soon. Tindie updates a lot and products are replaced with newer versions.. if you sniff around you’ll find it.

I’ll move along to another project now, perhaps order some parts and revisit this one again. If you run along this and you’ve done this with steppers I’d be interested in knowing how it worked out for you.

Analog C Electronics Microcontrollers PIC Programming Steppers

Analog Stepper Gauge Friday night fun

Took a while to clear off the bench tonight. I got a little happy with the ORDER button last week through weekend. I’ve filled two more parts storage containers and luckily one of my new packages with another parts storage container from Amazon; I couldn’t find any locally, I hope they’re still making them.

The last thing I got to was this “Gauge Stepper Breakout” I got off The Rengineer (The Renaissance Engineer)’s Tindie store. Adam took this very nice stepper motor, put a gauge needle on it (which I believe he 3D printed, or at least it looks like it) and some nice diodes for voltage protection. What’s great about this board is you can drive it right from your microcontroller. I’m sure I don’t need to tell you how weird that is.. I worry about big LEDs.. but here this stepper was happy as a clam being powered by my PIC. I still might consider at least buffering this if I was to place it in a permanent  circuit.

Adam’s provides links to some Arduino libraries but he was saved me a ton of time and just happened to have some PIC sample code! Not before I had about 75% of a ECCP program completed. (I’ll link some of that code if you’re looking for an example of Enhanced PWM output). Once I had Adam’s code I ported it to the TAUTIC 18F26K22 dev board because I already had one on the breadboard. That was mostly changes in the TMR0 (timer 0) code. The only thing of note is check out my IO comments for wiring. You have to cook up 5V/GND to this board then I drove RC3 –> A1 RC2 — A2, RC1 –> B1 and RC0 –> B2. When I had it flipped around the stepper moved in the opposite direction of how I wanted.

A little video of the code in action:

This code is a little sloppy but I just testing this out and it did the trick:

 * File:   main.c
 * Author: Charles M Douvier  Contact at:
 * Core Driver Code by Adam F. of
 * Created on April 4th, 2014
 * Target Device:
 * TAUTIC PIC 18F26K22 Dev Board
 * Project:
 * Version:
 * 1.0

#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000 //4Mhz FRC internal osc
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))


//config bits


#define _XTAL_FREQ 4000000 //defined for delay
#define MIN_STEPS_LEFT 23
#define MAX_STEP 945 /* motor can move 945 steps from stop to stop*/

    int     an8_value, an9_value;          //value for a/d
    char    buf[10];            //buff for iota
    long int    fvar;           //long for format math
    long int    tens;           //left of decm
    long int    decm;           //decimal places
    int     tempi;              //to add leadign zeros..
    int     vtxdata;             //volts int for TX
    int     itxdata;

    unsigned short defaultAccelTable[][2] =
  {   1750, 3},
  {   1149, 3},
  {  926,   3},
  {  794,   3},
  {  709,   3},
  {  666,   4},
  {  /*629*/450,   4},
unsigned int currentStep;
unsigned char currentState;
unsigned char stateMap[] = {0x09, 0x01, 0x07, 0x06, 0x0E, 0x08};
unsigned char serialBuffer[10];
unsigned char serialByteCount;
 static const unsigned char stateCount = 6;

    volatile unsigned int uart_data;    // use 'volatile' qualifer as this is changed in ISR
void interrupt ISR() {

    if (PIR1bits.RCIF)          // see if interrupt caused by incoming data
        uart_data = RCREG;     // read the incoming data
        PIR1bits.RCIF = 0;      // clear interrupt flag


void init_io(void) {
    TRISAbits.TRISA0 = 0; // output
    TRISAbits.TRISA1 = 0; // output
    TRISAbits.TRISA2 = 0; // output
    TRISAbits.TRISA3 = 0; // output
    TRISAbits.TRISA4 = 0; // output
    TRISAbits.TRISA5 = 0; // output
    TRISAbits.TRISA6 = 0; // output
    TRISAbits.TRISA7 = 0; // output

    ANSELA = 0x00; // all port A pins are digital I/O

    LATAbits.LATA0 = 0;
    PORTAbits.RA0 = 0;

    TRISBbits.TRISB1 = 0;   //P1C output
    TRISBbits.TRISB2 = 0;  // P1B output
    TRISBbits.TRISB3 = 1;  // AN9    speed control 0-5V
    TRISBbits.TRISB4 = 0;  // P1D output
    TRISBbits.TRISB5 = 1; // RB5 = nc
    TRISBbits.TRISB6 = 0; // RB6 = nc
    TRISBbits.TRISB7 = 0; // RB7 = nc

    ANSELB = 0b00001000;     //RB3, AN9

    TRISCbits.TRISC0 = 0; // output to B2 .. reversed to stoke the right direction
    TRISCbits.TRISC1 = 0; // output to B1
    TRISCbits.TRISC2 = 0; // output to A2
    TRISCbits.TRISC3 = 0; // output to A1
    TRISCbits.TRISC4 = 0; // output
    TRISCbits.TRISC5 = 0; // output
    TRISCbits.TRISC6 = 0; // output
    TRISCbits.TRISC7 = 0; // output
    ANSELC = 0x00; // all port B pins are digital I/O

void uart_xmit(unsigned int mydata_byte) {

    while(!TXSTA1bits.TRMT);    // make sure buffer full bit is high before transmitting
    TXREG = mydata_byte;       // transmit data

void serial_init(void)
    //9600 8N1
    // calculate values of SPBRGL and SPBRGH based on the desired baud rate
    // For 8 bit Async mode with BRGH=0: Desired Baud rate = Fosc/64([SPBRGH:SPBRGL]+1)
    // For 8 bit Async mode with BRGH=1: Desired Baud rate = Fosc/16([SPBRGH:SPBRGL]+1)

    TXSTA1bits.BRGH=1;       // select low speed Baud Rate (see baud rate calcs below)
    TXSTA1bits.TX9=0;        // select 8 data bits
    TXSTA1bits.TXEN = 1;     // enable transmit

    RCSTA1bits.SPEN=1;       // serial port is enabled
    RCSTA1bits.RX9=0;        // select 8 data bits
    RCSTA1bits.CREN=1;       // receive enabled

    SPBRG1=25;  // here is calculated value of SPBRGH and SPBRGL

    PIR1bits.RCIF=0;        // make sure receive interrupt flag is clear
    PIE1bits.RCIE=1;        // enable UART Receive interrupt
    INTCONbits.PEIE = 1;    // Enable peripheral interrupt
    INTCONbits.GIE = 1;     // enable global interrupt

         __delay_ms(50);        // give time for voltage levels on board to settle

    uart_xmit('R');         // transmit some data

// All this motor and timer code is from Adam with very minor changes to fit the processor

void t0Delay(unsigned int usec)
    unsigned int t0ticks; //16 microsecond timer0 ticks
    unsigned char t0Preload;
        t0ticks = usec/16;
    t0Preload = 0xFF - t0ticks;
    INTCONbits.TMR0IF=0; //clear the flag
    TMR0 = t0Preload;

void zeroMotor()
    unsigned int i;
    for (i=0; i < MAX_STEP; i++)
        currentState = (currentState + 5) % stateCount;
        t0Delay(1900);  //2200 in datasheet
    //now the motor is zeroed, reset our state variables.
    currentStep = 0;
    currentState = 0;
    LATC=0; //turn off coils

void moveMotor(unsigned int targetStep)
    unsigned int dir;
    unsigned int curDelay;
    unsigned char speedIndex=0;
    unsigned char stepsAtThisSpeed=0;
    unsigned int stepsLeft;
    if(currentStep<targetStep)     {         dir = 1;         stepsLeft = targetStep-currentStep;     }     else     {         dir = -1;         stepsLeft = currentStep - targetStep;     }     while(stepsLeft>0)
        if(stepsLeft<=MIN_STEPS_LEFT)         {             //decellerating             if(stepsAtThisSpeed==0)             {                 if(speedIndex>0)

            //accellerating or steady state
                if(speedIndex<MAX_ACCEL_INDEX)                 {                     speedIndex++;                     curDelay=defaultAccelTable[speedIndex][0];                     stepsAtThisSpeed=defaultAccelTable[speedIndex][1];                 }                 //else we're at steady state - do nothing.             }         }         //write step         LATC=stateMap[currentState];         if(dir==1)         {             currentState = (currentState + 1) % stateCount;         }         else         {             currentState = (currentState + 5) % stateCount;         }         t0Delay(curDelay);         if(stepsAtThisSpeed>0)

int main(void) {


    // set up oscillator control register, using internal OSC at 4MHz.
    OSCCONbits.IRCF = 0x05; //set OSCCON IRCF bits to select OSC frequency 4MHz
    OSCCONbits.SCS = 0x02; //set the SCS bits to select internal oscillator block

    ADCON0 = 0b00100101;                            //select AN9 and enable
    ADCON1 = 0b00000000;                  //speed Vref=AVdd, VssRef=AVss
    ADCON2 = 0b00111011;                //ledft justified, 20RAD, FRC

    INTCONbits.TMR0IE = 0;


    T0CONbits.T08BIT = 1;
    T0CONbits.T0CS = 0;
    T0CONbits.PSA = 0;
    T0CONbits.T0PS = 0x04;
    INTCONbits.TMR0IF = 0;

        T0CONbits.TMR0ON = 1;


    currentStep = 0;
    currentState = 0;

    __delay_ms(149);        //this could be less messy


    while (1) {

        //PORTAbits.RA0 = 1;      //heart beat
        //PORTAbits.RA0 = 0;

        ADCON0 = 0b00100101;    //select AN9 and enable
        GO = 1;
        while (GO) continue;    //wait for conversion
        an9_value = ADRESH;     //AN9 value

        fvar = an9_value;
        fvar = fvar * 10749;    //calibration.. change to meet your needs
        fvar = fvar / 256;
        tens = fvar / 100;
        //tens = tens % 10;
        decm = fvar % 100;
        vtxdata = fvar / 20;
        uart_xmit(vtxdata);    // -->RS232

        //moveMotor(5); //from sample code
    return (EXIT_SUCCESS);

Some ECCP ( Enchanced PWM ) code written for the PIC 18F26K22 code I wrote following the screen shot of the output:

Deadband on Enhance PWM mode output on PIC
Deadband on Enhance PWM mode output on PIC

void pwm_init(){

//    CCPR1L = 0x120;
    CCPR1Lbits.CCPR1L = 0xFE;
    PR2 = 0xFE;
    CCPTMRS0bits.C1TSEL = 0;     //CCP TMR2 Selection
    CCP1CONbits.P1M = 0x02;     //half bridge
    CCP1CONbits.DC1B = 0x00;
    PWM1CONbits.P1RSEN = 0;
    PWM1CONbits.P1DC = 0x1F;    //dead band delay
    ECCP1ASbits.CCP1AS = 0x00;
    ECCP1ASbits.CCP1ASE = 0;    //Auto-shutdown off
    CCP1CONbits.CCP1M = 0x0C;
    PSTR1CONbits.STR1A = 1;
    PSTR1CONbits.STR1B = 1;

    T2CONbits.T2CKPS = 1;
    T2CONbits.TMR2ON = 1;


//.. now dump something smaller than 127 into CCPR1Lbits.CCPR1L
//to set the pulse width