Forum: Mikrocontroller und Digitale Elektronik Wie ein Byte über den UART ausgeben?


von Mustermann (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich nutze einen EFM8SB1 MC auf einem SLSTK2010A Board von Silabs und 
möchte den Wert einer gesteuerten Stromquelle über den UART ausgeben. 
Nun habe ich mir bereits mehrere Beispiele durchgelesen und verschiedene 
Methoden ausprobiert, aber das Hyperterminal will nichts anzeigen.


Der Fehler wird vermutlich sehr einfach und dumm sein, da ich relativ 
neu auf dem Gebiet bin.


In einem Demo-Programm vom Hersteller wird das wie im angehängten Bild 
gemacht (links die Main, rechts die Interrupt Datei), wobei mir die 
Reihenfolge eher unüblich erscheint. Erst wird das Transmit-Flag 
gesetzt, dann in der Transmit ISR das Byte mit SBUF0=Byte ausgegeben. 
Funktioniert so auch. Aber eigentlich wird das TI Flag doch erst nach 
dem Senden gesetzt?



Meine Vorgehensweise nun (IREF0CN0 ist das Byte, in dem der Stromwert 
ist):


SI_INTERRUPT (UART0_ISR, UART0_IRQn)
{
  if(SCON0_TI==1)
  {

    LED0=0;
    IE|=IE_ES0__DISABLED;   //disable UART interrupts
    SCON0_TI=0;    //clear transmit flag

    SBUF0= IREF0CN0;

    IE|=IE_ES0__ENABLED;     //enable UART interrupts

  }
}


Es passiert, wie gesagt, nichts. Muss evtl der Code selbst verändert 
werden oder nur an anderer Stelle stehen, oder fehlt irgendeine 
Configuration? Die Baud Rate passt auf jeden Fall.

von Johnny B. (johnnyb)


Lesenswert?

Bist Du sicher, dass der Wert überhaupt im Terminal darstellbar ist 
gemäss einer ASCII-Tabelle?

Zum testen kannst Du ja einfach mal ein Zeichen schicken. z.B.
1
SBUF0 = 'T';

: Bearbeitet durch User
von Jim M. (turboj)


Lesenswert?

Mustermann schrieb:
> Es passiert, wie gesagt, nichts.

Setzt Du irgendwo in der main() das SCON0_TI flag? Das muss genau 1x 
gesetzt werden um damit den Interrupt "anzustoßen".

Alternativ schreibt man ein Byte ins SBUF0 register, denn das TI Flag 
wird auch nach dem Senden eines Bytes von der Hardware gesetzt.

von SklavenTreiber (Gast)


Lesenswert?

Bei einem Boolean musst du bei ner if-Abfrage nicht ==1 oder ==True 
machen, da reicht es einfach
if(flag){
    Wenn flag 1
}
zu machen

von Kein Sklaventreiber (Gast)


Lesenswert?

SklavenTreiber schrieb:
> Bei einem Boolean musst du bei ner if-Abfrage nicht ==1 oder ==True
> machen, da reicht es einfach
> if(flag){
>     Wenn flag 1
> }
> zu machen

Das das ja nix mit dem Problem zu tun hat, nehme ich an, dass Du nur 
einen Verbesserungsvorschlag zum Kodierstil geben wolltest.

Dem möchte ich jedoch ein ABER hinzufügen.

In der Fallunterscheidung werden Wahrheitswerte betrachtet. Soweit 
richtig.
Das ein Boolean nicht zwangsläufig verglichen werden muss, ist bis dahin 
auch korrekt.

Allerdings soll der Code ja auch lesbar sein.

Wenn Du daher eine Variable wie "isValid" oder "receiverReady" oder eine 
Funktion wie "available()" abfragst, dann ist das gut verständlich und 
lesbar, weil man die Bedeutung und die Aussage sofort versteht.

Wenn man aber sowas wie "SCON0_TI" betrachtet, dann ist es durchaus 
sinnvoll, den Vergleich komplett auszuschreiben. SCON0_TI ist wenig 
bezeichnend und könnte ja auch außer true (1) oder false (0) vielleicht 
auch mal eine 3 enthalten.
Das weiß man nur, wenn man weiß was SCON0_TI genau ist.

Daher ist
1
if(SCON0_TI==1) {
2
}

schon genau richtig.

Noch schöner wäre es, wenn man anstelle der "1" eine bezeichnende 
Konstante verwendet.

Zum Beispiel
1
if( SCON0_TI == TX_INTERRUPT_FLAG_SET) {
2
}


Aber das nur als kleiner Einwand - man muss nicht immer alles auf's 
Minimum wegkürzen. Das erschwert oft nur die Arbeit... insbesondere, 
wenn man nach einem halben Jahr den Code nochmal ändert. ;)

von SklavenTreiber (Gast)


Lesenswert?

Ja, das hat nichts mit dem Thema zu tun. Da es eine 3 enthalten könnte 
hab ich extra „bei Boolean“ geschrieben und ja du hast recht, manchmal 
ist es besser es auszuschreiben aber in diesem Fall würde ich es 
persönlich weglassen. Ist wohl Geschmackssache.

von S. R. (svenska)


Lesenswert?

