Gast
#6170466
Hallo liebe Mikrocontroller-Gemeinde, ich habe in den letzten Tagen versucht ein LIN-Bus Protokoll mit zwei Arduino Boards, über deren USART0 Schnittstelle, zu realisieren. Dabei stoße ich jedoch auf ein Hindernis, welches ich einfach nicht überwinden kann. Der Master überträgt seinen Frame (kontrolliert via Oszi), im Slave verwende ich nun zwei Interrupts. Der erste (INT0) erkennt den Syncbreak (13 LOW Bits) und schaltet daraufhin den Slave in Empfangsmodus. Der zweite (USART_RX) soll nun immer ausgelöst werden, wenn neue Daten im Puffer verfügbar sind. Der INT0 Interrupt wird auch tadellos ausgeführt (Kontrolle via LED) und erkennt den Syncbreak. Der USART_RX wird hingegen gar nicht getriggert. Globale Interrupts sind aktiviert, Masse ist verbunden und beide USART sind gleich konfiguriert. Mit den Arduino eigenen Funktionen klappt alles wie gewünscht. Genutzt wird AVR Atmel ATmega 328P Programmiert wird in der Arduino IDE, loop() entspricht der main(). setup() wird bei Programmstart automatisch ausgeführt. Erläuterung des Codes: Der Slave wartet auf den INT0 Interrupt um den Syncbreak zu erkennen. Ist der Syncbreak erkannt, wird der USART Empfänger aktiviert. (Zwischen Ende des Syncbreak und Eingang von Daten über dem USART vergehen 4 Bit bei 19.2k Baud. Der Empfänger soll nun Antworten wenn seine PID empfangen wird. Nach der Antwort geht der Slave wieder in Ausgangsposition zurück. Vielleicht hat jemand von euch eine Idee, was hier falsch laufen könnte. Vielen Dank im Voraus! Hier der Code des Slaves: #include <avr/io.h> // Inkludiere IO Ports #include <avr/interrupt.h> // Inkludiere Interrupt Adressen unsigned char PID = 0x92; // Enthält die geschütze ID des LIN Slave unsigned char sync = 0x55; // Enthält die Form des Syncfield unsigned char RESP = 0xFF; // Antwort des Slave volatile bool Lowedge = false; // Gibt an, ob eine Low Edge erkannt wurde volatile unsigned char data[2]; // Enthält empfangende Daten volatile int i = 0; // Index für Datenpuffer volatile bool newdata = false; // Gibt an, ob neue Daten empfangen wurden // Erkennung Syncbreak ISR(INT0_vect) // Interrupt wenn Pegelwechsel auf INT0 = RX { EICRA ^= B00000001; // Wechsel von Low auf High, bzw. High auf Low Edge Trigger if(Lowedge == false) { TCNT1 = 0; // Timer1 mit Startwert = 0 TCCR1B = B00000011; // Starte Timer1 64 Prescaler Lowedge = true; // Low Edge erkannt } else { if(TCNT1 >= 84) // Syncbreak mindestens 13 Bit { UART_config_RX(); // syncBreak erkannt -> Receiver an } TCCR1B = B00000000; // Stoppe Timer1 Lowedge = false; // Low Edge Flag reset EIMSK = B00000000; // Disable INT0 } } // Erkennung neuer Datenpakete ISR(USART_RX_vect) // Interrupt wenn im RX Buffer des USART Daten verfügbar sind { data[i++] = UDR0; // Lade die neuen Daten in das Datenarray newdata = true; // Teile mit, dass neue Daten verfügbar sind } void setup() { SREG |= B10000000; // Enable Global Interrupts EICRA = B00000010; // Falling Edge Trigger EIMSK = B00000001; // Enable INT0 TCCR1B = B00000000; // Timer1 gestoppt } void UART_config_RX() { // UART-Empfänger konfigurieren UBRR0L = 51; // 19200 Baud //Init UART UCSR0B = B11010000; // 8-Bit Data, RX + TX aktiv, TX deaktiviert, RX Interrupt aktiviert UCSR0C = B00000110; // 8-Bit Data, Keine Parity, Rising Clock } void UART_config_TX() { // UART-Sender konfigurieren UBRR0L = 51; // 19200 Baud // Init UART UCSR0B = B11001000; // 8-Bit Data, TX + RX aktiv, RX deaktiviert, TX Interrupt aktiviert UCSR0C = B00000110; // 8-Bit Data, Keine Parity, Rising Clock } void UART_ausschalten() { // Deaktiviere USART UCSR0B = B00000000; UCSR0C = B00000000; } void LIN_receive() { if((data[0] == sync) && (data[1] == PID)) { UART_ausschalten(); LIN_sendResponse(); // Sende Antwort an Master EIMSK = B00000001; // Enable INT0 - Ermöglicht erneutes empfangen eines Syncbreak data[0] = 0; data[1] = 0; } else { UART_ausschalten(); EIMSK = B00000001; // Enable INT0 - Ermöglicht erneutes empfangen eines Syncbreak data[0] = 0; // Reset data Array data[1] = 0; } } void LIN_sendResponse() { UART_config_TX(); while(!(UCSR0A & (1 << UDRE0))); // Warte bis Transmitbuffer leer ist UDR0 = RESP; // Sende Antwort = 0xFF } void loop() { if(newdata == true) // Warte auf Empfangene Daten { if((data[0] != 0) && (data[1] != 0)) // Wenn zweites Byte empfangen { LIN_receive(); // Starte Datenverarbeitung } newdata = false; // Setze NewData-Flag zurück } }