Forum: Mikrocontroller und Digitale Elektronik MSP430G2553 PWM Duty Cycle mit Poti einstellen


von C. B. (windmill)


Lesenswert?

Hallo zusammen,

ich versuche mit meinem MSP430G2553 Launchpad ein PWM Signal(zwischen 
100Hz-1000Hz) erzeugen, dessen Duty Cycle ich mit einem Poti (über 
ADC10) einstellen möchte.(Später werde ich mit 2 Poti sowohl Frequenz 
als auch Duty Cycle, aber erst mal Duty Cycle!) Im Grunde werde ich den 
ADC10MEM Wert zu den CCR1 zuweisen, damit ich den Duty Cycle einstellen 
kann. Dafür benutze ich P1.5 als ADC Eingang und P1.7 als PWM Ausgang. 
Wenn ich 1 kHz Frequenz einstelle, toggelt der P1.7 mit halber Frequenz 
mit dem (festen)50% Duty Cycle, aber ich kann den Duty Cycle nicht 
ändern. Das geht irgendwie nicht.

Ich würde mich sehr freuen, wenn ihr euch mein Code anschauen und sagen, 
wo ich den Fehler mache.

Mit freundlichen Grüßen


#include <msp430.h>
unsigned int value=0;

#define FreqMin 10000 //100 Hz
#define FreqMax 1000 //1000 Hz

void ConfigureAdc(void);
void ConfigureTimer(void);

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

    BCSCTL1 = CALBC1_1MHZ; // Set range
    DCOCTL = CALDCO_1MHZ;
    BCSCTL2 &= ~(DIVS_3); // SMCLK = DCO = 1MHz

    P1DIR |= BIT0 + BIT6;
    P1OUT &= ~(BIT0 + BIT6);
    P1OUT |= BIT2; // +3,3V at P1.2

    P1DIR |= BIT7;
    P1OUT |= BIT7;
    //P1SEL |= BIT7; // P1.7 is PWM output

    ConfigureAdc();
    ConfigureTimer();

    //__enable_interrupt(); // Enable interrupts.
    __bis_SR_register(GIE);

    while(1)
       {
          __delay_cycles(1000); // Wait for ADC Ref to settle

          TA0CCR0 = FreqMax; //PWM period ---> 1MHz/TA0CCR0= Frequency
          TA0CCR1 = 750;  // PWM Duty Cycle

          ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
          __bis_SR_register(CPUOFF);// + GIE); // LPM0 with interrupts 
enabled
          value = ADC10MEM;

        if (value>511)
        {
         P1OUT &= ~(BIT0 + BIT6);
         P1OUT |= BIT0; // RED LED
        }
        else
        {
         P1OUT &= ~(BIT0 + BIT6);
         P1OUT |= BIT6; // GREEN LED
        }

       }
}


 void ConfigureAdc(void)
 {
   /* Configure ADC Channel */
     ADC10CTL0 &= ~ENC;
     ADC10CTL1 = INCH_5 + ADC10DIV_3 + ADC10SSEL_3; // Channel 5 + 
ADC10CLK/4 + ADC10CLK=SMCLK=1MHz
      ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE; //Vcc & Vss 
as reference + 64xADC10CLK
      ADC10AE0 |= BIT5; // P1.5 is ADC input
 }


 void ConfigureTimer(void)
 {
   TACCTL0 = CCIE; // Capture/compare interrupt enable
   TA0CTL = TASSEL_2 + MC_1; // SMCLK + up mode
   TA0CCTL1 = OUTMOD_7; // Output mode reset/set
 }



 // ADC10 interrupt service routine<br />
 #pragma vector=ADC10_VECTOR
 __interrupt void ADC10_ISR (void)
 {
    __bic_SR_register_on_exit(CPUOFF); // Return to active mode
 }

 // Timer A0 interrupt service routine


 #pragma vector=TIMER0_A0_VECTOR
   __interrupt void Timer0_A0 (void)
{
  P1OUT ^= BIT7;            // Toggle red LED
}

von Nico (nico123)


Lesenswert?

Wo weist Du denn den ADC-Wert dem PWM-Register zu?
Ich kanns nicht finden und deswegen wirds auch nicht funktionieren.

von C. B. (windmill)


Lesenswert?

Ich weise erstmal nicht zu. Ich gebe einen festen Wert 750(75%). Wenn 
das funktionieren würde, hätte ich schon ADC10MEM Wert zu CCR1 
zugewiesen.

von C. B. (windmill)


Lesenswert?

Interrupt wird immer nur dann ausgelöst, wenn der Wert CCR0 erreicht 
wird. Dann toggelt der P1.7 mit 50% Duty Cycle. Also, der Timer erkennt 
CCR1 gar nicht.

von Dennis (Gast)


Lesenswert?

Du musst nur mit dem OUTMOD_7 arbeiten, ohne ISR - dafür ist der ja.

CCR0 setzt die Periodendauer, CCR1 den Duty-Cycle. Das kannst du nun 
unabhängig voneinander einstellen. Den entsprechenden Pin dem Timer 
zuweisen.

von MSP430 (Gast)


Lesenswert?

Genau, dafür gibt es die verschiedenen OUTMODE. Das wird direkt durch 
die Hardware unterstützt und benötigt keinen zusätzlichen Code für 
Interrupts.

Aber es geht natürlich auch zu Fuß. Ein Blick in den Family User Guide 
im Kapitel TimerA zeigt uns ....., dass es zwei Interrupts für den 
TimerA gibt! Einen für TACCR0 und einen Shared Interuppt, der auch mit 
TACCR1 verbunden ist. Du musst den Ausgang in der anderen ISR setzen und 
in der vorhanden löschen. Oder umgekehrt.

