LIN Bus
Der LIN Bus wird hauptsächlich in der Automobilindustrie zum ansteuern einfacherer Sensoren und Aktoren verwendet. Die Busspannung beträgt 12V und funktioniert nach dem Master/Slave Prinzip. Das Master-Steuergerät sendet eine Anfrage oder eine Anweisung und die Slaves reagieren darauf. Eine LIN-Botschaft (=Frame) besteht aus dem Frame Header der immer vom Master gesendet wird und einem Response Frame der im Falle eines Sensors vom Slave gesendet wird oder bei einem Aktor als zusätzliche Anweisung vom Master.
Da die Slaves nicht von sich aus senden dürfen genügt für den ganzen Datenverkehr nur eine Busleitung. Für das Senden und Empfangen der LIN Bus Daten kann die serielle Schnittstelle (UART) des Mikrocontrollers verwendet werden. Die Übertragung der einzelnen Bytes ist gleich. Start Bit, 8 Datenbits mit dem LSB als erstes und einem abschließenden Stop Bit.
Zwischen der UART Schnittstelle des µC un der LIN Busleitung muss noch ein Transceiver für die Pegelwandlung in beiden Richtungen angeschlossen werden (5V UART < > 12V LIN).
Anschluss am Arduino
Der Arduino UNO hat nur eine Hardware UART Schnittstelle. Da diese Schnittstelle für die Kommunikation mit dem PC benötigt wird verwendet man am einfachsten einen Arduino MEGA. Der Mega hat in Summe 4 seriellen Schnittstellen, so dass eine weitere für die Kommunikation dem Transceiver zur Verfügung steht.
Die Arduino Befehle zum Ansteuern der seriellen µC Schnittstelle sind im entsprechenden Artikel beschrieben und können hier nochmal nachgelesen werden.
LIN Protokoll
Im oberen Bild ist eine komplette LIN Botschaft (= LIN Frame) mit Header und Response abgebildet. Der Idle Zustand des Busses ist +12V. Bis auf den Break zum Einleiten einer Übertragung werden die ganzen Botschaften byteweise übertragen. Jeweils mit einem beginnenden Startbit und einem abschließenden Stopbit. Zwischen den Bytes kann es eine Pause geben (Inter-Byte-Space).
HEADER Frame vom Master gesendet
Header Break
Der Datenbus wird zunächst vom Master für eine Länge von mindestens 13 bit auf Low (GND) gezogen. Die Slaves erwachen dadurch von ihrem Sleep Zustand.
Header Synchronisierung
Durch die abwechselnde Folgen von 1 und 0 können sich die Slaves synchronisieren und die nachfolgende
Übertragungsrate erkennen. Dazu wird ein Byte B01010101 (HEX 55) gesendet. Wie immer mit dem LSB als erstes.
Die typische Übertragungsrate ist 19200 oder 9600 Baud pro Sekunde (52µs bzw. 104 µs Bitlänge).
Protected ID (PID)
Jeder Slave hat eine einzigartige Adresse (=FrameID) mit der man diesen ansprechen kann. Die Frame ID hat eine Länge von 6 bit. Kann also 26 = 64 verschiedene Adressen darstellen. Stelle D6 und D7 des Bytes sind berechnete Parity Bits und dienen der Übertragungssicherheit.
RESPONSE Frame (vom Slave oder vom Master gesendet)
Es werden maximal 8 Byte Nutzdaten gesendet. An die Nutzdaten wird immer noch ein Checksummenbyte angehängt. Im Beispiel sind es 5 Byte Nutzdaten (Data 0 - Data 4) und 'Data 5' ist die Checksumme.
Checksumme
Unterschieden wird die Berechnungsmethode CLASSIC bei Lin 1.x und die ENHANCED Variante ab Lin 2.x. Bei der Enhanced Variante wird das vom Master übertragen PID Byte mit in die Berechnung einbezogen.
Die Nutzdatenbytes (und ggf. das PID Byte bei Enhanced) werden nacheinander addiert. Läuft dabei ein Byte über, wird also größer als 255 (=Overflow) wird das neunte Bit abgeschnitten und das verbleibende Ergebnisbyte um +1 erhöht.
Nach der kompletten Berechnung muß das Ergebnis noch invertiert werden um die Checksumme zu erhalten.
Beispiel Funktion checksumme() in C++
byte checksumme(bool variante) {
/* Mit dieser Methode wird die Checksumme berechnet. Entweder nach der ENHANCED Methode für LIN 2.x
mit Berücksichtigung der vom Master gesendeten Anfrage (der PID) oder nach der CLASSIC Methode
für LIN 1.x bzw. für die DIAGNOSTIC FRAMES.
*/
int CS = 0;
if (variante == ENHANCED) {
for (int i = 1; i <= anzahlEmpfangeneByte ; i++) {
CS = CS + empfangenesByte[i];
if (CS > 255) CS = CS - 256 + 1;
}
}
else {
for (int i = 2; i <= anzahlEmpfangeneByte ; i++) {
CS = CS + empfangenesByte[i];
if (CS > 255) CS = CS - 256 + 1;
}
}
byte cs = ~ CS;
return cs;
}