Hallo zusammen, ich habe eine wie ich finde besondere Herausforderung an meinen µC. Ich habe ein Gerät1, dass alle 20 Sekunden einen String über COM (8N1) ausgibt und welcher dann von meinem µC eingelesen und gespeichert wird. Auf der anderen Seite meines µC steht ebenfalls ein Gerät2, was bei Knopfdruck am Gerät2 einen String an meinen µC schickt. Wenn der String von Gerät2 kommt, so wird dieser eingelesen und darauf hin werden Teile von dem von Gerät1 gespeicherten String gesendet. (Je nach Art des Befehls) Meine Software UART geht über das INT0 Ereignis und nutzt dann einen 8-Bit Timer. Die Hardware-UART habe ich über das ISR(USART_RX_vect) implementiert. Mein Programm funktioniert tadellos. Die Ausnahme ist, wenn beide Geräte gleichzeitig einen String an den µC senden. Habt ihr irgendwelche Tipps wie ich nen optimales Timing machen könnte, damit mein µC gleichzeitig zwei Strings empfangen kann? Merci beaucoup :-) Grüße Marcel
> Habt ihr irgendwelche Tipps wie ich nen optimales Timing machen > könnte, damit mein µC gleichzeitig zwei Strings empfangen kann? Das wait() in Zeile 42 sollte raus... Im Ernst: zeig doch mal deinen Quellcode. Vermutlich brauchst du zuviel Zeit beim Bearbeiten der Interrupts...
>Habt ihr irgendwelche Tipps wie ich nen optimales Timing machen >könnte, damit mein µC gleichzeitig zwei Strings empfangen kann? Ja, das Wort 'gleichzeitig' streichen. Der PC schickt abwechselnd Anfragen an G1 und G2; nur das angefragte Gx darf mit seinem Wert antworten.
Höchst wahrscheinloich hast du Grundregel 1 verletzt: In einem Interrupt wird auf nichts und niemanden gewartet. Auch nicht auf einen Timer.
Karl heinz Buchegger schrieb: > Höchst wahrscheinlich hast du Grundregel 1 verletzt: > In einem Interrupt wird auf nichts und niemanden gewartet. Und vermutlich auch Grundregel 2: Ein Interrupt hat schnellstmöglich abgearbeitet zu sein. Verwaltungsaufgaben und Datenverarbeitung werden woanders gemacht.
Wow vielen Dank für die supi schnellen Antworten :-). Das stimmt, das hatte ich noch gar nicht bedacht, dass wenn man sich in einem Interrupt befindet, der µC wartet bis dieses beendet wurde und dann ins nächste springt. Das Problem ist, dass die beiden Geräte nicht auf die Befehle meines µC hören, sondern Gerät1 spricht dauerhaft alle 20 Sekunden und Gerät2 bringt den Befehl raus (vielleicht 1x in der Stunde) und wartet 1,5 Sekunden lang auf eine Antwort. Ich hab mir noch was anderes überlegt. Wenn ich Gerät2 an meine Soft-UART lege und wenn dann beim Empfang von Zeichen von Gerät2 (sprich fallenede Flanke an INT0) sofort die Hardware-UART deaktiviert wird und ich Gerät2 dann einfach die Werte gebe, die noch vor 20 Sekunden aktuell waren. So kommt wennigstens kein Müll heraus. Das setzt aber auch vorraus, dass ich die von Gerät1 empfangenen Strings immer 2x im µC deponiere. Der erste Zeichen-Array wird von Gerät1 immer wieder fleißig überschrieben und wenn dann gerade zum Empfangszeitpunkt von Gerät1 eben Gerät2 seinen Befehl schickt, wird die Zeichenaufnahme von Gerät1 gestoppt (dann ist ja der String von Gerät1 nicht vollstädig übertragen worden.). Dann habe ich ja noch den "alten" String den ich dann schicke. Das kopieren der Strings kann ich ja zu einem unkritischen Zeitpunkt machen. Damit mir da auch nichts wieder bei flöten geht, deaktiveire ich zu diesem Zeitpunkt die Hardware-UART und wenn dann gerade von Gerät2 nen String kommt (Soft-UART), dann wird der erst in nen FIFO geschoben und anschließend verarbeitet. Somit müssten alle zeitkritischen Punkte abgefedert sein und seht ihr noch einen? Das wäre doch ne Möglichkeit. - oder habt ihr ne bessere? Danke Marcel
Die Hardware-UART hat mindestens 2 Bytes Zeit, die Soft-UART ist viel viel zeitkritischer. Wenn der Handler der Hardware-UART länger als ein paar Befehle ist, dann dort sofort den UART-Interrupt abschalten und die Interrupts wieder freigeben. Dann kommt der kritischere Soft-Int wieder durch (aber jeder andere auch, Vorsicht Stack-Grösse). Annahme dabei: Soft-UART via externem Interrupt für das Rx-Startbit und via Timer-Interrupt für den Rest.
Genau so hab ich auch meine Soft-UART programmiert. ;-) Von der Interruptlänge - sind die zu lange?: PS: Indem UART Receive Interrupt wird eine Funktion aufgerufen, die wartet, bis das Register ausgelsen werden kann (--- while ( !(UCSR0A & (1<<RXC0)) )----) Danke im Vorraus Marcel FALLENDE FLANKE AN INT0: ISR(INT0_vect) { sparkline_sending++; //Disable Hardware Uart if nothing received at the moment if(meter_sending==0) { //Disable Hardware UART UCSR0B &= ~(1<<RXEN0); } state = RECEIVE; // Change state DISABLE_EXTERNAL0_INTERRUPT( ); // Disable interrupt during the data bits. DISABLE_TIMER_INTERRUPT( ); // Disable timer to change its registers. TCCR_P &= ~( 1 << CS01 ); // Reset prescaler counter. TCCR_P &= ~( 1 << CS00 ); TCNT0 = INTERRUPT_EXEC_CYCL; // Clear counter register. Include time to run interrupt rutine. TCCR_P |= ( 1 << CS01 ); // Start prescaler clock. TCCR_P |= ( 1 << CS00 ); OCR = TICKS2WAITONE_HALF; // Count one and a half period into the future. SwUartRXBitCount = 0; // Clear received bit counter. CLEAR_TIMER_INTERRUPT( ); // Clear interrupt bits ENABLE_TIMER_INTERRUPT( ); // Enable timer0 interrupt on again } ISR(INT0_vect) { sparkline_sending++; //Disable Hardware Uart if nothing received at the moment if(meter_sending==0) { //Disable Hardware UART UCSR0B &= ~(1<<RXEN0); } state = RECEIVE; // Change state DISABLE_EXTERNAL0_INTERRUPT( ); // Disable interrupt during the data bits. DISABLE_TIMER_INTERRUPT( ); // Disable timer to change its registers. TCCR_P &= ~( 1 << CS01 ); // Reset prescaler counter. TCCR_P &= ~( 1 << CS00 ); TCNT0 = INTERRUPT_EXEC_CYCL; // Clear counter register. Include time to run interrupt rutine. TCCR_P |= ( 1 << CS01 ); // Start prescaler clock. TCCR_P |= ( 1 << CS00 ); OCR = TICKS2WAITONE_HALF; // Count one and a half period into the future. SwUartRXBitCount = 0; // Clear received bit counter. CLEAR_TIMER_INTERRUPT( ); // Clear interrupt bits ENABLE_TIMER_INTERRUPT( ); // Enable timer0 interrupt on again } TIMER INTERRUPT ISR(TIMER0_COMPA_vect) { switch (state) { // Transmit Byte. case TRANSMIT: // Output the TX buffer. if( SwUartTXBitCount < 8 ) { if( SwUartTXData & 0x01 ) { // If the LSB of the TX buffer is 1: SET_TX_PIN(); // Send a logic 1 on the TX_PIN. } else { // Otherwise: CLEAR_TX_PIN(); // Send a logic 0 on the TX_PIN. } SwUartTXData = SwUartTXData >> 1; // Bitshift the TX buffer and SwUartTXBitCount++; // increment TX bit counter. } //Send stop bit. else { SET_TX_PIN(); // Output a logic 1. state = TRANSMIT_STOP_BIT; } break; // Go to idle after stop bit was sent. case TRANSMIT_STOP_BIT: DISABLE_TIMER_INTERRUPT( ); // Stop the timer interrupts. state = IDLE; // Go back to idle. ENABLE_EXTERNAL0_INTERRUPT( ); // Enable reception again. break; //Receive Byte. case RECEIVE: OCR = TICKS2WAITONE; // Count one period after the falling edge is trigged. //Receiving, LSB first. if( SwUartRXBitCount < 8 ) { SwUartRX ENABLE_EXTERNAL0_INTERRUPT( ); // Enable interrupt to receive more bytes. } break; // Unknown state. default: state = IDLE; // Error, should not occur. Going to a safe state. } } HARDWARE-UART RECEIVE ISR(USART_RX_vect) { //Es werden Zeichen auf der Hardware UART empfangen meter_buffer[counter_meter]=USART_Recieve(); counter_meter++; }
> PS: Indem UART Receive Interrupt wird eine Funktion aufgerufen, die > wartet, bis das Register ausgelsen werden kann (--- while ( !(UCSR0A & > (1<<RXC0)) )----) Der Interrupt wird ja aber genau dann ausgelöst, wenn ein Zeichen empfangen wurde (das Register kann also auf jeden Fall sofort ausgelesen werden). Und RXC wird beim Eintritt in die ISR automatisch gelöscht, das heißt, deine Schleife wartet dann also, bis noch ein Zeichen empfangen wurde.
Die Hard-UART abzuschalten heisst, dass du schon verdammt sicher sein solltest, dass in der fraglichen Zeit nix kommt. Wobei du sie dann auch nicht abschalten musst ;-). Denn wenn grad was reinkommt während du wieder einschaltest, dann gibt es Schrott. Wenn schon, dann den Int abschalten, nicht die ganze Unit. Gibt hier aber keinen Grund, im Ext-Int überhaupt was von der UART abzuschalten. Den Timer-Int in der ISR anfangs abzuschalten bringt nix, weil in einer ISR sowieso alle Interrupts unbearbeitet liegen bleiben. Cut-and-Paste-Fehler im Timer-Int? Ein echter Funktionsaufruf in kleiner ISR ist vergleichsweise teuer, weil der Compiler dann nicht nur diejenigen Regs sichert, die er selber wirklich verwendet, sondern auch alle von der Funktion prinziell verwendbaren Regs.
Ne in der Timer INT hab ich keine Copy Paste Fehler drinn - was ist dir denn an der Routine aufgefallen? LG Marcel
zb, dass du die Hardware UART dort drinnen abschaltest
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.