von C. B. (windmill)


Lesenswert?

Hey,
vielen Dank! ich kann jetzt mein LED mit dem Poti dimmen.

von MSP430 (Gast)


Lesenswert?

C. B. schrieb:
> ich kann jetzt mein LED mit dem Poti dimmen

Schön, dass es läuft. Und wie hast du es gemacht?

von C. B. (windmill)


Lesenswert?

Früher war P1.7 Ausgang und das hab ich vom Oszi gelesen. Jetzt hab ich 
kein Oszi. deswegen hab ich P1.6(grün LED auf dem launchpad) als Timer 
Ausgang geändert. Timer ISR hab ich deaktiviert.

was mich aber noch denken lässt ist, dass der ADC10 mir nur bis 750 LSB 
gibt, was in dem Fall gut ist, weil mein CCR0 1000 ist. Aber ich hätte 
erwartet, dass der ADC10MEM die Werte bis 1023 geben sollte. Ich nimme 
3,3V von P1.2 und schließe nur einen 50k Poti an.
Übrigens, ist es in Ordnung, dass der Timer ISR leer ist?

#include <msp430.h>
unsigned int value=0;

#define FreqMin 10000 //100 Hz
#define FreqMax 1000 //1000 Hz

void ConfigureAdc(void);
void ConfigureTimer(void);
void ConfigureSystemClock(void);

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

    ConfigureSystemClock();

    P1DIR |= BIT0 + BIT6;
    P1OUT &= ~(BIT0 + BIT6);
    P1OUT |= BIT2; // +3,3V at P1.2

    //P1DIR |= BIT7;
    //P1OUT |= BIT7;
    P1SEL |= BIT6; // P1.6 is PWM output

    ConfigureAdc();
    ConfigureTimer();

    TA0CCR0 = 1000; //PWM period ---> 1MHz/TA0CCR0= Frequency
    TA0CCR1 = 500;  // PWM Duty Cycle

    //__enable_interrupt(); // Enable interrupts.
    __bis_SR_register(GIE);

    while(1)
       {
          __delay_cycles(1000); // Wait for ADC Ref to settle

          ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
          __bis_SR_register(CPUOFF);// + GIE); // LPM0 with interrupts 
enabled
          value = ADC10MEM;

          TA0CCR1 = value;

        if (value>511)
        {
         P1OUT &= ~(BIT0 + BIT6);
         P1OUT |= BIT0; // RED LED
        }
        else
        {
         P1OUT &= ~(BIT0 + BIT6);
         //P1OUT |= BIT6; // GREEN LED
        }

       }
}
/***********************************************************************
 ***********************Configurations**********************************
 **********************************************************************/

 void ConfigureSystemClock(void)
 {
   BCSCTL1 = CALBC1_1MHZ; // Set range
   DCOCTL = CALDCO_1MHZ;
   BCSCTL2 &= ~(DIVS_3); // SMCLK = DCO = 1MHz
 }

 void ConfigureAdc(void)
 {
   /* Configure ADC Channel */
     ADC10CTL0 &= ~ENC;
     ADC10CTL1 = INCH_5 + ADC10DIV_3 + ADC10SSEL_3; // Channel 5 + 
ADC10CLK/4 + ADC10CLK=SMCLK=1MHz
     ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE; //Vcc & Vss as 
reference + 64xADC10CLK
     ADC10AE0 |= BIT5; // P1.5 is ADC input
 }


 void ConfigureTimer(void)
 {
   TACCTL0 = CCIE; // Capture/compare interrupt enable
   TA0CTL = TASSEL_2 + MC_1; // SMCLK + up mode
   TA0CCTL1 = OUTMOD_7; // Output mode reset/set
 }

/***************************************************************
 *******************Interrupt Service Routine********************
 ***************************************************************/

 // ADC10 interrupt service routine<br />
 #pragma vector=ADC10_VECTOR
 __interrupt void ADC10_ISR (void)
 {
    __bic_SR_register_on_exit(CPUOFF); // Return to active mode
 }

 // Timer A0 interrupt service routine

 #pragma vector=TIMER0_A0_VECTOR
   __interrupt void Timer0_A0 (void)
{
  //P1OUT ^= BIT6;            // Toggle green LED
}

von MSP430 (Gast)


Lesenswert?

Ok, hier ein Beispiel für OUTMODE auf dem Launchpad:
1
#include <msp430g2553.h>
2
3
#define LED_GREEN   BIT6
4
#define TASTE_S2    BIT3
5
6
int main(void) {
7
8
   WDTCTL = WDTPW + WDTHOLD; // WDT stoppen
9
10
   BCSCTL1 = CALBC1_1MHZ;    // Sytemtakt
11
   DCOCTL = CALDCO_1MHZ;
12
13
   P1SEL |= LED_GREEN;       // LED zeigt PWM
14
   P1DIR |= LED_GREEN;
15
   
16
   P1REN |= TASTE_S2;        // Pullup einschalten
17
   P1OUT |= TASTE_S2;
18
   
19
   TACCR0 = 1000;            // Frequenz einstellen
20
   TACCR1 = 100;             // Tastverhältnis 1 : 9
21
   TACCTL1 = OUTMOD2 | OUTMOD1 | OUTMOD0;    // TAO.1 im Mode 7
22
   TACTL = TASSEL1 | MC0 | TACLR;            // Timer einstellen und löschen
23
24
   while (1) {
25
     
26
     TACCR1 = (P1IN & TASTE_S2) ? 100 : 900;  // Tastverhältnis umdrehen
27
     
28
   }
29
30
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.