Forum: Mikrocontroller und Digitale Elektronik Geschwindigkeit einer Schleife


von Stef (Gast)


Lesenswert?

Hallo,
ich bin grad beim Programmieren eines MSP430, habe eine while Schleife, 
die unendlich läuft und in welcher ich immer Daten auf meine serielle 
Schnittstelle ausgebe. Nun habe ich das Problem, dass wenn ich mit dem 
Debugger händisch arbeite, die Daten perfekt an meinem PC ankommen, wenn 
ich aber auf run klicke ( ==> soll heißen Programm läuft ) dann kommen 
nurmehr fetzen von Daten an.
Nun schließe ich daraus, dass die Schnittstelle mit dem Schreiben der 
Daten nicht mehr nachkommt und deshalb möchte ich irgendwie die 
Geschwindigkeit der Schleife bremsen. Doch habe ich noch nichts wirklich 
passendes finden können.
Nun wende ich mich an euch, in der Hoffnung, dass mir hier jemand helfen 
kann.

Danke

Stef

von Karl H. (kbuchegg)


Lesenswert?

Stef wrote:

> Nun schließe ich daraus, dass die Schnittstelle mit dem Schreiben der
> Daten nicht mehr nachkommt

Auf einem µC hat die Serielle Schnittstelle ja normalerweise
eine Form von 'Ich arbeite noch'-Status. Wenn du also vor dem
Schreibvorgang diesen Status überprüfst, und solange wartest
bis die Schnitstelle 'frei' meldet, kann dieser Fall nicht
auftreten.

von Labberer (Gast)


Lesenswert?

Genauer gesagt muss es ein Uart statusregister geben, das ein bit 
enthaelt, das den TxReady zustand enthaelt. Das bit abfragen und warten. 
Ein Interrupt ist zwar praktischer

von Stef (Gast)


Lesenswert?

Danke für die Tipps, ich versuche es im Moment aber mit einer zweiten 
while Schleife, die so lange verzögern sollte, bis die Schnittstelle 
wieder "frei" ist.
Ist zwar kein schönes programmieren, aber vielleicht klappt es.
Sonst werde ich euch noch um genauere Informationen bitten müssen.

von Stef (Gast)


Lesenswert?

So, der Versuch mit meiner Schleife ist gescheitert, nun werde ich den 
Uart-Status abfragen müssen.
Ein paar Fragen dazu:
Wie genau sieht dieses Register aus:
Ist es: a) UART0 Interrupt Enable Register
        b) UART0 Interrupt Flag Register
        c) UART0 Module Enable Register
        d) keines von den oben genannten

Ich weiß nicht, welches dieser Register den Status enthält.


Wie sieht dieses Statusbit aus??

Danke


Stef

von Falk B. (falk)


Lesenswert?

@ Stef (Gast)

>So, der Versuch mit meiner Schleife ist gescheitert, nun werde ich den
>Uart-Status abfragen müssen.

Wohl wahr.

>Ich weiß nicht, welches dieser Register den Status enthält.

Schon mal das Datenblatt gelesen?

MFg
Falk

von Falk B. (falk)


Lesenswert?

When the transmitter is enabled (UTXEx = 1), data should not be written 
to
UxTXBUF unless it is ready for new data indicated by UTXIFGx = 1. 
Violation
can result in an erroneous transmission if data in UxTXBUF is modified 
as it
is being moved into the TX shift register.

von Stef (Gast)


Lesenswert?

Ich hab das nun so probiert, jedoch ohne Erfolg
( ja, wahrscheinlich ist es lächerlich, wie ich es probiert habe, aber 
ich
kenne mich noch nicht aus)

 if(UTXE0=1)
     {
          UTXIFG0=0;
          else
          UTXIFG0=1;
     }

Doch muss ersten bei If ein modifable value her, zweitens muss auch 
UTXIFG0 ein modifable value sein, und bei else erwartet mein Compiler 
ein Statement.


Kann mir nicht jemand ein Beispiel geben??

Danke

Stef

von Karl H. (kbuchegg)


Lesenswert?

