Monthly Monday Microcontroller Madness: Motors!


After speaking to a few folks that expressed an interest in the MMMM workshop, it became apparent (a) most folks were newbs who want to learn the basics and (b) everyone wants to control motors.  Excellent!  We’ll do that.

Although motor control is potentially a vast and complex topic, with highly specialized branches, the basics are fairly easy to learn — and they’ll take you pretty far.   So … we’ll be prepared to present the following items:

  • DC motors
  • H-bridge circuits — these let puny microcontrollers run fairly powerful motors
  • Stepper motors — just a little more complex to program than DC motors and they use H-bridge circuits too
  • Quadrature Encoders — these are a  simple and accurate way to read the position of something

We’ll also try to discuss some organizational items — like the logistics of future workshops and the use of the MMMM GitHub, so that we can build up assets collectively, share them with the world and manage changes and contributions in a free-and-easy-but-organized way.

If you are coming , please bring:

  • Yourself — If you’re a newb, welcome — If you’re an MCU Yoda, then attend you must and wisdom to newbs impart
  • Some ideas
  • A laptop if you have one
    • You may want to install VMWare Player or VMWare Fusion before you arrive
  • An MCU development kit if you have one or …
  • Some money if you don’t.  We’ll have some development kits that you can buy.  Plan on at least $10 for the kits and some parts that you can use for small learning projects.
  • A bread-board if you want to build some live circuits to keep.  We’ll have breadboards to loan, but if you want to take one home, it has to be one that arrived with you.

That’s about it — see you all Monday.  To whet your appetite, there is some prototype code below for reading a quadrature encoded position detector (not really elegant enough for a final effort, but it’s a start).  We’ll have you writing stuff like this in no-time.

This code is part of an effort to turn salvaged InkJet printers into motion controllers.  Most of these positioners let you position an InkJet head to within 1/600 inch — they’re fast, accurate, compact, surprisingly strong … and dirt-cheap.

#include  <msp430x20x2.h>

#define LED0 BIT0
#define LED1 BIT6
#define PHASE1 BIT1
#define PHASE2 BIT2
#define PHASE_MASK 6
#define PHASE_SHIFT 1

int state;     // used to hold current state of encoder bits (00, 01, 10 or 11) 
int lastState; // used to hold previous state of encoder bits (00, 01, 10 or 11) 
int pos;  // used to count steps. A 1/150" encoder (the most common kind) yields 600 steps per inck. 

// -- prototype of common bit of code used to compute the present state value 
void updateState(void);

int main(void)
{
	WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer 
	// --- set up some initial values 	
        pos = 0;
	P1DIR &= ~(PHASE1 + PHASE2); // Set P1.1 and P1.2 as inputs 	
        P1DIR |= (LED0 + LED1); // Set P1.0 and P1.6 to outputs. These are the LEDs on a LaunchPad. 

	// --- get initial conditions so that the first interrupt 	
 // has the right "edge" values and so that position calculations are based on feasible transitions 	
        updateState();
	lastState = state;

	P1IFG &= ~(PHASE1 | PHASE2); // clear interrupt flags for P1.1 and P1.2 	
        P1IE |= (PHASE1 | PHASE2); // P1.1 and P1.2 interrupt enabled 
	__enable_interrupt(); // enable all interrupts 	
 for(;;)
	{ /* just loop forever and let the interrupts do all the work */ }
}

// updateState() calculates updates for the edge detectors used in the interrupts 
// and also updates the "lastState" variable 
void updateState(void){
	state = P1IN & PHASE_MASK;

	if (state & PHASE1)
		P1IES |= PHASE1; // PHASE1 high, then interrupt on falling edge 	
        else
		P1IES &= ~PHASE1; // PHASE1 low, then interrupt on rising edge 
	if (state & PHASE2)
		P1IES |= PHASE2; // PHASE2 high, then interrupt on falling edge 	
        else
		P1IES &= ~PHASE2; // PHASE2 low, then interrupt on rising edge 

	// ---"right-justify" state so that it is in the range 0..3	
       state =  (state >> PHASE_SHIFT);
}

// Port 1 interrupt service routine #pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
    updateState();

    // --- test for all clockwise incremental cases      
 // if we stepped clockwise, then increment the position     
    if ( (lastState == 0 & state == 2)
       ||(lastState == 2 & state == 3)
       ||(lastState == 3 & state == 1)
       ||(lastState == 1 & state == 0)){
         pos++;
    }
    // --- If we didn't move clockwise, then we must have moved counter-clockwise     
 // so decrement the position     
    else{
        pos--;
    }

    // --- record last state     
    lastState = state;

    // --- update LEDs just to help debug     
    // use "state" as intermediate variable so that we can see the output value in the debugger easily     
    // This is just so that we can see the encoder signal. No functional purpose.     
    state = state + ((state << 5) & 0x40);
    P1OUT = state;

    // --- clear the interrupt flags     
    P1IFG &= ~(PHASE1 | PHASE2); // clear interrupt flags for P1.1 and P1.2  
}

5 Replies to “Monthly Monday Microcontroller Madness: Motors!”

  1. Hey Hive76, Monthly Monday Microcontroller Madness was awesome. Lindsay and I planned on coming Wednesday but got caught up with work. We’ll definitely be back though, you guys are super nice and it was a relaxed and inviting atmosphere. I learned a lot, and I’m looking forward to seeing you guys again soon. Keep up the good work

    Sincerely,

    Daniel and Lindsay

  2. Hi Dan,

    Thanks for the kind words and hope you become a regular at the MMMM. Do you still have the Computron? If so, it might be an awesome MCU project to lovingly up-cycle it (e.g. COMPUTRON twitter feed).

Comments are closed.