This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi,
I am trying to implement a servo motor(sg90) into the msp430's potentiometer. I want the servo motor to be controlled by the potentiometer i.e turning the potentiometer would turn the motor. I have the ADC code but I am struggling with the other code needed to implement this. Any help would be greatly appreciated. Thanks a lot!
I assume you mean A/D, not "potentiometer".
For a servo, you need to set a PWM to a particular frequency and adjust the duty cycle. Can you show us what you have? We don't want to just do your homework for you.
try the timer_a_ex4_pwmMultipleUpDown example.
Here s a servo tutorial:
https://learn.sparkfun.com/tutorials/basic-servo-control-for-beginners/servo-motor-basics
For your servo, you want a 20 millisecond period and a duty cycle that varies from 5% (1mS pulse) to 10% (2ms pulse)
Hi Bilal,
Not sure what you want to output from MSP430.
If it is a digital signal, you can take the suggestion from Keith.
If it is a analog signal, this device can not derectly ouput a analog voltage (DAC). Maybe you can output a PWM signal to simulate a analog signal.
B.R.
Sal
A servo is a motor that takes a certain pwm signal to set a motor to a particular position. In this case a 7.5ms pulse with a 20ms repetition rate is used to set the servo to its zero position. Adjustments in duty cycle set different positions. They are used extensively in small radio controlled vehicles.
I suggest you go to SparkFun, get one, and play with it it is pretty fun.
Thanks Keith for introduction, I got what servo is. Just potentiometer seems like a voltage output which makes me little confused.
B.R.
Sal
He did not say it clearly. I believe this is a beginner's homework assignment that takes the position of a potentiometer and sets a servo accordingly via a reading from the ADC, and subsequent setting of the PWM dutycycle.
The servomotor equivalent of a blinky.
Hi Keith, thank you for your response. This is what my code is looking like right now and im not sure how to adjust it.
#include <msp430.h>
#include <driverlib.h>
#include <Board.h>
void configureADC()
{
//ADC setup
SYSCFG2 |= ADCPCTL9; // turn on analogue pin 9 so it is not GPIO
ADCCTL0 |= ADCON; // TURN ON ADC
ADCCTL1 |= ADCSHP; // choose bit 9
ADCCTL1 |= ADCSSEL_2; // choose SMCLK
ADCCTL2 |= ADCRES_2; // clock resolution
ADCMCTL0 |= ADCSREF_7; //+ve and -ve reference pins
ADCMCTL0 |= ADCINCH_9; // A9 as input input
ADCIFG &= ~0x01; //Clear interrupt flag
ADCIE |= ADCIE0; //Enable ADC conversion complete interrupt
}
void initPWM() {
TA0CCTL1 = OUTMOD_7; // CCR1 reset/set
TA0CTL = TASSEL_2 + MC_1 + TACLR; // SMCLK, up mode, clear TAR
TA0CCR0 = 20000-1; // PWM Period for 20ms (50Hz)
TA0CCR1 = 1000; // Initial duty cycle for 1ms pulse
P1DIR |= BIT2; // P1.2 as output for PWM
P1SEL0 |= BIT2; // P1.2 option select
}
void main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
configureADC(); // Setup ADC
initPWM(); // Setup PWM for servo
__bis_SR_register(GIE); // Enable global interrupts to start ADC
while(1) {
ADCCTL0 |= ADCENC | ADCSC; // Start sampling/conversion
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, ADC_ISR will force exit
}
}
// ADC interrupt service routine
#pragma vector=ADC_VECTOR
__interrupt void ADC_ISR(void) {
if(ADCIFG & ADCIFG0) { // Check if conversion is complete
unsigned int adcValue = ADCMEM0; // Fetch ADC conversion result
unsigned int dutyCycle = 1000 + (adcValue * 1000 / 4095); // Map ADC value to duty cycle range
TA0CCR1 = dutyCycle; // Update PWM duty cycle to adjust servo position
ADCIFG &= ~ADCIFG0; // Clear interrupt flag
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
}
I want the motor to rotate, but nothing is happening when I rotate the A/D on the msp430. I have also connected it to a 5V supply so I’m unsure why it’s not working.
One problem is that 1.2 does not connect to the Timer, it is used by the USCI.
You need to use 1.6 or 1.7 as the example shows:
//
// MSP430FR4133
// ---------------
// /|\| |
// | | |
// --|RST |
// | |
// | P1.7/TA0.1|--> CCR1 - 75% PWM
// | P1.6/TA0.2|--> CCR2 - 25% PWM
//
this is what my code looks like now :
#include <msp430.h>
#include <driverlib.h>
#include <Board.h>
void configureADC() {
// ADC setup
SYSCFG2 |= ADCPCTL9; // Enable A9 for ADC input
ADCCTL0 |= ADCON; // Turn on ADC
ADCCTL1 |= ADCSHP; // Sample-and-hold pulse-mode select
ADCCTL1 |= ADCSSEL_2; // SMCLK as ADC clock source
ADCCTL2 |= ADCRES_2; // 12-bit conversion results
ADCMCTL0 |= ADCSREF_7; // Reference voltages are V(R+) = VREF+ and V(R-) = VREF-
ADCMCTL0 |= ADCINCH_9; // A9 as input
ADCIFG &= ~0x01; // Clear interrupt flag
ADCIE |= ADCIE0; // Enable ADC conversion complete interrupt
}
void initPWM() {
// Configure GPIO
P1DIR |= BIT7; // Set P1.7 as output
P1SEL0 |= BIT7; // Select TA0.1 option for P1.7
// Timer A0 configuration for PWM
TA0CCTL1 = OUTMOD_7; // CCR1 reset/set
TA0CTL = TASSEL_2 + MC_1 + TACLR; // SMCLK, up mode, clear TAR
TA0CCR0 = 20000-1; // PWM Period: 20ms (for 50Hz)
TA0CCR1 = 1500; // Start with a neutral duty cycle (e.g., ~7.5% for 1.5ms pulse width)
// Note: Adjust the TA0CCR1 value based on ADC reading in ADC_ISR
}
void main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
configureADC(); // Setup ADC
initPWM(); // Setup PWM for servo
__bis_SR_register(GIE); // Enable global interrupts to start ADC
while(1) {
ADCCTL0 |= ADCENC | ADCSC; // Start sampling/conversion
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, ADC_ISR will force exit
}
}
// ADC interrupt service routine
#pragma vector=ADC_VECTOR
__interrupt void ADC_ISR(void) {
if(ADCIFG & ADCIFG0) { // Check if conversion is complete
unsigned int adcValue = ADCMEM0; // Fetch ADC conversion result
// Map ADC value to PWM duty cycle range (1000 for 5% to 2000 for 10%)
unsigned int dutyCycle = 1000 + (adcValue * 1000 / 4095);
TA0CCR1 = dutyCycle; // Update PWM duty cycle to adjust servo position
ADCIFG &= ~ADCIFG0; // Clear interrupt flag
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
}
> unsigned int dutyCycle = 1000 + (adcValue * 1000 / 4095);
The FR4133 has a 10-bit ADC. Also it is highly probable that the multiplication will overflow. The overall result is that your offset from 1000 (full-right?) will vary in a very small range. You might do better with something like:
> unsigned int dutyCycle = 1000 + (adcValue * 1000UL / 1024);
---------------
> ADCMCTL0 |= ADCSREF_7; // Reference voltages are V(R+) = VREF+ and V(R-) = VREF-
I expect you don't have the external VREF pins connected, so I'm not sure what the result will be. SREF=0 (VCC) or =1 (internal VREF) will probably get better results.
---------------
You're setting (by omission) ADCSHT=0, which is a very short time, particularly coming from a resistor-divider circuit -- those generally have very high impedance. You're not in a big hurry, so trying setting ADCSHT to something fairly large, e.g.
> ADCCTL0 |= ADCSHT_6; // 128 ADC clocks for sample/hold
I only have a 2311 available, but this code works - I changed the numbers to get your 20ms period.
This is the MSP430fr231X_tb0_16 example.
I suggest you start with a simple pwm example to get it working before you hook up the ADC.
(Oh, and please use the code insert facility to make your code readable)
int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop WDT P1DIR |= BIT6 | BIT7; // P1.6 and P1.7 output P1SEL1 |= BIT6 | BIT7; // P1.6 and P1.7 options select // Disable the GPIO power-on default high-impedance mode to activate // previously configured port settings PM5CTL0 &= ~LOCKLPM5; TB0CCR0 = 20000; // PWM Period TB0CCTL1 = OUTMOD_7; // CCR1 reset/set TB0CCR1 = 15000; // CCR1 PWM duty cycle TB0CCTL2 = OUTMOD_7; // CCR2 reset/set TB0CCR2 = 5000; // CCR2 PWM duty cycle TB0CTL = TBSSEL__SMCLK | MC__UP | TBCLR; // SMCLK, up mode, clear TBR __bis_SR_register(LPM0_bits); // Enter LPM0 __no_operation(); // For debugger }
Thanks a lot guys for your time and patience - I'll give that a go and hopefully it works. Cheers
**Attention** This is a public forum