Stef wrote:
> Ich hab das nun so probiert, jedoch ohne Erfolg
> ( ja, wahrscheinlich ist es lächerlich, wie ich es probiert habe, aber
> ich
> kenne mich noch nicht aus)
>
>  if(UTXE0=1)
>      {
>           UTXIFG0=0;
>           else
>           UTXIFG0=1;
>      }
>

Du sollst nicht UTXIFG setzen, sondern abfragen ob es 0 oder 1
ist! Nur dann wenn es 1 ist, darfst du einen neuen Wert zur
Schnittstelle geben.

Irgendwas in der Art
1
   //
2
   // Warte in einer Schleife solange, bis UTXIFG0 zu 1 wird
3
   //
4
   while( UTXIFG0 != 1 )
5
     ;

Was ich jetzt nicht weiss ist, ob UTXIFG0 ein komplettes Register
oder nur ein Bit in einem Register ist.

von Ampfing (Gast)


Lesenswert?

Hi Stef,

ohne jetzt Deinen Controller zu kennen und ungetestet!
1
while(1)
2
{
3
  while(UTXIFGx == 1);  //warten bis Schnittstelle fertig
4
  UxTXBUF = Daten;      //Daten ist das Byte, das übertragen werden soll
5
}

Dass du vorher die UART richtig initialisieren musst ist Dir klar, oder?

Viele Grüße

P.S.: was die Zeile "if(UTXE0=1)" tut weißt Du aber schon auch, oder??

von Falk B. (falk)


Lesenswert?

@ Stef (Gast)

>Doch muss ersten bei If ein modifable value her, zweitens muss auch
>UTXIFG0 ein modifable value sein, und bei else erwartet mein Compiler
>ein Statement.

Du solltest dir schnellstens eine gutes Buch über C besorgen.

>Kann mir nicht jemand ein Beispiel geben??

void putc(char data) {
    while(UTXIFG0 != 1);       // warte auf UART Transmitter
    U0TXBUF = data;            // Daten senden
}

MfG
Falk

von Ampfing (Gast)


Lesenswert?

Oje, Text falsch gelesen...
Die Zeile "while(UTXIFGx == 1);" muss natürlich ein "while(UTXIFGx != 
1);" sein, sorry.

Viele Grüße

von Stef (Gast)


Lesenswert?

Danke für die zahlreiche Hilfe, aber es funktioniert immer noch nicht:

Hier ist ein Teil von meinem Code:


 while(i < 20 )   /* Schleife, um unsigned char auszugeben */
            {
              {
                while(UTXIFG0 == 1);  //warten bis Schnittstelle fertig
                TXBUF0 = answer1[i];      //Daten ist das Byte, das 
übertragen werden soll
              }
              i++;
            }




Und diese while(i<20) Schleife befindet sich in meiner Endlosschleife.


Danke für weitere Anregungen

Stef

von Stef (Gast)


Lesenswert?

Achso, jetzt bin ich zu langsam gewesen. Ok, ich probier gleich einmal 
die neuere Variante aus.


Danke


Stef

von Karl H. (kbuchegg)


Lesenswert?

