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 }
Wo weist Du denn den ADC-Wert dem PWM-Register zu? Ich kanns nicht finden und deswegen wirds auch nicht funktionieren.
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.
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.
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.
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.
C. B. schrieb: > ich kann jetzt mein LED mit dem Poti dimmen Schön, dass es läuft. Und wie hast du es gemacht?
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 }
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.