Kein Sklaventreiber schrieb:
> Zum Beispiel
> if( SCON0_TI == TX_INTERRUPT_FLAG_SET) {
> }

Das kann in die Hose gehen, wenn SCON0_TI tatsächlich Flags enthält. 
Denn wenn mehrere Flags gesetzt sind, ist der Vergleich falsch.

Dann schriebe man besser:
1
if( SCON0_TI & TX_INTERRUPT_FLAG_SET ) {
2
}
Und achte darauf, dass hier das genaue Ergebnis ebenfalls nicht 
ausgewertet wird. Wie SklavenTreiber schon schrieb.

von Mustermann (Gast)


Lesenswert?

Johnny B. schrieb:
> Bist Du sicher, dass der Wert überhaupt im Terminal darstellbar ist
> gemäss einer ASCII-Tabelle?
>
Das wäre eine Überlegung wert. Es ist halt ein 8 Bit Register, und der 
problemlosen Kompilierung habe ich entnommen, dass es geht. Allein daran 
wird's aber nicht liegen, denn ich habe es zuvor mit einem char 
versucht, mit dem selben Ergebnis.


>Setzt Du irgendwo in der main() das SCON0_TI flag? Das muss genau 1x
>gesetzt werden um damit den Interrupt "anzustoßen".


Nicht in der Main, sondern in der Timer ISR zuvor. Ich will mit einem 
Rotary Encoder die Stromquelle steuern (habe noch SEHR mit dem 
Entprellen zu kämmpfen) und den Wert dann über UART ausgeben.

von Mustermann (Gast)


Lesenswert?

Kein Sklaventreiber schrieb:
> Wenn Du daher eine Variable wie "isValid" oder "receiverReady" oder eine
> Funktion wie "available()" abfragst, dann ist das gut verständlich und
> lesbar, weil man die Bedeutung und die Aussage sofort versteht.

Da gebe ich dir absolut recht. Schön ist mein bisheriger Code nicht. Ich 
muss nur gerade Prioritäten setzen. Muss mich für einen Job in 
Windeseile komplett von 0 auf 100 in das Thema MC hineinlesen und bin 
heilfroh, wenn das Programm am Ende funktioniert - derzeit hänge ich an 
diesem Thema und dem Entprellen des Encoders. Schönheits-OPs kommen dann 
später...




Ich frage mich halt, was ich im Gegensatz zum Demoprogramm vergessen 
habe. Dort wird auch konkret nur gesagt


SBUF0=Byte;


Die zugehörige ISR wird auch aufgerufen, habe da eine LED getriggert. 
Nur scheint er den Wert nicht ins Transmit Register schreiben zu wollen 
oder daran hängen zu bleiben.

von Mustermann (Gast)


Angehängte Dateien:

Lesenswert?

Hier noch die Interrupt.c

Es geht um die Timer2 ISR und die UART ISR. Sorry für den schlechten 
Stil.

Grüße

von Jim M. (turboj)


Lesenswert?

Kein Sklaventreiber schrieb:
> SCON0_TI ist wenig
> bezeichnend und könnte ja auch außer true (1) oder false (0) vielleicht
> auch mal eine 3 enthalten.

Nö, das ist ein einzelnes Bit - nur 0 und 1 sind möglich.

Wir sind hier auf einem 8051, da gibt es bit-adressierbaren Speicher.

von Lothar (Gast)


Angehängte Dateien:

Lesenswert?

Habe hier keinen EFM8SB1 sondern EFM8BB1 da muss zuerst die Pin-Matrix 
angeschaltet werden:

XBR0 |= (1 << (0));  // cross-bar enable UART0 pins
XBR2 |= (1 << (6));  // cross-bar enable all pins

Dann hatten die Demo-Boards das Problem, dass TX als Open-Drain nicht 
ging, daher:

// P0.4 - UART0 TX - PUSH_PULL
P0MDOUT |= (1 << (4));

Habe mal ein Demo-Programm angehängt.

Dann gab es noch den Bug, dass auf den Demo-Boards der USB-seriell Chip 
nur eine Baudrate verträgt, nämlich 115200

Jim M. schrieb:
> Wir sind hier auf einem 8051, da gibt es bit-adressierbaren Speicher

Gibt es bei vielen ARM auch und ist sehr nützlich :-)

von Mustermann (Gast)


Lesenswert?

Lothar schrieb:
> Habe hier keinen EFM8SB1 sondern EFM8BB1 da muss zuerst die
> Pin-Matrix
> angeschaltet werden:
>
> XBR0 |= (1 << (0));  // cross-bar enable UART0 pins
> XBR2 |= (1 << (6));  // cross-bar enable all pins
>
> Dann hatten die Demo-Boards das Problem, dass TX als Open-Drain nicht
> ging, daher:
>
> // P0.4 - UART0 TX - PUSH_PULL
> P0MDOUT |= (1 << (4));
>

Werde ich versuchen, danke! Melde mich dann hier mit dem Ergebnis.

von Mustermann (Gast)


Lesenswert?

Es hat tatsächlich an dem Push-Pull und dem Crossbar-Register gelegen. 
Jetzt bekomme ich zumindest schon mal ein Signal über den UART. Danke!

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.