Mir geht es so ähnlich, wie im Beitrag "MSP430 UART senden" angefragt wurde. Am Ausgang P3.4 UTXD0 soll zunächst im Abstand eines Timertaktes ein Byte gesendet werden. Leider kommt an P3.4, gemessen mit einem Oszi, nichts an. (nur LED blinkt im Timertakt) Der Ausgang bleibt auf 3V stehen. Kann jemand meinen Fehler erkennen? Vermutlich wird der Sendeprozess nicht angestoßen? Verwendet wird der MSP430F169
:
Bearbeitet durch User
Ist das Port von GPIO auf UART umgestellt? Wer generiert den ersten Tx-Interrupt? => versuche das erste Zeichen in main() auszugeben (oberbalb von for(;;)
:
Bearbeitet durch User
Gerald K. schrieb: > Ist das Port von GPIO auf UART umgestellt? Wie ist das gemeint? Mein gesamtes Programm ist hier: 0167-iar-UART_DS04_V01.c dargestellt
Ich sehe es ist in der Programmzeile 60 durchgeführt. Also kann man den ersten Punkt abhaken. Zum zweiten Punkt: der Interrupt ist freigegben (Code Zeile 68), aber wer löst den Tx Interrupt aus? <<USART Transmit Interrupt Operation The UTXIFGx interrupt flag is set by the transmitter to indicate that UxTXBUF is ready to accept another character. An interrupt request is generated if UTXIEx and GIE are also set. UTXIFGx is automatically reset if the interrupt request is serviced or if a character is written to UxTXBUF. UTXIFGx is set after a PUC or when SWRST = 1. UTXIEx is reset after a PUC or when SWRST = 1. The operation is shown is Figure 13−10.>> Quelle: https://www.ti.com/lit/pdf/slau049 13-29: UTXIFG1 bzw. 2 muss gesetzt werden um eiinen TX Interrupt auszulösen. Normalerweise passiert das mit dem Ende des Stopbits des zuletzt gesendeten Bytes. Wurde nichts gesendet, dann muss dieses Bit gesetzt werden.
:
Bearbeitet durch User
Gerald K. schrieb: > 13-29: UTXIFG1 bzw. 2 muss gesetzt werden um eiinen TX Interrupt > auszulösen. Normalerweise passiert das mit dem Ende des Stopbits des > zuletzt gesendeten Bytes. Wurde nichts gesendet, dann muss dieses Bit > gesetzt werden. Und wie würden die entsprechenden Zeilen und Befehle aussehen. "txwert" ist bei mir das Byte, welches gesendet werden soll. Dieser Wert wird bei jeden Timerdurchlauf gemäß txwert=txwert+1; "berechnet" und soll zunächst mit dem Oszi an P3.4 nachweisbar sein, also gesendet werden. Später sollen mal Messwerte über UART gesendet werden.
Wolle G. schrieb: > Und wie würden die entsprechenden Zeilen und Befehle aussehen. > "txwert" ist bei mir das Byte, welches gesendet werden soll.
1 | int main(void) { |
2 | WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer |
3 | Timer_einstellen(); |
4 | UART_einstellen(); |
5 | P1DIR |= BIT7; //LED grün |
6 | // P2DIR |= BIT0; //LED rot
|
7 | |
8 | |
9 | |
10 | TXBUF1 = txwert; /* erstes Zeichen in main() verschicken (damit wird der Tx-Interrupt angestoßen), nächste Zeichen werden über Interrupt geholt */ |
11 | |
12 | |
13 | |
14 | for(;;); |
15 | }
|
:
Bearbeitet durch User
Danke. Jetzt erscheint das Datenbyte an P3.4 UTXD0 (mit Oszi gemessen) Die Zeile: TXBUF0=txwert; // alt: TXBUF1=txwert; steht jetzt im Timer (nicht in main) und // UART0 TX ISR #pragma vector=UART0TX_VECTOR __interrupt void usart1_tx (void) { } bleibt leer. siehe Anhang Im nächsten Schritt muss jetzt noch der Datenempfang zum Laufen gebracht werden.
Wolle G. schrieb: > steht jetzt im Timer (nicht in main) Ist auch eine Möglichkeit der Realisierung. Aber Achtung, der Ticker darf nicht schneller als die Zeit für das Ausgeben des Bytes sein.
Also Senden ohne Tx Interrupt im Timerinterrupt, dann würde ich den Tx Interrupt sperren auch sperren, dann braucht es keine Tx-Interruptroutine.
:
Bearbeitet durch User
Zwischenzeitlich funktioniert auch das Senden von 8 Bit breiten Zeichen. Es sollen aber auch mehrere verschiedene 16Bit breite Messwerte übertragen werden. (z. B. Temperatur 1, Temperatur 2 usw.) Man könnte vor dem Senden den Messwert in ein oberes und unteres Byte zerlegen und dann diese zwei Bytes senden. Das Zerlegen und Zusammenfügen ist nicht das Problem. Aber wie müssten die Programme aussehen, damit die richtigen Bytes gesendet bzw. richtig empfangen und zusammengesetzt werden können? Im Anhang meine aktuellen Programme.
Wenn man den Tx-Buffer in der Timerroutine befüllt, bedarf es keines Tx-Interrupts. Der Tx-Interrupt (buffer empty) kann man die gesamte Laufzeit auf disabled belassen. IE1 |= UTXIE0 + URXIE0; ==> IE1 |= URXIE0 Wenn nicht, dann wird nach jedem versendeten Zeichen die leere Interruptroutine usart1_tx ( ) aufgerufen. Fällt nicht auf, kostet aber Rechenzeit.
Beitrag #6723556 wurde vom Autor gelöscht.
Beitrag #6723572 wurde vom Autor gelöscht.
@Gerald K. Zwischenzeitlich hatte ich noch ein weiteres Thema zur 16Bit-übertragung aufgemacht. (Beitrag "MSP430—über UART 16Bit Daten übertragen") Den noch nicht richtig funktionierenden Programmentwurf hänge ich hier mal an. Kannst Du meine Fehler entdecken? Zur Erklärung: Mit dem ersten Byte (0xAA) soll dem Empfänger signalisiert werden, dass im Anschluss ein neues „Datentelegramm“ kommt. Danach soll der Interupt abgeschaltet werden, damit nicht laufend weiter gesendet wird. Wenn im Timer wieder der Interupt aktiviert wird, dann wird ein neues Telegramm gesendet. Leider sind am Oszi nur das 1.Byte (0xAA) und das letzte Byte zu sehen, obwohl es 3 Bytes sein sollten. Hoffentlich habe ich mich verständlich ausgedrückt. Es kann sich natürlich hier jeder beteiligen, der helfen möchte.
Wolle G. schrieb: > Hoffentlich habe ich mich verständlich ausgedrückt. Ja. Die Tx-Interruptroutine kann so nicht funktionieren. Was passiert in der Interruptroutine? Es wird das erste Byte 0x50 in den Sendepuffer geschrieben und anschließend sofort dss zweite Byte 0xab nachgeschoben. Der TX-Teil hat keinen Zwischenpuffer und so wird das zweite Byte durch das dritte überschrieben. Der Sendevorgang eines Byte dauert wesentlich länger als zwei aufeinander folgende Schreibvorgänge in den Puffer.
:
Bearbeitet durch User
**Lösung** : Ein Byte nach dem anderen in der Timerinterruptroutine ausgeben. Die zeitlichen Bedingungen habe ich in einem vorangegangenen Beitrag beschrieben. Es ist kein Tx-Interrupt notwendig. Er sollte immer gesperrt (disabled) sein.
:
Bearbeitet durch User
Gerald K. schrieb: > **Lösung** : > > Ein Byte nach dem anderen in der Timerinterruptroutine ausgeben. Die > zeitlichen Bedingungen habe ich in einem vorangegangenen Beitrag > beschrieben. > Es ist kein Tx-Interrupt notwendig. Er sollte immer gesperrt (disabled) > sein. Meine Programmierkünste sind nur schwach ausgebildet. Deshalb suche ich hier Unterstützung. Wie sollten die Programmzeilen konkret aussehen, damit alle Bytes gesendet werden?
Wolle G. schrieb: > Wie sollten die Programmzeilen konkret aussehen, damit alle Bytes > gesendet werden? Die zu versendenden Bytes z.B. in main () in einen Sendpuffer schreiben:
1 | int tx_cnt=0; |
2 | char tx_buffer[]={0xaa,0x50,0xab}; |
oder
1 | char tx_buffer[3]; |
2 | |
3 | int tx_cnt=0; |
4 | tx_buffer [0]=0xaa; |
5 | tx_buffer [1]=0x50; |
6 | tx_buffer [2]=0xab; |
Mit jedem Aufruf der Timer Interruptroutine wird Byte für Byte ausgeben:
1 | if (tx_cnt<3) |
2 | {
|
3 | TXBUF0=tx_buffer[tx_cnt]; |
4 | tx_cnt++; |
5 | }
|
oder kürzer
1 | if (tx_cnt<3) TXBUF0=tx_buffer[tx_cnt++]; |
Bedingung Beitrag "Re: MSP430 über UART Daten senden" beachten!
:
Bearbeitet durch User
Gerald K. schrieb: > Mit jedem Aufruf der Timer Interruptroutine wird Byte für Byte ausgeben: Das habe ich etwas umgestrickt, da der Timertakt für andere Zwecke benötigt wird. Deshalb wurden 2 neue Funktionen geschaffen ( hier „werte_feld_fuellen“ und „wert_senden“) Diese Funktionen werden im Timer aufgerufen. Mit __delay_cycles wird dafür gesorgt, dass sich TXBUF0 nicht überschneidet. Das könnte man vielleicht noch besser lösen. (Abfrage, ob txbuffer[i] leer ist.--> k.A. ) Für den Empfang der gesendeten Daten habe ich allerdings noch kein funktionierendes Programm. Gedacht hatte ich, wie gestern schon geschrieben, an: „Mit dem ersten Byte (0xAA) soll dem Empfänger signalisiert werden, dass im Anschluss ein neues „Datentelegramm“ kommt.“ Wäre dies eine Möglichkeit? bzw. wie würde das programmiertechnisch aussehen.
Der Realisierungsansatz hat zwei große Schwachstellen: 1.) Interruptroutinene sollten niemals Delayroutinen z.B. __delay_cycles enthalten 2.) Interruptroutinene sollten niemals Schleifenkonstrukte enthalten. Schleifen sollten außerhalb des Timerinterrupts geschlossen werden, dass heisst ein Iterationsschritt pro Interruptaufruf. Siehe Beitrag "Re: MSP430 über UART Daten senden" Der Iterationsschritt wird durch tx_cnt gezählt und entspricht dem i im Code https://www.mikrocontroller.net/attachment/520803/0167-iar_V05-UART_DS04_16bit.c.
1 | // Timer A0 interrupt service routine
|
2 | #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A (void)
|
3 | {
|
4 | P1OUT ^= BIT7; |
5 | //LED grün temp_1 = 0x1667;
|
6 | // Messwert 1 Beisoiel werte_feld_fuellen(); wert_senden();
|
7 | |
8 | if ((tx_cnt<3) && (U0TCTL&1)) |
9 | {
|
10 | TXBUF0=tx_buffer[tx_cnt]; |
11 | tx_cnt++; |
12 | }
|
13 | }
|
1.) tx_buffer ist in main() zu befüllen 2.) tx_cnt ist eine gobale Variable und wird am Anfang auf 0 gesetzt. 3.) (U0TCTL&1) ist 1 wenn TXBUF0 leer ist
:
Bearbeitet durch User
Ich habe versuch den Sendevorang zu Impementieren. siehe example.c Wichtig ist, dass Interruptroutinen möglichst schlank sind (kurze Ausführungszeit, wenig Code) Die (zeitunkritische) Verarbeitung sollte sequenziell im Background erfolgen. In den Interruptrountinen sollten keine Zeitverzögerungen und Schleifen eingebaut sein. Grund: wenn im Timerinterupt gewartet wird bis alle drei Bytes versendet sind, dann funktionieren Interrupts mit niedriger Priorität nicht. Den Empfang würde ich wie das Versenden ausführen. RX-Interruptrounine einen genügend großen globalen Puffer rx_buffer[] zur Verfügung stellen. Ein globaler Empfangszähler rx_cnt wird in der Interruptroutine mit jedem empfangenen Byte hochgezählt. Ab einem besimmten Wert des Empfangszähler rx_cnt kann in der Interruptroutine ein Überlauf unterbunden werden. Im Background können Empfangszählerstand und Epmfangspufferinhalt ausgewertet und weiterverwarbeitet werden. Beispiel für Empfanginterrupt für 5 Zeichen:
1 | int rx_cnt; |
2 | char rx_buffer[5]; |
3 | |
4 | // in main() while(1)
|
5 | |
6 | // Empfangsfreigabe zum richtigen Zeitpunk!
|
7 | rx_cnt=0; |
8 | |
9 | // Auswertung Empfang:
|
10 | |
11 | if (rx_cnt=4) // 5 Zeichen empfangen |
12 | {
|
13 | ... = rx_buffer[0]; // verfügen über RX-Pufferinhalte |
14 | }
|
Interruptroutine:
1 | {
|
2 | if (rx_cnt<5) |
3 | {
|
4 | rx_buffer[rx_cnt++]=RXBUF0; |
5 | }
|
6 | }
|
:
Bearbeitet durch User
Aus dem „example.c „ Programm habe ich vorhandene Doppelfunktionen entfernt und danach als: "0167-iar_V07-UART_DS04_16bit.c" eingespielt. Leider läuft der Timer, und damit das Programm, nicht. Aus meiner Sicht fehlt in main() die for(;;); -Schleife, o. ä. Aus meinem ursprünglichen Programm habe ich __delay_cycles() entfernt und die Funktion: wert_senden() umgebaut. "0167-iar_V06_UART_DS04_16bit.c" Mit dem Oszi sind jetzt alle 3 Bytes, wie gewünscht, zu sehen. Mit dem Datenempfang bin ich noch nicht weiter gekommen.
Wolle G. schrieb: > Aus meiner Sicht fehlt in main() die for(;;); -Schleife, o. ä. Ich habe die for(;;) gegen while(1) Schleife ersetzt. Der Background sollte immer durch den Interrupt unterbrochen werden, außer der globale und/oder in diesem Fall der Timerinterrupt ist gesperrt. Fehler ist definitiv in Zeile 72, wo der TX-Interrupt freigegen ist. Dieser sollte gesperrt sein. Daher Zeile auskommentieren. Die Ausgabe in den TX_buf erfolgt nicht in der TX-Interruptroutlne, sondern in der Timerinterruptroutine, daher TX-Interrupt in Zeie 72 nicht freigeben. (Sorry, habe ich bei meinem Beispiel übersehen) Bei die früheren Implementierungen ist die leere TX-Interruptroutine unnötigerweise aufgrufen worden, dies hatte außer Rechenzeitvergeudung keine anderen negative Auswirkung. Dadurch, dass die TX-Interruptroutine auskommentiert ist, greift der TX-Interrupt ins Leere und hängt sich der MC ein.
:
Bearbeitet durch User
Gerald K. schrieb: > Fehler ist definitiv in Zeile 72, wo der TX-Interrupt freigegen ist. > Dieser sollte gesperrt sein. Daher Zeile auskommentieren. Zunächst erst einmal vielen Dank für Deine Mühen. Die Zeile 72 habe ich mal auskommentiert. Jetzt läuft der Timer (erkennbar an der blinkenden LED), aber am Oszi ist nach einem Neustart nur einmal ein Datenbyte (welches ?) zu sehen. Im Anhang meine aktuellen Programme ( senden bzw empfangen). Sie laufen jetzt wunschgemäß. Ob es noch versteckte Ungereimtheiten gibt, ? Da 0xAA (Anfangsmerkmal) auch in einem Datenbyte vorkommen könnte, sollte man, wie ich gelesen habe, die Daten in ASCII umwandeln (Beitrag "Problem: 16 Bit Variable über UART zu empfangen" Mal sehen, ob ich das hinkriege. Falls jemand in meinen Programmentwürfen noch schwer wiegende Mängel erkennt, her damit. Ich werde es dann mal testen.
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.