Hallo, ich möchte gerne bei meiner Anwendung die Möglichkeit haben die UART Schnittstelle zu wechseln, beispielsweise, wenn ich auf der einen Schnittstelle keine Daten mehr empfange soll auf die andere Schnittstelle umgeschaltet werden. Diese Schnittstelle soll als Rückfallebene dienen. Ich weiss nur nicht, wie ich das anstellen soll. Hat da jemand einen Tipp für mich? Ich muss dann ja einen anderen IRQ Handler verwenden... Gruß paule
Ganz versteh ich dein Problem nicht. Wieso überwachst du nicht einfach alle UART's. Die Interrupt-routine kann für alle Uart's grundsätzlich gleich sein, nur arbeiten sie mit seperaten Buffern für RX/TX. Grüsse
Formulier Dein Problem am Besten nochmal von vorn;-) Was soll umgeschaltet werden? Die Pins, die USART selber, die Buffer...
Hallo ich habe so etwas mit Funktionspointer gelöst: (Hier die Schnellvariante, ich hab das ein wenig komponentenorientierter programmiert.) void (*ptr_ISR_Funktion_UART0) (uint_8) = 0U; void (*ptr_ISR_Funktion_UART1) (uint_8) = 0U; /*Hat den VOrteil, dass es der bearbeitenden Funktion gleichgültig ist, von woher sie aufgerufen wird. Interruptpriorisierung ist ev. dringend angeraten. Aber das sollte auf dem STM32 kein Problem sein. */ /*####################################################*/ /* erste Interrupt Service Routine bspw. UART 0*/ ISR ( UART0) { (*ptr_ISR_Funktion_UART0) (USART_DATENREGISTER) } /*####################################################*/ /* zweite Interrupt Service Routine bspw. UART 1*/ ISR (UART2) { (*ptr_ISR_Funktion_UART1) (USART_DATENREGISTER) } /*####################################################*/ /* Wo anders im Code oder im Projekt die Bearbeitungsroutine*/ void MachWasDamit(uint_8 recvd_char) { ... (Deine Aufgaben.) } /*####################################################*/ void Initialisiere (void) // ganz wichtig zu Beginn aufrufen, sonst geht nicht. { ptr_ISR_Funktion_UART0 = MacheWasDamit; ptr_ISP_Funktion_UART1 = MacheWasDamit; } /*####################################################*/ Viel Erfolg.
Hallo, ich möchte die Hardware UART umschalten von USART1 auf USART3. Wo ich da genau ansetze ist ja meine Frage, setze ich da an den PINs an und ändere die auf die entsprechende Schnittstelle, oder ändere ich die Sache im IRQ Handler, den ich geschrieben habe. Buffer halte ich für zu kompliziert, da ich dazu softwaremäßig einiges ändern müsste. Buffer sind rxBuffer und txBuffer.
1 | void USART3_IRQHandler(void) |
2 | {
|
3 | uint16_t sr = USART3->SR; |
4 | portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; |
5 | portBASE_TYPE xTaskWokenByReceive = pdFALSE; |
6 | |
7 | // Check for received Data
|
8 | if (sr & USART_SR_RXNE) |
9 | {
|
10 | if (rxReadPtr < rxWritePtr) |
11 | {
|
12 | uint16_t byte = (uint16_t) USART3->DR; |
13 | if(byte & 0x100) |
14 | rxReadPtr = 0; |
15 | rxBuffer[rxReadPtr++]=byte; |
16 | if(rxReadPtr == 6) |
17 | {
|
18 | rxWritePtr =(((6 + byte) + 3) & ~0x03); |
19 | rxWritePtr=rxWritePtr+4; |
20 | }
|
21 | if(rxReadPtr>6 && rxReadPtr==rxWritePtr) |
22 | {
|
23 | length=rxWritePtr; |
24 | rxWritePtr=7; |
25 | rxReadPtr=0; |
26 | xQueueSendFromISR (hSerialRx, &length, &xHigherPriorityTaskWoken); |
27 | }
|
28 | }
|
29 | }
|
30 | |
31 | // Check if transmit buffer is empty
|
32 | if (sr & USART_SR_TXE) |
33 | {
|
34 | if(txReadPtr < txWritePtr) |
35 | {
|
36 | uint16_t byte = txReadPtr==0 ? 0x100 : 0; |
37 | byte |= txBuffer[txReadPtr++]; |
38 | USART3->DR = byte; |
39 | }
|
40 | else
|
41 | // disable TXE interrupt
|
42 | USART3->CR1 &= ~USART_CR1_TXEIE; |
43 | }
|
44 | }
|
Ich würde bei meinem IRC Handler die Variable sr anpassen und dann mit einer if schleife abfragen, ob sr = USART3->SR oder USART1->SR ist und dann entsprechend zum Beispiel: USART3->DR = byte oder USART1->DR=byte setzen. Ich hoffe man konnte mich jetzt ein bisschen besser verstehen und das ganze nachvollziehen.
Naja, wenn es um den Empfang geht, hat ja jede UART ihre jeweils eigenen zugehörigen Interrupt-Service-Routinen. Also, in der ISR von UART3 würde ich nicht auf das Datenregister der UART1 zugreifen. Es sei denn, dass es da hinweisende FLags gibt. Aber mit der Funktionspointerlösung bist Du, wie ich glaube, gut bedinent. Du brauchst Dir keinen Kopf darüber machen, wann von woher etwas rein kommt. Auch solche Sachen wie TimeOut auf bestimmten Kanälen überwachen, kannst Du getrost auf die Kombination ISR- / Pointerfunktion verlagern. Wenn Du eine gegenseitige Verriegelung einbauen willst, dann wird es bei einer 3. UART, die so behandelt werden soll, langsam unübersichtlich. Bei den Funktionspointer läuft alles automatisch. Ggf. kannst Du ja vor dem Funktionspointeraufruf noch den Empfang des anderen Interrupt sperren. Viel Erfolg.
Hallo, dann hätte ich demnach in den 2 Interruptroutinen ja dasselbe stehen wie die Daten die ankommen oder gesendet werden behandelt werden,oder? Dann noch eine Frage zum Funktionspointer: Was bedeutet OU bei: void (*ptr_ISR_Funktion_UART0) (uint_8) = 0U; und, diese Schritte verstehe ich noch nicht: /*####################################################*/ /* Wo anders im Code oder im Projekt die Bearbeitungsroutine*/ void MachWasDamit(uint_8 recvd_char) { ... (Deine Aufgaben.) } /*####################################################*/ void Initialisiere (void) // ganz wichtig zu Beginn aufrufen, sonst geht nicht. { ptr_ISR_Funktion_UART0 = MacheWasDamit; ptr_ISP_Funktion_UART1 = MacheWasDamit; } /*####################################################*/ Was meinst du bei der Initialisierung mit MachWasDamit? Weil im Prinzip empfangene ich in der ISR die Bytes und schreib sie direkt in einen Buffer. Beim Senden genauso, da wird aus einem Buffer gelesen. Ich hatte meine ISR ja mal angehängt. Steht bei deiner Variante nur das in der ISR?: ISR (UART2) { (*ptr_ISR_Funktion_UART1) (USART_DATENREGISTER) } Versteh das noch nicht soo ganz, was du da machst. Gruß
Hi paule, 1.) das hier ist eine Initialisierung einer globalen Variablen, die auf eine Funktion im CODE zeigt, mit NULL. void (*ptr_ISR_Funktion_UART0) (uint_8) = 0U; Eigentlich brauchst Du das nicht. Aber wenn Du - warum auch immer - während des Betriebs so etwas wie einen warmstart durchführst, ist das definierte Rücksetzen Pflicht. - Das kannst Du halten , wie es Dir beliebt. Ich muß nach Prozess arbeiten und da ist das Pflicht. 2.) Den Code in // check for received data ... würde ich aus der ISR herausnehmen und in eine separate Funktion schreiben. Der Trick ist die Schnittstelle. Also der Parameter mit dem die Daten vom Aufrufer an den Bearbeiter gegeben werden. Und genau das Schreiben der Daten in den Puffer würde ich in einer Funktion durchführen, die als Parameter entweder das empfangene Byte oder einen Datenpointer auf ein Array erhält, in dem ggf. die FiFo-daten drin sind. (Ich weiß jetzt nicht, ob der STM32 einen FIFO hat oder nicht ...) Jetzt kann nämlich Deine ISR von UART3 nur das empfangene Byte in den Parameter des Funktionsaufrufes eintragen und in der MachWasDamit-Routine springen. Die Funktionspointer habe ich Dir deshalb empfohlen, weil Du dann nur die Prototypen konsistent halten mußt und Dir das Verriegeln ersparen kannst. Du kann auch gern konventionell die Funktion MachWasDraus oder in Deinem Fall SchreibeByteInPuffer aufrufen. Wenn Du jetzt aber nicht willst, dass die UART1 dazwischen funkt, sperrst Du entweder den Interrupt oder Weißt dem Funktionspointer eine Adresse einer Funktion mit den selben Prototypen zu, die nach Aufruf sofort wieder zurückspringt (So was wie ein reti in Assembler). Man nennt so etwas späte Bindung. Das heißt ich kann während der Laufzeit durch Pointermanipulation den Ablauf der Programms ändern. Dadurch läßt sich der von Dir erbetene geringere Aufwand - bestehenden Code zu ändern - gering halten. 3.) Die Initialisierungsfunktion gehört nicht zu MachWasDraus. /*####################################################*/ void Initialisiere (void) // ganz wichtig zu Beginn aufrufen, sonst geht nicht. { ptr_ISR_Funktion_UART0 = MacheWasDamit; ptr_ISR_Funktion_UART1 = MacheWasDamit; (hier war was falsch) } Diese Funktion muß vor dem Betrieb (In der Regel vor dem while(1) -Konstrukt) durchgeführt werden. Weil jetzt die Funktionspointer auf die Adresse von der Funktion MacheWasDamit zugewiesen werden. Kommt jetzt ein Interrupt auf UART3, dann zwingt die oben angegeben Syntax den MCU dazu, die Funktion MacheWasDamit(mit den Parametern) aufzurufen. In Assembler wäre das der CALL ... Und genauso würde sich jetzt die Empfangsroutine von UART1 verhalten. Soll UART1 aber nicht MacheWasDamit aufrufen können, dann kannst Du das durch eine einfache Zuweisung verhindern. Diese Funktionspointer-Technik ist eine sehr flexibele Vorgehensweise und hält den Aufwand gering. Probier es aus. das funktioniert sogar auf den AVRs...
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.