Ich begrüße Sie zu einem weiteren Blogbeitrag. Der letzte Beitrag behandelte eine Form der Kommunikation zwischen Geräten mit Qt Bluetooth Low Energy. Ich habe mich entschieden, noch ein wenig bei diesem Thema zu bleiben, daher werden wir uns heute mit dem CAN-Bus befassen. Dieses Thema könnte etwas schwieriger sein als das letzte, aber keine Sorge – wie immer werde ich versuchen, es so einfach und angenehm wie möglich zu gestalten. Ohne weitere Umschweife, legen wir los!
Kommunikation zwischen Geräten – eine triviale Frage?
Lassen Sie uns mit einem kleinen geistigen Aufwärmtraining beginnen. Angenommen, wir haben ein Fahrzeug mit zwei ECUs (Electronic Control Units – das sind kleine eingebettete Geräte, die Eingabedaten von z. B. Sensoren aufnehmen, verarbeiten und weiterleiten). Sie möchten, dass sie miteinander Informationen austauschen – was ist der einfachste Weg, sie zu verbinden? Ich gebe Ihnen ein paar Sekunden zum Nachdenken…
Zeit ist um. Die richtige Antwort ist ein Kabel 😅 Einfach, aber effektiv! Und wenn es mehr ECUs gibt? Dann verbinden Sie sie erneut mit einem Kabel – und das war’s! Dieser Ansatz wurde in der Automobilindustrie bis in die 1980er Jahre verwendet. Doch diese Lösung hatte viele Nachteile, also wurde eine intelligentere Methode entwickelt.
CAN-Bus – eine kurze Einführung
So wurde der CAN-Bus von der Firma Bosch entwickelt, um der zunehmenden Komplexität elektronischer Systeme in Fahrzeugen gerecht zu werden. Da Autos immer fortschrittlicher wurden, benötigten Hersteller eine Möglichkeit, verschiedene ECUs – wie jene für Motorsteuerung, Getriebe, Bremsen und Infotainment – miteinander zu verbinden, ohne dass eine übermäßige Verkabelung erforderlich war. Im Laufe der Zeit wurde der CAN-Bus zum Standard nicht nur in der automobilen HMI-Software und Sicherheitssystemen, sondern fand auch Anwendung in der industriellen Automatisierung, einigen medizinischen Geräten und anderen Bereichen, die einen Echtzeit-Datenaustausch erfordern.
Auf dem unten abgebildeten Foto sehen Sie den Beginn dieser Technologie – das erste Auto, das den CAN-Bus verwendete: der Mercedes-Benz W140 aus dem Jahr 1991.
1991 Mercedes-Benz W140
Was ist der CAN-Bus und wie funktioniert er?
Um den steigenden Anforderungen an eine effiziente und zuverlässige Kommunikation zwischen elektronischen Steuergeräten (ECUs) gerecht zu werden, wurde der CAN-Bus als leichtgewichtige, aber robuste Netzwerklösung entwickelt.
Im Gegensatz zur herkömmlichen Punkt-zu-Punkt-Verkabelung, die Fahrzeuge komplexer und schwerer machte, führte der CAN-Bus eine vereinfachte Methode für den Datenaustausch zwischen ECUs über einen gemeinsamen Kommunikationskanal ein.
Diese Architektur reduzierte nicht nur die Verkabelung, sondern erhöhte auch die Systemzuverlässigkeit und Fehlertoleranz. Dank seiner Effektivität in der Echtzeitkommunikation etablierte sich der CAN-Bus schnell als Industriestandard – zuerst im Automobilbereich und später in der industriellen Automatisierung, in medizinischen Geräten und anderen Bereichen, die eine schnelle und deterministische Datenübertragung erfordern.
CAN-Bus-Leitungen und ECU-Architektur
Der CAN-Bus nutzt eine differentielle Signalübertragung mit zwei speziellen Leitungen: CAN High (CAN_H) und CAN Low (CAN_L). Diese beiden Leitungen arbeiten zusammen, um Störungen zu reduzieren und die Zuverlässigkeit zu erhöhen. Wenn ein logisches „0“ (dominantes Bit) gesendet wird, steigt die Spannung auf CAN_H, während CAN_L sinkt. Wird ein logisches „1“ (rezessives Bit) gesendet, befinden sich beide Leitungen auf demselben Spannungsniveau.
Werfen wir einen Blick auf den Aufbau der bereits erwähnten Electronic Control Units (ECUs). Eine ECU besteht aus drei Hauptkomponenten:
Electronic Control Units ECU
ECUs kommunizieren über den CAN-Bus, indem sie Nachrichten in Form von CAN-Frames übertragen und empfangen, die einer standardisierten Struktur folgen.
CAN-Bus-Frame-Struktur
Ein CAN-Bus-Frame ist eine strukturierte Nachricht, die zur Kommunikation zwischen Geräten in einem CAN-Netzwerk verwendet wird. Sie besteht aus mehreren Schlüsselbereichen. Hier ist die Struktur eines standardmäßigen CAN-Bus-Datenframes:
CAN-Bus-Frame-Struktur
- Start of Frame (SOF) – 1 Bit – Markiert den Beginn des Frames und synchronisiert die Geräte.
- Arbitrationsfeld (ID) – 11 oder 29 Bit – Eindeutige Nachrichtenkennung, bestimmt die Priorität (niedrigerer Wert = höhere Priorität).
- RTR-Bit – 1 Bit – 0 für eine normale Nachricht, 1 für eine Datenanforderung.
- IDE-Bit – 1 Bit – 0 für eine Standard-ID (11 Bit), 1 für eine erweiterte ID (29 Bit).
- DLC (Data Length Code) – 4 Bit – Gibt die Anzahl der Datenbytes an (0–8 in CAN 2.0, bis zu 64 in CAN FD).
- Datenfeld – 0–8 Bytes (bis zu 64 in CAN FD) – Enthält die tatsächlich übermittelten Daten.
- CRC-Feld – 15 Bit – Fehlerprüffeld zur Sicherstellung der Datenintegrität.
- ACK-Feld – 2 Bit – Bestätigungsfeld – der Empfänger bestätigt den Empfang der Nachricht.
- End of Frame (EOF) – 7 Bit – Markiert das Ende der Nachrichtenübertragung.
- Interframe Space (IFS) – 3 Bit – Eine kurze Pause vor der nächsten Nachricht.
CAN-Bus-Synchronisation
Der CAN-Bus ist ein Broadcast-System, bei dem alle Knoten jede Nachricht empfangen, aber nur relevante Nachrichten verarbeiten. Er verwendet keine globale Uhr, sondern setzt auf Bit-Level-Synchronisation, bei der Signalübergänge die Knoten im Takt halten.
Um die Stabilität zu gewährleisten, fügt das Bit-Stuffing nach jeweils fünf identischen Bits ein entgegengesetztes Bit ein, um eine korrekte Synchronisation sicherzustellen. Arbitration verhindert Kollisionen – nur der Knoten mit der niedrigsten ID (höchste Priorität) setzt die Übertragung fort, während andere sofort stoppen.
Die Knoten verwenden außerdem eine dynamische Resynchronisation, bei der sie ihre Taktung anpassen, wenn sie unerwartete Übergänge erkennen.
CAN-Bus-Protokollversionen
In der Beschreibung der Frame-Struktur haben einige der Bits unterschiedliche Werte, je nach verwendeter Protokollversion. Die folgenden aktuellen Protokollversionen sind verfügbar:
- CAN 2.0A (Standard) – Verwendet einen 11-Bit-Identifier, weit verbreitet in der Automobilindustrie.
- CAN 2.0B (Extended) – Verwendet einen 29-Bit-Identifier, ermöglicht mehr eindeutige Nachrichten.
- CAN FD (Flexible Data Rate) – Erhöht die Datenkapazität auf 64 Bytes pro Frame und ermöglicht höhere Übertragungsgeschwindigkeiten.
- CAN XL – Die neueste Version, entwickelt für Hochgeschwindigkeitsanwendungen, unterstützt bis zu 2048 Bytes pro Frame.
Arten von CAN-Bus-Frames
Neben der Übertragung von eigentlichen Informationen gibt es im CAN-Bus verschiedene Arten von Frames, die sich in ihrer Funktion unterscheiden, aber eine ähnliche Struktur haben:
- Daten-Frame – Überträgt echte Daten (0–8 Bytes, bis zu 64 in CAN FD). Häufigster Frame-Typ.
- Remote-Frame – Fordert Daten von einem anderen Knoten an (RTR-Bit auf 1 gesetzt, kein Datenfeld).
- Fehler-Frame – Wird gesendet, wenn ein Übertragungsfehler erkannt wird, um alle Knoten zu benachrichtigen.
- Überlast-Frame – Verzögert die nächste Nachricht, falls ein Knoten mehr Verarbeitungszeit benötigt.
Branchen, die den CAN-Bus nutzen
-
Automobil- und Nutzfahrzeuge – Der CAN-Bus ist ein zentrales Kommunikationssystem in modernen Fahrzeugen. Er verbindet Steuergeräte (ECUs) für Motor, Getriebe, ABS, Airbags, Klimaanlage und Infotainment. Er ermöglicht Echtzeit-Diagnosen, reduziert Wartungskosten und steigert die Effizienz.
-
Industrielle Automatisierung – In der Produktion und Automatisierung verbindet der CAN-Bus Maschinen, Sensoren und Steuerungen, um den reibungslosen Betrieb von Fertigungslinien und Robotern zu gewährleisten.
-
Öffentlicher Verkehr und Bahnwesen – Der CAN-Bus wird in Zügen, Straßenbahnen und Bussen zur Steuerung von Antriebssystemen, zur Fahrzeugüberwachung und für Fahrgastinformationssysteme eingesetzt.
Branchen, die den CAN-Bus nutzen
Dank seiner Vielseitigkeit und Robustheit bleibt der CAN-Bus ein zentraler Kommunikationsstandard in vielen Branchen – von der Automobilindustrie bis zum Gesundheitswesen und darüber hinaus!
CAN-Bus vs. andere Kommunikationsprotokolle
Als Entwickler, der mit Embedded-Systemen arbeitet, habe ich den CAN-Bus als eines der zuverlässigsten und einfachsten Kommunikationsprotokolle kennengelernt – sobald man sich mit seinen Eigenheiten vertraut gemacht hat. Im Gegensatz zu RS-232 oder RS-485, wo man oft mit Punkt-zu-Punkt-Verbindungen und zusätzlichem Verkabelungsaufwand zu kämpfen hat, ist der CAN-Bus mit seinem Multi-Node-Aufbau auf nur zwei Leitungen ein echter Game-Changer.
Verglichen mit Ethernet mag der CAN-Bus etwas altmodisch wirken, da er niedrigere Datenraten bietet. Aber für Echtzeitanwendungen ist er unschlagbar. Wenn man an einem ECU-System arbeitet, bei dem eine verzögerte Nachricht möglicherweise einen Autounfall verursachen könnte, gewährleistet der deterministische Charakter des CAN-Bus, dass kritische Daten genau dann übertragen werden, wenn sie benötigt werden. Ethernet hingegen eignet sich hervorragend für die Übertragung großer Datenmengen, ist jedoch nicht ideal, wenn jede Millisekunde zählt.
Dann gibt es noch LIN, das man als die einfachere und kostengünstigere Variante des CAN-Bus betrachten kann – ausreichend für Funktionen wie Sitzverstellungen, aber nicht für sicherheitskritische Systeme geeignet.
Qt CAN-Bus – Überblick
Wie Sie vielleicht bereits wissen, bietet das Qt-Framework eine Reihe von Bibliotheken zur Implementierung verschiedener Kommunikationsformate – und der CAN-Bus bildet da keine Ausnahme. Im Qt Serial Bus-Modul steht eine Reihe von Klassen zur Verfügung, um die CAN-Bus-Kommunikation in Ihrer Anwendung zu implementieren.
Warum Qt für CAN-Bus-Kommunikation verwenden?
Abgesehen von den offensichtlichen Vorteilen der Verwendung von Qt in Ihrem Projekt (ja, Qt-Entwicklungsdienstleistungen sind genau das, was Scythe anbietet), gibt es drei Hauptvorteile bei der Verwendung von Qt CAN-Bus:
-
Hohe Abstraktionsebene – Qt bietet eine intuitive API für die CAN-Kommunikation und macht es überflüssig, direkt mit Low-Level-Treibern, Dateideskriptoren oder ioctl-Aufrufen zu arbeiten. Stattdessen kann man mit QCanBusDevice Verbindungen herstellen und Frames strukturiert senden/empfangen. Das macht den Code übersichtlicher, leichter wartbar und portierbar. Außerdem ermöglicht es ein einfaches Umschalten zwischen verschiedenen CAN-Bus-Versionen, indem lediglich die Verbindungsparameter angepasst werden.
-
Eingebaute CAN-Bus-Unterstützung – Qt unterstützt nativ mehrere CAN-Backends, darunter SocketCAN (Linux), PeakCAN und TinyCAN. Dadurch kann Ihre Anwendung mit minimalen Änderungen auf verschiedenen Plattformen laufen. Beispielsweise können Sie ein Test-Tool unter Linux mit SocketCAN entwickeln und dieselbe Anwendung unter Windows mit PeakCAN einsetzen, indem Sie lediglich den Backend-Namen wechseln. Diese Flexibilität macht Qt ideal für plattformübergreifende Entwicklungen mit unterschiedlichen Hardwareanforderungen.
-
Effizientes ereignisgesteuertes Modell – Das Signal-Slot-Mechanismus von Qt passt perfekt zur CAN-Kommunikation, da es ermöglicht, Nachrichten in Echtzeit asynchron zu verarbeiten. Anstatt den Bus ständig nach neuen Daten abzufragen, kann Ihre Anwendung automatisch auf eingehende Frames reagieren. Beispielsweise kann in einem Fahrzeug-Telemetriesystem ein Signal ein Live-Tachometer aktualisieren, sobald ein neuer Geschwindigkeitswert empfangen wird. In einer industriellen Automatisierungsumgebung könnte ein CAN-Frame mit Temperaturdaten sofort einen Alarm auslösen, wenn ein Grenzwert überschritten wird – und so für Echtzeit-Reaktionsfähigkeit sorgen.

