Forum: Mikrocontroller und Digitale Elektronik MSP430 2 Timer Initialisierung


von E. Isser (Gast)


Lesenswert?

Guten Abend,
ich möchte mit einem MSP430g2453 zwei TimerA testweise zur Erzeugung von 
2 PWMs erzeugen jedoch verwirren mich gerade der User Guide von TI und 
diverse Beispiele im Internet.

Mein Ansatz:
Ich habe einen TimerA0 und TimerA1, die ich jeweils mit Der Taktquelle 
verbinde, ihnen den Modus zuteile und eventuell, wenn gewünscht einen 
Teiler zuweise. Weiterhin muss ich die Interrupts Aktivieren und die 
CCRx Werte zuweisen. Jetzt ist mein Problem, dass ich nicht ganz 
verstehe, welches der Interrupts wozu gehört.
Welches Interrupt wird bei TAxCTL (TAIE) ausgelöst und welches mit dem 
CCIE? Oder ist dort etwas doppelt(zuviel), wenn ich Globale Interrupts 
erlaube.

Soweit ich weiss, gibt es einmal die verwendeten, TIMERA0_A1_VECTOR und 
TIMERA1_A1_VECTOR, Vectoren und auch TIMERA0_A0_VECTOR bzw 
TIMERA1_A0_VECTOR.

Da bin ich gerade etwas durcheinander.
Vielleicht kann mir ja jemand weiterhelfen.

Danke im Vorraus!!