Stef wrote:
> Danke für die zahlreiche Hilfe, aber es funktioniert immer noch nicht:
>
> Hier ist ein Teil von meinem Code:
>
>
>  while(i < 20 )   /* Schleife, um unsigned char auszugeben */
>             {
>               {
>                 while(UTXIFG0 == 1);  //warten bis Schnittstelle fertig

Denkst du eigentlich auch selber mit?

Falk hat weiter oben einen Ausschnitt aus dem Datenblatt
gepostet. Darin steht eindeutig, dass UTXIFG0 erst dann zu 1
wird, wenn die Schnittstelle fertig ist. Das heist aber auch
im Umkehrschluss, dass solange gewartet werden muss, solange
UTXIFG0 nicht 1 ist!

   while( UTXIFG0 != 1 )
     ;

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

UTXIFG0 kann man nicht einfach so abfragen. Das ist nur eine numerische 
Konstante, die den Wert eines Bits in einem Register beschreibt.

Es muss geprüft werden, ob dieses Bit im zugehörigen Register IFG1 
gesetzt ist.

Eine korrekte Abfrage davon sieht so aus:

    while (!(IFG1 & UTXIFG0));   // USART0 TX buffer ready?

bzw. so für die zweite UART:

    while (!(IFG2 & UTXIFG1));   // USART1 TX buffer ready?


Im Gegensatz zur hier im Forum und bei AVRs sehr verbreiteten 
Bitshift-Schreibweise ist es bei der MSP430-Programmierung üblich, daß 
eine ein Bit beschreibende Konstante wie UTXIFG0 nicht die Bitnummer, 
sondern den Bitwert enthält.

Wäre es die Bitnummer, würde die Abfrage so aussehen:

    while (!(IFG1 & (1 << UTXIFG0)));

Aber das ist bei den üblichen MSP430-Compilern und den damit gelieferten 
Headerdateien definitiv nicht so realisiert.


Auszug aus msp430x14x.h von Rowley Crossworks:

#define UTXIFG0             (0x80)

Auszug aus io430x14x.h von IAR Embedded Workbench

enum {
  ...
  UTXIFG0             = 0x0080,
  ...
};

von MockUp (Gast)


Lesenswert?

@Falk Brunner (falk)
Sag mal hast du den ein gutes Buch parat.
Habe auch grad angefangen mit c.
VHDL war meine erste sprache. geht schon ganz gut

Uart, adc ausgabe an pins bekomm ich schon hin.
habe nen Mega128 auf der Platine von Uhlrich Radig.
das Datenblatt von dem Mega hab ich ausgedruckt.
Sollte man auf alle Fälle rein schauen,
in meinem sind auch c schnipsel drinne.

Wäre also nett wenn du ein gutes buch kennst!
hab keine lust Bücher zu kaufen die schrott sind.
Danke.

von Falk B. (falk)


Lesenswert?

@ MockUp (Gast)

>@Falk Brunner (falk)
>Sag mal hast du den ein gutes Buch parat.

Nein, aber schau dir mal die Buchempfehlungen an. Der Klassiker 
Kernigham und Ritchi sowie die diversen Ableger sind ganz OK. Ich hab 
hier "Programmieren in C" rumliegen, das reicht schon SEHR weit.

>Habe auch grad angefangen mit c.
>VHDL war meine erste sprache. geht schon ganz gut

VHDL ist aber was anderes.

Mfg
Falk

von MockUp (Gast)


Lesenswert?

Ja weiß ich.
Ok werde mal schauen, wo ich eins von denen bekomme.
Danke
MockUp

von Stef (Gast)


Lesenswert?

So, es würde nun so weit funktionieren, nur noch , dass die einzelnen 
Zeichen meines Charakters einzeln vervielfacht werden:
1
 ggggeeeeeeewwwwwaaaaaaaeeeeeeeehhhllllltttttee
2
eeerrrrrr    Kaannnnnnnaaaaaaall::0



So sieht mein Code jetzt aus, vielleicht erkennt jemand von euch den 
Feher:

1
 while (i < 20)             
2
            {
3
            do
4
                {                  
5
                  TXBUF0 = answer1[i];
6
                  
7
                }
8
                  while (!(IFG1 & UTXIFG0));
9
              
10
              i++;
11
            }
12
            TXBUF0 = '0';


Es müsste doch schon laufen, oder habe ich wieder einen Bock 
abgeschossen?

von Karl H. (kbuchegg)


Lesenswert?

Stef wrote:
> So, es würde nun so weit funktionieren, nur noch , dass die einzelnen
> Zeichen meines Charakters einzeln vervielfacht werden:
>
>
1
 ggggeeeeeeewwwwwaaaaaaaeeeeeeeehhhllllltttttee
2
> eeerrrrrr    Kaannnnnnnaaaaaaall::0
>
>
>
> So sieht mein Code jetzt aus, vielleicht erkennt jemand von euch den
> Feher:
>
>
>
1
 while (i < 20)
2
>             {
3
>             do
4
>                 {
5
>                   TXBUF0 = answer1[i];
6
> 
7
>                 }
8
>                   while (!(IFG1 & UTXIFG0));
9
> 
10
>               i++;
11
>             }
12
>             TXBUF0 = '0';
13
> 
14
>
>
>
> Es müsste doch schon laufen, oder habe ich wieder einen Bock
> abgeschossen?

Hast du.
Was ist eigentlich so schwer daran zu verstehen, dass man zuerst
abfragt, ob die Schnittstelle frei ist, und erst dann das Zeichen
auf den Weg bringt. Das sollte doch eigentlich klar wie
Klossbrühe sein.

Und wenn du dir endlich ein vernünftiges Einrückschema angewöhnen
würdest, dann würdest du auch sehen, dass du umgangssprachklich
ausgedrückt, folgendes programmiert hast:

  Sende ein Zeichen, solange die Schnittstelle nicht frei ist.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

So schreibst Du immer und immer wieder den auszugebenden Wert in das 
TXBUF-Register ... und gibst diesen Wert dadurch auch immer wieder auf 
der seriellen Schnittstelle aus. Daß das UTXIFG-Bit überhaupt mal 
gesetzt wird, ist eher Zufall.

Du solltest ZUERST warten, bis das UTXIFG-Bit gesetzt wird und DANN erst 
das Zeichen ausgeben:
1
  while (!(IFG1 & UTXIFG0));
2
  TXBUF0 = c;

Baue Dir am besten eine putc-Routine und rufe die von den entsprechenden 
Stellen auf:
1
void putc(char c)
2
{
3
  while (!(IFG1 & UTXIFG0));
4
  TXBUF0 = c;
5
}


Deine Ausgabeschleife ließe sich dann so formulieren:
1
i = 0;
2
while (i < 20)
3
{
4
  putc(answer1[i++]);
5
}
6
putc('0');

von Falk B. (falk)


Lesenswert?

@ Stef (Gast)

Versuchs mal damit
1
for (i=0; i<20; i++) {
2
    while (!(IFG1 & UTXIFG0));
3
    TXBUF0 = answer1[i];
4
}

Erkennst du die Schönheit? Und vor allem dass es so funktioniert?

MFG
Falk

von Stef (Gast)


Lesenswert?

Danke für die Hilfe, habe meinen Fehler aber entdeckt:
Und zwar so müsste es nun endgültig richtig lauten:

1
while (i < 20)             
2
            {
3
            
4
              TXBUF0 = answer1[i];
5
            while (!(IFG1 & UTXIFG0));
6
              
7
              i++;
8
            }
9
            TXBUF0 = '0';



Die Reihenfolge von TXBUF0= ...
und der while-Schleife ist ausschlaggebend!!


An alle ein herzliches Dankeschön und bis zu meinem nächsten Problem

;-)

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Ich wäre ja für das hier:
1
#define until(x) while(!(x))
2
3
for (i=0; i<20; i++) {
4
  until (IFG1 & UTXIFG0);
5
  TXBUF0 = answer1[i];
6
}

von Karl H. (kbuchegg)


Lesenswert?

Stef wrote:
> Danke für die Hilfe, habe meinen Fehler aber entdeckt:
> Und zwar so müsste es nun endgültig richtig lauten:
>
>
>
1
> while (i < 20)
2
>             {
3
> 
4
>               TXBUF0 = answer1[i];
5
>             while (!(IFG1 & UTXIFG0));
6
> 
7
>               i++;
8
>             }
9
>             TXBUF0 = '0';
10
>
>
>

Nein. Das ist immer noch falsch. Liest du eigentlich, was
wir hier so von uns geben?

>
> Die Reihenfolge von TXBUF0= ...
> und der while-Schleife ist ausschlaggebend!!

Das ist richtig.
Aber du musst zuerst abfragen, ob die Schnittstelle bereit
ist und erst dann das Zeichen senden!

Oder benutzt du zunächst mal das Auto deines Vaters und fragst
erst danach um Erlaubnis?

Abfragen ob die Schnittstelle frei ist:
1
     while (!(IFG1 & UTXIFG0))
2
       ;

Zeichen auf den Weg bringen:
1
     TXBUF0 = answer1[i];

Im Verbund:
1
   // zuerst abfragen, ob die Schnittstelle für die
2
   // Uebertragung des naechsten Zeichens frei ist,
3
   // und solange zuwarten, bis sie es ist
4
   while (!(IFG1 & UTXIFG0))
5
     ;
6
7
   // und dann das Zeichen ausgeben
8
   TXBUF0 = answer1[i];

von Stef (Gast)


Lesenswert?

Ok, ist ein viel besserer Programmierstil.
Aber im Moment bin ich froh, dass es nun läuft.

von Karl H. (kbuchegg)


Lesenswert?

Stef wrote:
> Ok, ist ein viel besserer Programmierstil.

Das hat nichts mit besserem Programmierstil zu tun.
Das ist eine Frage der Logik

> Aber im Moment bin ich froh, dass es nun läuft.
Bis es dann übermorgen, nach der 120-ten Programmergänzung
plötzlich nicht mehr läuft, weil du dich nicht an die einfachste
Sache der Welt halten kannst:
  * Zuerst nachfragen, ob ein Gerät bereit ist einen
    Befehl auszuführen und gegebenenfalls darauf warten,
    dass es bereit wird.
  * Dann dem Gerät den Befehl geben

von Stef (Gast)


Lesenswert?

Sorry, tut mir leid, aber meine Antwort hat sich auf Andreas Schwarz 
bezogen. Die Sachen mit den Programmierstil und so
Wenn ich aber so schreibe:
1
while (!(IFG1 & UTXIFG0)); 
2
              TXBUF0 = answer1[i];                          
3
              i++;

hänge ich bei meiner while Schleife endlos drinnen.
Deshalb habe ich veruschweise die while-Schleife hinter den TXBUF0 
gestellt und es hat danach funktioniert!!
Ich sehe es von der Logik schon ein, aber warum habe ich dann eine 
endlos Schleife, und andersherum nicht???
Nur aus den empirischen Resultaten habe ich die Struktur umgestellt.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Wenn ich aber so schreibe:
>
1
> while (!(IFG1 & UTXIFG0)); 
2
> TXBUF0 = answer1[i];                          
3
> i++;
4
>
> hänge ich bei meiner while Schleife endlos drinnen.
> Deshalb habe ich veruschweise die while-Schleife hinter den TXBUF0
> gestellt und es hat danach funktioniert!!


Was soll die völlig nutzlose Einrückung des auf die while-Schleife 
folgenden Codes? Lass sowas sein, das fördert nicht die Lesbarkeit des 
Codes.

Wenn es sich tatsächlich so verhält, wie Du beschreibst, dann lässt das 
darauf schließen, daß Du möglicherweise die UART nicht korrekt 
initialisierst.

Wie genau machst Du das?

von Stef (Gast)


Lesenswert?

Mhm, kann glaube ich auch nur das einzige sein


Hier, so hab ich das initialisiert:
1
P3SEL = 0x30;  // P3.4 und P3.5 als USART0 TXD/RXD
2
ME1 |= UTXE0 + URXE0;
3
.....
4
UCTL0 &= ~SWRST´
5
IE1 |= URXIE0 + UTXIE0;
6
IFG1 &= ~UTXIFG0;


Das wars eignetlich auch schon.
Was stimmt dann aber hier nicht?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Was soll das hier?
1
IFG1 &= ~UTXIFG0;

Wie sieht Dein Interrupthandler aus?

von Karl H. (kbuchegg)


Lesenswert?

Stef wrote:
> Mhm, kann glaube ich auch nur das einzige sein
>
>
> Hier, so hab ich das initialisiert:
>
>
1
> P3SEL = 0x30;  // P3.4 und P3.5 als USART0 TXD/RXD
2
> ME1 |= UTXE0 + URXE0;
3
> .....
4
> UCTL0 &= ~SWRST´
5
> IE1 |= URXIE0 + UTXIE0;
6
> IFG1 &= ~UTXIFG0;
7
>

Du löscht hier das UTXIFG0 Flag explizit.
Dadurch ist es natürlich nicht gesetzt, wenn du es das erste
mal abfrägst.

von Stef (Gast)


Lesenswert?

Genau, jetzt endlich.
Das habe ich für eine andere Applikation vorher gebraucht, die jetzt 
nicht mehr benötig wird.
Jetzt kann ich es endlich ausbessern.


Nochmals danke an alle für die tatkräftige Hilfe


Stef

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.