Jump to content
43oh

First Project - Brushed DC Motor Controller


Recommended Posts

Well, after some researching and input from a couple people I have actually gotten off to a fairly good start on a basic motor controller using the MSP430G2231 which came with the Launchpad. Currently the controller takes input from three buttons, one for direction, the other two for increasing and decreasing the speed. Simple yes, but I am actually fairly happy with it so far, as this is my first time using anything other than the BasicATOM or BasicStamp MCU's. As such I had a bit of a learning curve transitioning from Basic to C.

 

The end goal of the project is to have the controller accept inputs from a RC radio/reciever and do the calculations necessary for a Proportional Steering system for a robot my business partner and I are working on. So still a long ways off. Also, being a newbie at this, my code may be bloated... frankly I'm just glad it works, but any input would be fantastic.

 

#include  

//variables
#define     BUTTON      BIT1    // Button on P1.1
#define     BUTTON2     BIT3    // Button on P1.3
#define     BUTTON3        BIT5    // Button on P1.5
unsigned int PWM = 100;
unsigned int Freq = 0;


void main(void)
{
 WDTCTL = WDTPW + WDTHOLD;                                 // Stop watchdog timer

 P1DIR |= (BIT0) + (BIT4) + (BIT2) + (BIT6);               // Set P1.0 P1.2 P1.4 AND P1.6 as Output Pins;
 P1SEL |= (BIT2);                                            // Tie TA0.1 to P1.2

 //Set Up Button P1.1
 P1DIR &= ~BUTTON;
 P1OUT |= BUTTON;
 P1REN |= BUTTON;
 P1IES |= BUTTON;
 P1IFG &= ~BUTTON;
 P1IE |= BUTTON;

 //Set Up Button P1.4
 P1DIR &= ~BUTTON2;
 P1OUT |= BUTTON2;
 P1REN |= BUTTON2;
 P1IES |= BUTTON2;
 P1IFG &= ~BUTTON2;
 P1IE |= BUTTON2;

 //Set Up Button P1.5
 P1DIR &= ~BUTTON3;
 P1OUT |= BUTTON3;
 P1REN |= BUTTON3;
 P1IES |= BUTTON3;
 P1IFG &= ~BUTTON3;
 P1IE |= BUTTON3;


 //PWM Generation on P1.2
 CCR0 = 1000-1;                                             // PWM Period
 CCTL1 = OUTMOD_7;                                         // CCR1 reset/set
 TACTL = TASSEL_2 + MC_1;                             

 _BIS_SR(LPM0_bits + GIE);                                 
}


#pragma vector=PORT1_VECTOR
__interrupt void Port1_ISR(void){

   //Direction
   switch(P1IFG & BUTTON) {

       case BUTTON:  
       P1OUT ^= BIT4;
         P1IFG = 0; 

   }

   //Increase Speed
   switch(P1IFG & BUTTON2) {

       case BUTTON2:
       if (Freq < 11) { 
           Freq++; 
           CCR1 = PWM*Freq;
           P1OUT &= ~BIT0;
           P1OUT |= BIT6;
             P1IFG = 0; 
       }
       else {
           P1OUT |= BIT0;
           P1OUT &= ~BIT6;
             P1IFG = 0; 
       }

   }


   //Decrease speed
   switch(P1IFG & BUTTON3) {

       case BUTTON3:
       if (Freq > 0) { 
           Freq--; 
           CCR1 = PWM*Freq;
           P1OUT &= ~BIT0;
           P1OUT |= BIT6;
             P1IFG = 0; 
       }
       else {
           P1OUT |= BIT0;
           P1OUT &= ~BIT6;
             P1IFG = 0; 
       }

   }

}

 

Feel free to comment away, use the code, etc. I do have some questions though, which may seem apparent, but I just can't seem to figure out.

 

1. I will actually need a total of 2 PWM signals, one per motor. Is this possible with this chip? I don't want to get to far in to it only to find out I need to switch MCU's.

 

2. I am at an absolute loss as to how to program the MCU to decode the RC signals. Basically, I need the MCU to measure the length of the pulses being sent by the receiver. (ie: 1.6ms = forward/10% Duty Cycle, 1.5ms = full stop, 1.4ms = Revers/10% Duty Cycle.) ANY input on this would be greatly appreciated.

 

 

Anyway, this forum has been awesome, probably the best source I have found along with NJC's blog. I just hope to be an additive part of it to some extent.

 

EDIT: On a side note, I also purchased a MSP-FET430U64 Target Board and Programmer, which this project will most likely fall back on if the Launchpad and Value Line MCU's aren't up to the task. So again, if you much more experienced people don't think this this platform will work, please let me know. :)

