Forum: Mikrocontroller und Digitale Elektronik MSP430G2553 und WS2812b Datensignal erzeugen mit Interrupt und Timer A0


von Benjamin B. (benjamin_b320)


Angehängte Dateien:

Lesenswert?

Hallo Zusammen

Ich versuche mich seit Montag Morgen mit den 144 Stück WS2812b LEDs und 
einem MSP430G2553.
Dieses Projekt ist ein Teilprojekt eines Grösseren...
Naja wen das dann klappen sollte.

https://www.mikrocontroller.net/articles/WS2812_Ansteuerung
Die LEDs brauchen ein Signal von 800kHz, meines schwankt zwischen 793 
kHz und 813 kHz. Was meines erachten genug genau ist.

Das ich nicht all zu viel Zeit verliere dachte ich, versuche ich mich 
mit Interrupts.
Soweit so klar, mein erster Interrupt funktioniert Yeaaass

Nun möchte ich aber zuerst nur die ersten 8 Bits ausgeben.
Als Versuch und Kontrolle.

Leider bekomme ich 12 Bits auf dem Oszilloskop über, was natürlich nicht 
sehr nützlich ist. (Bild im Anhang)
Sieht jemanden den Fehler, oder sind 800kHz zu schnell mit diesem 
Ansatz?


Meine Programmierstruktur lässt wünschen übrig, hoffe jedoch das es 
verständlich aufgebaut ist.

edit Richtiges Bild angehängt


1
#include <msp430.h> 
2
3
#define LED BIT6
4
#define LED_TH 7
5
#define LED_TL 3
6
#define LED_ON 19
7
8
unsigned int i = 0;
9
10
11
#pragma vector=TIMER0_A0_VECTOR;
12
__interrupt void LED_print()                 //Profisorische Datenübergabe Bitweise, LED_TH oder LED_TL setzen
13
    {
14
    i++;
15
16
      if(i<=8)
17
          {
18
          TA0CCR1 = LED_TH;
19
          }
20
      if(i>=8)
21
        TA0CCR0 = 0;
22
    }
23
24
25
int main(void)
26
{
27
    //                                  INIT                                     //    //----------------------------------------------------------------------------//
28
29
    WDTCTL = WDTPW | WDTHOLD;                                 // stop watchdog timer
30
31
    DCOCTL = CALDCO_16MHZ;                                    //MSP auf 16mHz
32
    BCSCTL1 = CALBC1_16MHZ;
33
34
    __enable_interrupt();                                    //interrupts aktivieren
35
36
    P1OUT = 0;
37
    P1DIR = LED;                                                //LED OUTPUT
38
    P1SEL  = LED;                                              //LED Quelle Auswählen
39
    P1SEL2 =~LED;
40
41
    TA0CTL = TASSEL_2 | ID_0 | TACLR;                          //Quelle auf SMCKL, 16mHz/0 = 16 mHz, Zähler in UP Mode
42
    TA0CCTL0 = TAIE | CCIE | TAIFG | CCIFG;                    //Interrup einstellen, Capter Compar Interup enable
43
    TA0CCTL1 |= OUTMOD_7;                                      //Output Mode LOW als wen Aus!!
44
    TA0CCR0 = LED_ON;                                         //Zeit EInstellen LED ON = 18 = 813kHz
45
    TA0CTL |= MC_1;
46
47
48
  while(1);
49
}

edit Richtiges Bild angehängt

: Bearbeitet durch User
von Clemens L. (c_l)


Lesenswert?

19 Taktzyklen zwischen zwei Interrupts ist zu wenig. Ein extrem 
optimierter Assembler-Interrupt-Handler könnte das vielleicht schaffen.

Ich hätte eher versucht, dieses Muster mit SPI auszugeben.

: Bearbeitet durch User
von Oder Falschversteher (Gast)


Lesenswert?

Clemens L. schrieb:
> 19 Taktzyklen zwischen zwei Interrupts ist zu wenig.

Warum?

Bei der Wahl des richtigen Outmode braucht nur ein Register bedingt 
geladen zu werden.

von Benjamin B. (benjamin_b320)


Lesenswert?

Hallo Zusammen

Ja die 19 Zyklen sind wenig. Ich habe nun auf ein MSP430F5529 Board 
gewechselt, da ich dieses gerade noch zur Hand habe. Dazu habe ich den 
Code noch angepasst mit den passenden Register.

Auf dem P2.2 Habe ich dann den SMCKL ausgegeben. Hier miss ich nun 
25.6mHz. Allerdings nicht das schönste Rechtecksignal.

Nun dachte ich ich gebe es auf den P1.2 aus. Mit dem Oszilloskop kam 
hier aber nichts raus...

Ich habe leider noch nicht sehr viel Übung mit Programmieren. Aber was 
nicht ist, kann noch kommen.

Freue mich auf eine Antwort.

