CAN-Kommunikation mit Arduino
Einleitung / Aufgabenstellung
In diesem Beitrag wird erläutert, wie mit einem Arduino Daten per CAN-Protokoll übertragen werden können. Dazu wird ein CAN-Shield der Firma Sparkfun eingesetzt. Alle verwendeten Programme bzw. Libraries werden an entsprechender Stelle hochgeladen. Zur Überprüfung der Kommunikation wird ein "CAN-Case" der Firma Vector eingesetzt.
Ziel dieses, im Rahmen des SDE-Praktikums "Systemintegration", ist es einen Arduino in Simulink so zu programmieren, dass mit diesem Sensoren ausgelesen, sowie Aktuatoren angesteuert werden können, wobei alle Informationen über CAN gesendet bzw. empfangen werden sollen. Die dabei gewonnenen Erkenntnisse sollen die Grundlage für ein Carolo-Cup Fahrzeug sein, welches komplett auf Mikrocontrollerbasis aufgebaut wird.
Inbetriebnahme der Hardware
Um die Funktion der zur verfügung gestellten Hardware zu testen, wird ein kleines CAN-Netzwerk mit zwei Teilnehmern aufgebaut. Ein Teilnehmer ist dabei der Arduino mit einem CAN-Shield der Firma Sparkfun. Der andere Teilnehmer ist ein CAN-Case der Firma Vector. Es soll gewährleistet werden, dass beide Teilnehmer senden und empfangen können. Um dies zu wird ein kleines Programm erstellt, welches eine CAN-Botschaft empfängt und zurückschickt. Das Programm bedient sich dieser Library, welcher auf der Sparkfun Seite von diversen Nutzern hochgeladen wurde. Die Library lässt durch einfaches Kopieren in den Arduino Unterordner "Libraries" (z.B. ...\arduino-1.0.3\libraries) einbinden. Die Software wird in einem späteren Kapitel erläutert.
Erste Versuche mit gegebener Hard- und Software blieben erfolglos, nach diversen Tests stellte sich heraus das die Verbindung über das vorgekrimpte Kabel nicht funktioniert. Der Grund dafür ist, dass das Pinning des Sub-D Stecker nicht der üblichen Vector-Norm entspricht. Sollen vorgefertigte Kabel verwendet werden, ist ein Adapter Notwendig. Üblicherweise liegt der CAN-High (im folgenden als CAN-H bezeichnet) an Pin 7 des Sub-D Steckers und CAN-Low (im folgenden als CAN-L bezeichnet) an Pin 2. Auf dem Sparkfun Shield liegt CAN-H auf Pin 3 und CAN-L auf Pin 1. Die folgende Tabelle zeigt die Zuordnung des Adapters:
Bezeichnung | Vector-Pinning | Sparkfun-Pinning |
---|---|---|
CAN-H | Pin 7 | Pin 3 |
CAN-L | Pin 2 | Pin 1 |
Alternativ stellt das Arduino-Shield an anderer Stelle CAN-H und CAN-L zur verfügung, über diese Kontakte kann mit zwei einadrigen Leitungen einer direkte Verbindung zu dem CAN-Case hergestellt werden.
Ein einfaches Aufstecken des CAN-Shieldes nur bei dem Arduino UNO möglich ist. Wird ein Arduino Mega 2560 vewendet, müssen die Pins des Shieldes mit Leitungen zu bestimmten Pins des Arduino Megas geleitet werden. Der Grund dafür ist, dass Arduino und Shield über eine sogenannte SPI Schnittstelle Kommunizieren. SPI bedeutet "Serial Peripheral Interface" und ist ein serieller Datenbus mit einer Master und Slave Architektur. Die Pins die die Schnittstelle zum SPI zur verfügung stellen liegen beim Arduino Mega 2560 anders als beim UNO. Die Pin-Zuordnung dieser Pins zeigt folgende Tabelle:
CAN-Shield | Arduino-Mega | Arduino-UNO |
---|---|---|
VIN | VIN | VIN |
GND | GND | GND |
GND | GND | GND |
+5V | +5V | +5V |
+3,3V | +3,3V | +3,3V |
RST | RST | RST |
D10 | D50 | D10 |
D11 | D51 | D11 |
D12 | D52 | D12 |
D13 | D53 | D13 |
alle anderen Pins sind zum Betrieb des Shields nicht notwendig.
Bei dem elektronischen Aufbau dieses Versuches ist zu beachten das die Enden der CAN-Leitungen mit einem 120 Ohm Widerstand zwischen CAN-H und CAN-L abgeschlossen werden müssen. Wird dies nicht gemacht kommt es zu Reflektionen der Signale an den Leitungenden wodurch im schlimmsten Fall ein Kommunizieren auf der Leitung unmöglich wird. Das folgende Bild zeigt Schematisch den Aufbau:
Einlesen von Sensoren
Zum einlesen von analogen Werten, ist der Arduino mit Analog/Digitalwandlern ausgestattet. Als Referenz zum messen dient dabei die von dem Arduino zur Verfügung gestellte 5V Spannungsversorgung. Die Wandler können Werte von 0-1023 vom Typ integer zurückgeben. Damit ergibt sich eine Auflösung von 5V/1023=0,0049V=4,9mV pro Schritt. Im Programm können die analogen Eingänge mit dem Befehl "analogRead()" angesprochen werden. Die folgende mit dem Tool "Fritzing" erstellte und zeigt einen Versuchsaufbau zur Simulation eines Sensors. Dabei dient das Potentiometer als Sensor. Die LED wird zu Anzeigezwecken verbaut. An späterer Stelle soll diese durch einen DC-Motor ersetzt werden.
Ansteuerung von Aktuatoren
Konfiguration des CAN-Case
Um mit dem CAN-Case zu kommunizieren wird hier die Software "CANalayzer" eingesetzt. Als ersten Schritt muss der Messaufbau in der Software eingestellt werden. Dieser kann unter dem Reiter "Configuarion" am unteren Teil des Fensters von CANalayzer gefunden werden. Hier wir zunächst die der CAN-Kanal und die Baudrate eingesetllt. Die Einstellmöglichkeiten können durch einen Doppelklick auf das Kartensymbol oder unter Konfiguration/Netzwerk-Hardware-Konfiguration erreicht werden. Sind diese Einstellungen getroffen, kann der CAN-Bus mitgeloggt werden. Alle Botschaften auf dem CAN-Bus können unter dem Reiter "Trace" im unteren Bereich des Fensters angeschaut werden.
Soll das CAN-Case ebenfalls Botschaften senden, müssen in dem Messaufbau Generatorblöcke eingefügt werden. Diese können zyklisch oder auf Knopfdruck Botschaften senden. Alternativ können diese blöcke mit der C- Ähnlichen Programmiersprache "CAPL" programmiert werden. Dies ermöglicht z.B. das reagieren auf bestimmte Botschaften.
Umsetzung der Aufgabe in C
Wie zuvor beschrieben dient als Grundlage die Bibliothek "mcp2515.h". Diese bietet für den auf dem Shield eingesetzten Microcontroller zugeschnittene Funktionen. Dafür müssen die entsprechenden Dateien wie oben beschrieben in den Arduino Ordner kopiert werden. Im Quelltext kann die Datei dann mit #include <mcp2515.h> eingebunden werden.
In der Library wird eine Struktur mit dem Namen "tCAN" zum erstellen von CAN-Botschaften definiert. Diese Klasse hat die Attribute: ID, rtr, length und Data. Diese Werte sind mindestens nötig um eine Nachricht nach dem Standard des CAN Protokolls zu versenden. Wichtig für dabei ist, dass beim CAN-Bus ist die 0 Dominant und 1en überschreibt.
Die ID dient zur Identifizierung von CAN Botschaften, gleichzeitig können dadurch Nachrichten priorisiert werden. Bei der CAN Kommunikation findet regelmäßig eine Arbitierungsphase statt. Das bedeutet es wird ermittelt welche CAN Botschaft die höchste Priorität hat und somit als erstes übertragen wird. Dies wird so realisiert, dass alle Bus- Teilnehmer gleichzeit versuchen eine Botschaft zu senden. Da die ID als erstes gesendet wird wird die ID mit den meisten 0en alle anderen überschreiben. Wird eine Botschaft eines Teilnehmers von einer 0 eines anderen Teilnehmers überschreiben, registriert der entsprechende Teilnehmer das und bricht den Sendevorgang ab.
Mit dem rtr Bit wird angegeben ob es sich bei der CAN Botschaft um einen sogenannten "Remote Frame" handelt. Mit einem Remoteframe können Daten von einem anderen Busteilnehmer angefordert werden. In dem Fall der Übertragung von Sensorwerten, muss dieses Bit also auf 0 gesetzt werden.
Das length Bit gibt an, wie lang das Datenfeld der CAN Botschaft ist. Die hier eingesetzte Library benötigt diese Angabe als Ganzzahl, welche die Anzahl der Bytes angibt. Der Arduino kann an seinen Analogen Eingängen Werte von 0 - 1024 einlesen. Um dies per CAN zu übertragen benötigt man hier also 2 Bytes (2Bytes=FFFF=65535).
In dem Datenfeld werden die eigentlich zu üebrtragenden Daten angegeben.
Die entsprechende Sendenfunktion sieht so aus:
void CAN_send(int ID, int length,unsigned char *Data) //Funktion zum senden einer CAN-Botschaft { message.id = ID; //Zuweisen der ID in die Strukturvariable message.header.rtr = 0; //Zuweisen des rtr in den Header der Strukturvariable message.header.length = length; //Zuweisen der lenth in den Header der Strukturvariable for( int i = 0; i < length; i++ ) //kopieren des Datenarrays in das Datenarrays der Struktur { message.data[i] = Data[i]; } mcp2515_send_message(&message); //Funktion aus Library die das senden der fertigen Botschaft übernimmt }
Quelle:Vector, Bussysteme und Bordnetze Vorlesung 10
Umsetzung der Aufgabe in Simulink
Eine Anleitung zur Entwicklung von Arduino Treibern in Simulink befindet sich unter folgendem Link