Link to post
Share on other sites

As far as the code bloat goes, you can cut that down by setting up all three buttons at the same time, instead of repeating the same commands three times.

 

Here's the bit manipulation tutorial I use.

http://www.avrfreaks.net/index.php?name ... ic&t=37871

 

//Set Up Buttons
 P1DIR &= ~BUTTON & ~BUTTON2 & ~BUTTON3;
 P1OUT |= BUTTON | BUTTON2 | BUTTON3;
 P1REN |= BUTTON | BUTTON2 | BUTTON3;
 P1IES |= BUTTON | BUTTON2 | BUTTON3;
 P1IFG &= ~BUTTON & ~BUTTON2 & ~BUTTON3;
 P1IE |= BUTTON | BUTTON2 | BUTTON3;

 

Additionally, I don't think that's the best use of a case/switch function. Case is best when you have multiple results from a test, essentially a long if,elseif,elseif,elseif,else sequence. You should have a single switch and four cases. Finally, you should disable the interrupt before processing the flag, and clear the flag before reenable the interrupt and lpm.

disable interrupt code;

switch(P1IFG) {
case BUTTON:
Direction code;
break;
case BUTTON2:
Increase code;
break;
case BUTTON3:
Decrease code;
break;
default:
error catching, etc;
}
P1IFG = 0; //Clear flag

reenable interrupt/lpm code;

 

As far as pwms, I think the short answer depends on the msp430 chip you have, is only one easy to set one. Possibly more if you play with the code.

The launchpad's included chips, the msp430G value line don't have alot of comparators/timers. But other, launchpad compatible chips do.

http://e2e.ti.com/support/microcontroll ... 56142.aspx

http://www.msp430launchpad.com/2010/07/ ... oh-my.html

 

There is also Binary Code Modulation (Or Pulse Code Modulation) if you can use that.

http://blog.hodgepig.org/2010/09/12/577/

Link to post
Share on other sites

Hehe, oh how I love to miss the obvious. Anyway, thanks for the feedback on the bloated code. However.... I am actually in the process of rewriting the whole thing. After doing some more research regarding PWM on the MSP430G2231 series, I decided to step away from the LaunchPad all together, and jump up to the MSP430F417 and/or F2619. Though I have a couple of both MCU's I am leaning towards the F417 as it is quite a bit cheaper than the F2619. Anyway, one I get this recoded and working on the new chip I'll post an update. :)

Link to post
Share on other sites

you can only have 2 separate PWM outputs on selected pins using the timer a as the PWM source for the msp430 value line. but i know if you have a SW driven PWM, you can easily hook up 5 with out a problem, more is possible depending on how much time you want to give to the interrupt.

as for the MSP430F417 seems like a good choice if you need the HW PWM.

I would personaly start with getting the basics working on the launchpad before moving to the bigger chip.

 

 

How many sensors, and motors are you planning to connect to your bot?

Link to post
Share on other sites

Well.... in regards to focusing on the LaunchPad for the time being, you are probably right.

 

In regards to the bot, everything other than the motor control will be handled via an on board laptop. (sensors etc) As for the motor controller, I need to drive 2 12v Brushed DC motors off a powered wheelchair. Yes there are plenty of off the shelf options for this, but it's the design and implementation of home brewed components that peak my interest.

 

Anyway, a bit of background, I am actually working on 2 separate projects, one being the bot, the other being a "hopefully" soon to be available automation machine for the restaurant industry. I have completely functional and viable control systems already developed for both, including the motor controller. But they rely on the BasicATOM from Basic Micro. In the interest of production cost on the commercial project (1 dollar per TI MCU versus 70+ for the Atom) my business partner and I made the decision to switch. The motor controller for the bot is basically my version of "Getting my feet wet" before trying to tackle the other project, which has 17 motors for repeating actuation of various belts, control arms, etc. In addition to various optical and proximity sensors.

 

My problem has been this: I'm a PHP developer and electronics hobbyist, the embedded world is a whole new ball game for me. I chose the Atom initially due to it's ease of use, and very minor learning curve. The Basic Micro Studio IDE and Basic programming language made throwing control routines together a snap. The MSP Value Line however has proven to be a completely different monster. Let alone the F series chips. As such I am starting with a basic motor controller prior to even getting started on the "machine". At this juncture I have decided to break the motor controller project in to individual segments. Starting with decoding the PPM signal from the receiver.

 