Grüsse Benj
1
#include <msp430.h> 
2
3
#define LED BIT2
4
#define LED_TH 7
5
#define LED_TL 3
6
#define LED_ON 35000
7
8
unsigned int i = 0;
9
10
#pragma vector=TIMER0_A0_VECTOR;
11
__interrupt void LED_print()                 //Profisorische Datenübergabe Bitweise, LED_TH oder LED_TL setzen
12
{
13
    switch (TA0IV)
14
    {
15
        case 0xE:
16
            if (i < 8)
17
            {
18
                TA0CCR1 = LED_TL;
19
            }
20
            else
21
            {
22
                TA0CCR1 = 0;
23
            }
24
            i++;
25
            break;
26
27
        case 0:
28
            __no_operation();
29
            break;
30
31
        default:
32
            __no_operation();
33
    }
34
}
35
36
37
int main(void)
38
{
39
    //                                  INIT                                     //
40
    //----------------------------------------------------------------------------//
41
42
    WDTCTL = WDTPW | WDTHOLD;                                 // stop watchdog timer
43
44
    UCSCTL2 = FLLN9 | FLLN8;                                  //BIT 9+8 FFLD_0 = Freqenz /1
45
    UCSCTL1 |= DCORSEL_5;
46
47
48
    __enable_interrupt();                                     //interrupts aktivieren
49
50
    //P1OUT = LED;
51
    P1DIR = LED;                                              //LED OUTPUT
52
    P1SEL = LED;                                              //LED Quelle Auswählen
53
54
    TA0CTL = TASSEL_2 | ID_0 | TACLR;                         //Quelle auf SMCKL, 25mHz/0 = 25 mHz, Zähler in UP Mode
55
    TA0CCTL0 = TAIE | CCIE | TAIFG | CCIFG;                   //Interrup einstellen, Capter Compar Interup enable
56
    TA0CCTL1 = OUTMOD_7;                                      //Output Mode LOW als wen Aus!!
57
    TA0CCR0 = LED_ON;                                         //Zeit EInstellen LED ON = 18 = 813kHz
58
    TA0CTL |= MC_1;
59
60
61
  while(1);
62
}


PS. Die Zeiten mit LED_TH und LED_TL stimmt nicht mehr überein.

: Bearbeitet durch User
von Clemens L. (c_l)


Lesenswert?

Benjamin B. schrieb:
> Allerdings nicht das schönste Rechtecksignal.

Der Modulator schaltet zwischen zwei Frequenzen um (siehe Abschnitt 
5.2.8 des User's Guide).

> #pragma vector=TIMER0_A0_VECTOR;
> ...
> switch (TA0IV)

TIMER0_A0 ist der separate Vektor für CCR0 und taucht nicht in TA0IV 
auf.

>         case 0xE:
>         case 0:

Dafür gibt es TA0IV_TAIFG und TA0IV_NONE.

> TA0CCR1 = 0;

Wenn du den Timer anhalten willst, dann solltest du MC auf 0 setzen.

> TA0CCTL0 = TAIE | CCIE | TAIFG | CCIFG;

TAIE ist der falsche Interrupt (für den du keinen Handler hast), aber 
zum Glück setzt du dieses Bit im falschen Register. Genauso TAIFG. Und 
mit CCIFG bekommst du sofort einen Interrupt.

von Benjamin B. (benjamin_b320)


Lesenswert?

Hallo Clemens

Ich war noch in der Berufsschule und kann erst wider an meinem Projekt 
arbeiten. Zum Glück habe ich noch ein wenig Zeit um Programmieren zu 
lernen bis zum Abschluss ;)

Aber vielen Dank für die Antwort.

Ich habe den Code nochmals umgeschrieben und habe nun gleichzeitig SMCKL 
auf Pin 2.2 und mein PWM Signal auf Pin 1.2

SMCKL ist auf 24,4 mHz ca 25mHz/800kHz = 31.25 also müsste ich TA0CCR0 = 
31 Setzten.
Dabei bekomme leider nur 495kHz...

Da Proble ist das ich immernoch zwei Amplitude bekomme, auch wen ich 
eigentlich den Interrupt nur einmal Ausführen möchte und dann TA0CCR0 = 
MC_0 setzte um den Timer zu stoppen.

Hier mal den Code:
1
#include <msp430.h> 
2
3
#define LED BIT2
4
#define LED_TH 10
5
#define LED_TL 8
6
#define LED_ON 31
7
unsigned int i = 0;
8
9
#pragma vector=TIMER0_A1_VECTOR;
10
__interrupt void LED_print()                 //Profisorische Datenübergabe Bitweise, LED_TH oder LED_TL setzen
11
{
12
    switch (TA0IV)
13
    {
14
    case TA0IV_TAIFG:
15
            if (i < 1)
16
            {
17
                TA0CCR1 = LED_TH;
18
            }
19
            else
20
            {
21
                TA0CCR0 = MC_0;
22
            }
23
            i++;
24
            break;
25
26
        case TA0IV_NONE:
27
            __no_operation();
28
            break;
29
30
        default:
31
            __no_operation();
32
    }
33
}
34
35
int main(void)
36
{
37
    WDTCTL = WDTPW | WDTHOLD;                              // stop watchdog timer
38
39
    UCSCTL1 |= DCORSEL_7;
40
    UCSCTL2 = FLLN9 | FLLN8;                               //BIT 9+8 FFLD_0 = Freqenz /1
41
42
43
    __enable_interrupt();                                  //interrupts aktivieren
44
45
    P2DIR = LED;                                           //LED OUTPUT
46
    P2SEL = LED;                                           //LED Quelle Auswählen
47
    P1DIR = LED;                                           //LED OUTPUT
48
    P1SEL = LED;                                           //LED Quelle Auswählen
49
50
    TA0CTL |= TASSEL_2 |  MC_1 | TAIE | TACLR;             // | TACLR Quelle auf SMCKL, 25mHz/0 = 25 mHz, Zähler in UP Mode
51
52
    TA0CCTL1 = OUTMOD_7|TAIFG;
53
    TA0CCR0 = LED_ON;                                         //Auf 800kHz
54
55
56
  while(1);
57
}

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.