Qt CAN-Bus-API
Die Qt CAN-Bus-API bietet eine strukturierte Möglichkeit, mit CAN-Bus-Hardware zu interagieren. Sie umfasst mehrere Schlüsselklassen:
- QCanBus – Verwaltet CAN-Bus-Verbindungen und ermöglicht Entwicklern, verfügbare CAN-Bus-Plugins zu überprüfen.
- QCanBusDevice – Repräsentiert ein physisches CAN-Bus-Gerät und stellt Methoden zum Verbinden, Trennen sowie Senden/Empfangen von CAN-Frames bereit. Es unterstützt auch das Setzen von CAN-Bus-Verbindungsparametern.
- QCanBusFrame – Kapselt einzelne CAN-Nachrichten und speichert Attribute wie Frame-ID, Nutzdaten und Zeitstempel.
Seit Qt 6.5 gibt es zusätzliche Klassen, die die Handhabung von CAN-Nachrichten noch effizienter machen:
- QCanSignalDescription – Definiert einzelne Signale innerhalb eines CAN-Frames.
- QCanMessageDescription – Beschreibt vollständige CAN-Nachrichten, die mehrere Signale enthalten.
- QCanFrameProcessor – Automatisiert das Kodieren und Dekodieren von CAN-Frames basierend auf vordefinierten Nachrichtenbeschreibungen.
Praxistest – Qt CAN-Bus-Anwendung erstellen
Nachdem wir alle geplanten theoretischen Aspekte besprochen haben, ist es Zeit für die praktische Demonstration. Dieses Mal habe ich mich entschieden, etwas Code aus einem früheren Blogbeitrag wiederzuverwenden, in dem ich einen Parksensor gebaut habe. Falls Sie diesen noch nicht gelesen haben, nehmen Sie sich jetzt einen Moment Zeit, um sich mit ihm vertraut zu machen. Wir werden nur die Benutzeroberfläche (UI) verwenden, also keine Sorge – es wird ganz einfach.
Das Konzept ist folgendes: Wir haben eine App, die mit dem Parksensor verbunden ist. Diese Anwendung zeigt mithilfe einer grafischen Benutzeroberfläche und akustischer Signale die Entfernung zum nächsten Hindernis an. Um das besser zu verstehen, werfen Sie einen Blick auf unseren LinkedIn-Beitrag, in dem wir dieses einfache System in Aktion zeigen.
Ursprünglich haben wir einen Ultraschallsensor verwendet, der an einen ESP32 angeschlossen war und per Bluetooth Low Energy mit der Anwendung kommunizierte. Leider hat das Board, das ich kürzlich verwendet habe, keinen CAN-Bus-Anschluss. Deshalb habe ich beschlossen, die Hardware mit einem virtuellen CAN-Port zu simulieren und Linux-Tools zum Senden und Empfangen von CAN-Nachrichten zu verwenden.
Einrichten eines virtuellen Ports
Falls Sie Qt für die Entwicklung nutzen und einen CAN-Bus für Tests benötigen, aber keine physische Hardware zur Verfügung haben, bietet Linux eine einfache Möglichkeit, eine virtuelle CAN-Schnittstelle mithilfe von SocketCAN zu erstellen. Dadurch können Sie das Senden und Empfangen von CAN-Frames testen, ohne zusätzliche Geräte anschließen zu müssen.
Um einen virtuellen CAN-Port einzurichten, führen Sie die folgenden Befehle im Terminal aus:
sudo modprobe vcan # Lädt das virtuelle CAN-Modul
sudo ip link add dev vcan0 type vcan # Erstellt eine virtuelle CAN-Schnittstelle mit dem Namen vcan0
sudo ip link set up vcan0 # Aktiviert die virtuelle CAN-Schnittstelle
Sobald die virtuelle CAN-Schnittstelle aktiviert ist, können Sie die Tools cansend und candump verwenden, um die CAN-Kommunikation zu testen:
candump vcan0 # Überwacht alle Frames auf vcan0
cansend vcan0 123#10 # Sendet einen Frame mit der ID 123 und der Nutzlast 0x10
Hauptanwendung
Was den UI-Code betrifft, so bleibt er derselbe wie im Beispiel mit Bluetooth. Der einzige Unterschied besteht darin, dass wir statt BLEController nun CANBusController verwenden. Werfen wir einen Blick darauf, wie diese Klasse aufgebaut ist.
Grundlegende Implementierung der CAN-Bus-Kommunikation
CANBusController::CANBusController(QObject *parent) :
QObject(parent), m_device(nullptr)
{
m_device = QCanBus::instance()->createDevice("socketcan", "vcan0");
if (m_device) {
connect(m_device, &QCanBusDevice::framesReceived, this, &CANBusController::processReceivedFrame);
} else {
qWarning() << "Kann die CAN-Bus-Schnittstelle nicht öffnen, Fehler: " << m_device->errorString();
}
}
void CANBusController::connectToCANBus() {
if (m_device) {
m_device->connectDevice();
}
}
Im Konstruktor erstellen wir eine Instanz des QCanBusDevice-Objekts mit der Methode createDevice. Hier übergeben wir zwei Argumente: den Namen des Plugins und den Namen der Schnittstelle. Da wir einen virtuellen Port verwenden, lautet der Plugin-Name socketcan, und der Portname ist in unserem Fall vcan0. Falls wir unsere Anwendung mit einem physischen Gerät testen möchten, müssen wir lediglich den Plugin- und den Portnamen ändern – Qt übernimmt den Rest für uns! Um das Gerät mit dem CAN-Bus zu verbinden, rufen wir einfach m_device->connectDevice() auf. Werfen wir nun einen Blick auf die Methode processReceivedFrame, die alle eingehenden Frames verarbeitet.
void CANBusController::processReceivedFrame() {
if (!m_device) return;
while (m_device->framesAvailable()) {
QCanBusFrame frame = m_device->readFrame();
uint16_t frameId = frame.frameId();
QByteArray payload = frame.payload();
qDebug() << "ID: " << QString::number(frameId, 16).toUpper()
<< " Daten: " << payload.toHex().toUpper();
if (frame.frameId() == DISTANCE_FRAME_ID && !frame.payload().isEmpty()) {
int distance = static_cast(frame.payload()[0]);
setDistance(distance);
}
}
}
Diese Methode ist mit dem Signal QCanBusDevice::framesReceived verbunden. Sie wird jedes Mal aufgerufen, wenn CAN-Bus-Frames empfangen werden. In der Methode dekodieren wir zunächst den empfangenen Frame in eine ID und eine Nutzlast und geben die Daten in der Konsole aus. Anschließend überprüfen wir, ob die ID mit einer vordefinierten Konstante übereinstimmt. Eine solche Filterung kann auch durch das Festlegen von CAN-Bus-Verbindungsparametern erfolgen, aber für dieses Demo-Beispiel habe ich es bewusst einfach gehalten. Sobald wir sicher sind, dass der Frame die richtige Frame-ID hat, dekodieren wir dessen Inhalt. CAN-Bus-Daten werden normalerweise im hexadezimalen Format gespeichert, daher führen wir die entsprechenden Umwandlungen durch und setzen die Variable `distance`.
Das Senden von Daten ist ebenfalls sehr einfach. Angenommen, wir möchten einen Fehler-Frame senden, der eine Fehlerbeschreibung als Nutzlast (ein String mit bis zu 8 Zeichen) enthält. Dazu genügt folgender Code:
void CANBusController::sendMessage(const QString &data) {
if (!m_device) return;
uint frameId = ENGINE_MALFUNCTION_FRAME_ID;
QByteArray payload = data.toUtf8();
QCanBusFrame frame(frameId, payload);
if (!m_device->writeFrame(frame)) {
qWarning() << "Fehler beim Senden des Frames";
}
}
Ergebnisse und Erkenntnisse
In der folgenden Demonstration können Sie sehen, wie die Anwendung funktioniert. Denken Sie daran, dass die gesendeten und empfangenen Daten im hexadezimalen Format vorliegen (deshalb wird beim Senden von 100#10 der Abstand auf 16 gesetzt, da 0x10 (HEX) = 16 (DEC) ist).

Zum Abschluss noch ein kleines Rätsel: Wenn Sie die Fehler-Senden-Schaltfläche drücken, wird eine Nachricht gesendet. Können Sie entschlüsseln, was ihr Inhalt ist? 🕵️♂️
Viel Spaß und viel Freude beim Lesen der kommenden Artikel!
Benötigen Sie Qt- oder C++-Entwicklungsdienstleistungen? Kontaktieren Sie uns!
Nach der Lektüre dieses Artikels haben Sie sicherlich erkannt, wie wichtig der CAN-Bus als Technologie ist. Das gezeigte Beispiel ist natürlich sehr einfach – in der Realität sind Projekte, die diese Kommunikationsform nutzen, weitaus komplexer. Falls Sie Unterstützung bei der Implementierung dieser Lösung in Ihrem Projekt benötigen, zögern Sie nicht, uns zu kontaktieren – wir helfen Ihnen gerne bei jedem Embedded-Software-Problem!