Now if you have managed to last through that whole diatribe, here's where I am at, and hopefully some of you may be able to help. The incoming signal from the receiver is PPM and has a pulse width of approx 1-2ms based on the location of the control stick. All I need the MCU to do is measure the length of the pulse width, then set the outbound PWM Duty Cycle accordingly. The PWM I have down, it's the measuring of the pulse width that has me stuck. On the Atom, there was a predefined Basic command to do this for you, but that's not the case with the MSP430's. I understand I can use Timer_A in continuous mode and the CCRx registers to do it, but as of yet have not been able to implement it. Nor have I been able to find anything in the TI Example Code database that can help. Any input or a point in the right direction would be great.

Link to post
Share on other sites

I would look at the metronome code for inspiration http://blog.hodgepig.org/2010/09/08/571/

it has a way to measure between button presses, to set the tempo. I am sure that it can be modified for your purpose

this might be a good spot for you to start.

also this PPM hack may help as well http://hackaday.com/2010/10/02/rc-ppm-hacked/

 

but sounds like you have some impressive projects coming along - Good luck and let me know is you need any more help

Link to post
Share on other sites

I have fallen back to the Launchpad for the time being to work on individual pieces of the code I'll need. Was a good idea doing so actually, lol. After a bit of trial and error I was able to get the MSP430G2231 am developing on to interpret the PPM signal being sent out from the Spektrum AR7000 Receiver I am using.

 

#include "msp430g2231.h"

volatile unsigned int sample1 = 0;
volatile unsigned int sample2 = 0;
volatile unsigned int ppm1 = 0;
volatile unsigned int count1 = 0;
volatile unsigned int totalCount1 = 0;
volatile unsigned int totalPulse1 = 0;



void main(void)
{
 WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

 BCSCTL1 = CALBC1_1MHZ;                       // Set DCO to 1MHz
 DCOCTL = CALDCO_1MHZ;


 P1DIR |= (BIT0) + (BIT6);                                  // Configure LEDS
 P1OUT &= ~BIT0;                                              // SET P1.0 TO LOW


 P1SEL |= (BIT1) + (BIT2);                                 // P1.1 AND P1.2 TO TA0.0/0.1
 P1DIR &= ~(BIT1) + ~(BIT2);                             // P1.1 AND P1.2 TO INPUT
 TACTL = TASSEL_2 + MC_2 + ID_3;                   // SMCLK, contmode
 TACCTL0 = CM_3+CCIS_0+SCS+CAP+CCIE;       // Capture on Both Edge + CCIxA +
                                                                         // Synchronous Capture + Capture + Interrupt Enabled
 _BIS_SR(LPM0_bits + GIE);                               // ENTER LPMO W/ INTERRUPTS 
 while(1);
}

#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
       count1++;
       totalCount1++;
       totalPulse1 = (totalCount1 / 2);
       if (count1 == 1){                              // Store sample 1
           P1OUT ^= BIT0;                            // Toggle LED on P1.0
           sample1 = TACCR0;
           TACCR0 = 0;
       }
       if (count1 == 2){                              // Store sample 2
           P1OUT ^= BIT0;                            // Toggle LED on P1.0
           sample2 = TACCR0;
           ppm1 = (sample2 - sample1);      // PPM pulse width
           count1 = 0;
           TACCR0 = 0;
       }

}

 

In this code, the variable ppm1 comes out between 110 and 210 depending on the location of the control stick on the DX7 Radio. It shouldn't be hard at all to use those numbers to set the Duty Cycle for outbound PWM's to the H bridge. One question I do have though is this: Is it possible to use the same timer to measure pulse width on a second I/O Pin? I will be needing to watch two different signals when it is all said and done. If I am understanding things correctly I am at this point only using a single CCRx? If so cant he second one be used in capture mode to analyze the second PPM signal?

Link to post
Share on other sites
If I am understanding things correctly I am at this point only using a single CCRx? If so cant he second one be used in capture mode to analyze the second PPM signal?

 

You can use the other compare register to look at the other pin using the same timer block.

This is good news. Keep at it.

Link to post
Share on other sites
  • 3 weeks later...
The MSP430 clock project instructable below generates 2 independent pwm signals from a MSP430G2211 (Launchpad part).

http://www.instructables.com/id/MSP430-Based-Chronulator-using-Launchpad-chip

 

The code could be used to drive DC motors with the correct transistor drivers.

 

Funny, I just found it yesterday and was writing a blog post. Thanks for the link and welcome to the forums - looks like you just joined.

Are you the author of the instructable? You may want to enter it for the "Project of the month Contest - Nov 2010"

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...