Code:
1
#include <msp430g2453.h>
2
3
volatile unsigned int i=0, j=0, k=0, l=0;
4
5
#pragma vector=TIMER0_A1_VECTOR
6
__interrupt void Timer_A0(void){
7
switch(TA0IV)
8
{
9
  case 2:
10
    i++;
11
    break;
12
  case 4:
13
    _NOP();
14
    break;
15
  case 10:
16
    j++;
17
    break;
18
}
19
20
#pragma vector=TIMER1_A1_VECTOR
21
__interrupt void Timer_A1(void){
22
switch(TA1IV)
23
{
24
  case 2:
25
    k++;
26
    break;
27
  case 4:
28
    _NOP();
29
    break;
30
  case 10:
31
    l++;
32
    break;
33
}
34
35
void main(void)
36
{
37
  WDTCTL = WDTPW + WDTHOLD;
38
  BCSCTL1 = CALBC1_16MHZ;
39
  DCOCTL = CALDCO_16MHZ;
40
  
41
  TA0CTL = TASSEL_2 + TAIE;
42
  TA1CTL = TASSEL_2 + TAIE;
43
  
44
  TA0CCR0 |= 65535-1;
45
  TA1CCR0 |= 65535-1;
46
47
  TA0CCR1 |= 32000 + CCIE;
48
  TA1CCR1 |= 15000 + CCIE;
49
50
  _enable_interrupts();
51
52
  TA0CTL = MC_1;
53
  TA1CTL = MC_1;
54
55
  while(1){
56
  }
57
}

von Stefan S. (blacknighthawk)


Lesenswert?

Hallo,

habe gerade nicht viel Zeit...

Aber musst du nicht noch die Ports für die PWM- Erzeugung zuweisen?

von E. Isser (Gast)


Lesenswert?

Hallo,
ja klar, für die PWM müsste ich diese noch zuweisen, aber die Variablen 
waren jetzt auch nur für einen Test, um zu sehen, in welche er 
reinspringt.
Funktioniert leider immer noch nicht so, wie es soll.
Verstehe da glaube ich irgendwas falsch.

von Stefan S. (blacknighthawk)


Lesenswert?

Hallo,

ich habe den Timer für PWM folgendermaßen initialisiert und gestartet:
1
void Init_Timer_A(void)  // Timer A init
2
{
3
        TACTL =  TASSEL_2 + ID_0 + MC_1;
4
}
5
6
7
void Start_Timer_A(int adc_wert)
8
{
9
10
  TACCTL1 = OUTMOD_7;
11
  TACCR0 = 1024;
12
  TACCR1 = adc_wert;
13
  
14
}
15
16
#pragma vector = TIMERA0_VECTOR
17
__interrupt void TimerA_ISR(void)
18
{
19
20
}

Wobei "adc_wert" variabel war.
Den Interrupt habe ich allerdings nicht benutzt.

Ich hoffe das hilft etwas.

von E. Isser (Gast)


Lesenswert?

Helfen tut alles!!
Danke schonmal,
Das Problem bei mir ist leider, die Timer anders angesprochen werden.
Soweit ich jetzt nochmal probiert habe, muss ich wohl zB.
für TimerA0:
1
TA0CTL |= TAIE;
für TimerA1:
1
TA1CTL |= TAIE;
initialisieren, um die Interrupts für den Überlauf zu aktivieren, statt 
die im gleichen Atemzug wie
1
TA0CTL = TASSEL_2 + TAIE;

Habe hier im Forum noch etwas gefunden, welche Interrupts bei Überlauf, 
CCR0, CCR1 und CCR2 aufgerufen werden.
Ist es also richtig, dass Überlauf bzw. CCR0
1
TIMER0_A0_VECTOR
bzw.
1
TIMER1_A0_VECTOR

und CCR1 & CCR2
1
TIMER0_A1_VECTOR
bzw.
1
TIMER1_A1_VECTOR

aufrufen?

Wenn das richtig ist, muss ich eigentlich nur noch genau wissen welche 
TAIV Bits ausgelesen werden müssen.
Bei TIMER0_A1_VECTOR sollte es doch TA0IV sein und
bei TIMER1_A1_VECTOR sollte es doch TA1IV sein.

Zu deinem Code, Danke, das mit der Funktion
Stefan S. schrieb:
> void Start_Timer_A(int adc_wert)
war echt Hilfreich!!
Nur die erste Funktion verstehe ich nicht ganz. Ist es sinnvoller so 
etwas in Funktionen zu initialisieren oder in der Main?

von Dennis (Gast)


Lesenswert?

Also um hier mal ein bisschen Klarheit reinzubringen:

Dein Prozessor hat zwei Timer (TA0 unf TA1) mit je drei Zählregistern 
(CCR0, CCR1 und CCR2). Diese beiden Timer sind individuell voneinander 
konfigurierbar.

Zum TA0 gehören folgende Interrupt-Handler:

TIMER0_A0_VECTOR und TIMER0_A1_VECTOR

Der erste ist ausschließlich für CCR0, der zweite bedient CCR1, CCR2 und 
den Überlauf, weche mittels TA0IV ausgewertet werden können, dabei gilt:

2:  CCR1
4:  CCR2
10: Überlauf

Genauso ist es für den Timer 1, nur eben mit seinen eigenen Registern, 
welche sich aber nur mit der 0 und der 1 in ihrem Namen unterscheiden.

Jetzt mal zu deinem Code:

E. Isser schrieb:
> TA0CTL = TASSEL_2 + TAIE;

Hier sagst du, dass Timer 0 als Quelle SMCLK bekommt und dass der 
ÜBERLAUF einen Interrupt auslösen soll - mehr erstmal nicht.

E. Isser schrieb:
> TA0CCR0 |= 65535-1;

CCR0 hält den Wert, bei dem der Timer einen Interrupt auslösen könnte, 
wenn du ihn in dem Modus betreibst - ein Wert von 65534 ist natürlich 
totaler Quatsch, denn da kannste auch einfach nur den Überlauf nehmen, 
was du ja auch schon getan hast. Außerdem verodert man den Wert nicht 
mit dem Register, da dan definitiv nicht die Zahl drin steht, die man 
wollte.

E. Isser schrieb:
> TA0CCR1 |= 32000 + CCIE;

Das ist jetzt leider totaler Blödsinn, denn auch CCR1 ist ein Register 
zum Halten eines Wertes - du kannst hier kein Bit für den Capture 
Compare Interrupt setzen. Das setzt du in TA0CCTL1 (hier in deinem Fall 
für TA0.1) - dann würde der Timer beim Erreichen des Wertes in TA0CCR1 
einen Interrupt auslösen.

E. Isser schrieb:
> TA0CTL = MC_1;

Hier kommt leider ein weiterer großer Fehler, denn du überschreibst beim 
Setzen des Modus auf Up mit dem "=" alle Einstellungen, die du vorher in 
TA0CTL gemacht hast, also die Taktquelle und das TAIE. Hier gehört die 
Veroderung hin.

Wenn du deine PWM unbedingt in Software lösen willst, dann würde ich es 
folgendermaßen machen:

Mit einem Timer setzt du die Perdiodendauer, also setzt du z.B. TA0CCR1 
auf 50000. Mit einem zweiten Timer TACCR2 setzt du das Tastverhältnis - 
hier trägst du z.B. einen Wert von 25000 ein, wodurch du eine PWM mit 
50% Duty-Cycle bekommst. Verändern tust du nur CCR2. Das ganze im 
Up-Mode.

In den ISRs passiert folgendes:
CCR1: Ausgangspin auf high
CCR2: Ausgangspin auf low

Fertig ist die PWM.

Aber es wäre blöd, das in Software zu lösen, wenn der MSP das auch in 
Hardware kann.

Stefan S. schrieb:
> void Init_Timer_A(void)  // Timer A init
> {
>   TACTL =  TASSEL_2 + ID_0 + MC_1;
> }
>
>
> void Start_Timer_A(int adc_wert)
> {
>   TACCTL1 = OUTMOD_7;
>   TACCR0 = 1024;
>   TACCR1 = adc_wert;
> }

Und das ist genau die richtige Variante dafür. CCR0 setzt den Pin auf 
high, CCR1 auf low und das ohne ISRs, welche man dann natürlich auch 
nicht braucht - eine leere ISR wie diese hier

Stefan S. schrieb:
> #pragma vector = TIMERA0_VECTOR
> __interrupt void TimerA_ISR(void)
> {
>
> }

lässt man dann weg, ABER setzt auch kein CCIE- oder TAIE-Bit, denn kann 
der uC sich irgendwo verrennen.


So, hoffe, es ist ein bisschen klarer. Gruß,

Dennis

von Dennis (Gast)


Lesenswert?

Nachtrag:

Dennis schrieb:
> Außerdem verodert man den Wert nicht
> mit dem Register, da dan definitiv nicht die Zahl drin steht, die man
> wollte.

Beim Start kann es OK sein, wenn das Register mit 0 initialisiert wird. 
Trotzdem: Lass es  da gehört ein "=" oder ein "+" hin, letzteres aber 
eher im Cont-mode.

von Dennis (Gast)


Lesenswert?

Sorry, noch ein Fehler entdeckt:

Dennis schrieb:
> In den ISRs passiert folgendes:
> CCR1: Ausgangspin auf high
> CCR2: Ausgangspin auf low

Das muss heißen:
CCR0: Ausgangspin auf high
CCR1: Ausgangspin auf low

von E. Isser (Gast)


Lesenswert?

Dennis schrieb:
> So, hoffe, es ist ein bisschen klarer. Gruß,

Das hat mir sogar sehr geholfen. Vielen Dank für die Mühe!!

Dennis schrieb:
> denn du überschreibst beim
> Setzen des Modus auf Up mit dem "=" alle Einstellungen,

Das war denke ich auch eines der Dinge die ich jetzt verstanden habe.

Dennis schrieb:
> Hier gehört die Veroderung hin.

Ich glaube ich hatte das auch nicht ganz verstanden, dass man Bits mit 
|= setzt und quasi Einstellungen mit einem = festlegt.

Dennis schrieb:
> Wenn du deine PWM unbedingt in Software lösen willst

Das war ja nur für einen Test, natürlich muss ich die Direction und 
Selection noch auf die entsprechenden Ausgägne setzen.

Ich glaube das hat mir sehr weitergeholfen. Werde es mal probieren.
Vielen Dank!

von Dennis (Gast)


Lesenswert?

E. Isser schrieb:
> Ich glaube das hat mir sehr weitergeholfen. Werde es mal probieren.
> Vielen Dank!

Kein Problem, gerne. Habe übrigens nochwas in meinem Text gefunden

Dennis schrieb:
> Lass es  da gehört ein "=" oder ein "+" hin, letzteres aber
> eher im Cont-mode.

Und da muss es natürlich "+=" heißen, nicht nur "+". Sorry

von E. Isser (Gast)


Lesenswert?

Also ich habe es heute mal ausprobiert und siehe da, es läuft!!
Allerdings habe ich ein kleines Problem und weiss da nun absolut nicht 
was das sein kann.
Die 2 PWMs werden erzeugt und laufen auch bei verschiedenen Werten 
super. Zwischendurch tritt aber für einen winzigen Augenblick ein Fehler 
auf, bzw die LEDs, welche ich angeschlossen habe leuchten kurz ganz hell 
auf, oder sind kurz dunkel. Das Ganze ist in einem Bruchteil einer 
Sekunde. Was kann das denn sein?

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.