Themen:

AVR, avr-gcc, CAN, CPLD, Elektronik, Mikrocontroller, MSP430, PIC, Roboter, Schaltungen, Sensoren, Software, Testboards

über Mikrocontroller und ihre Schnittstellen

Tags: Mikrocontroller, AVR
Stand: 29. Juli 2006, 17:40
4 Kommentar(e)

Moderne Mikrocontroller haben ein ganzes Arsenal an verschieden Schnittstellen. Neben UART und SPI finden sich I2C (TWI), CAN und sogar USB. Ich will in diesem Artikel einmal versuchen die verschieden Schnittstellen vorzustellen und zu vergleichen.

Es soll dabei um folgende Schnittstellen gehen:

Man kann nicht sagen, dass eine Schnittstelle generell besser ist als die anderen, es kommt immer auf die spezielle Problemstellung an. Es soll in diesem Artikel hauptsächlich um die Vernetztung von mehreren Controller gehen und die Vor- und Nachteile der einzelnen Schnittstellen dafür.

UART

Der UART ist oftmals die einfachste Möglichkeit um zwei Controller miteinander zu verbinden, da so gut wie alle Controller ein integriertes UART Modul haben. Man muss lediglich auf beiden Controller die gleiche Baudrate einstellen und schon kann man Daten hin und her schieben.

Allerdings ist diese Verbindung auf Punkt zu Punkt Verbindungen beschränkt, es können also immer nur zwei Controller miteinander kommunizieren. Eine Erweiterung die man mit dem UART verwenden kann ist RS485. Damit alles sich Daten zwischen mehreren Teilnehmern austauschen, allerdings ist dies mit einigen Einschränkungen verbunden (siehe Unterpunkt RS485).

Die serielle Schnittstelle arbeitet dabei Byte-orientiert, das heißt es werden immer nur einzelne Bytes übertragen. Im Normalfall will man aber nicht nur Bytes sondern ganze Nachrichten übertragen. Man will also aus einem Datenstrom die wichtigen Daten heraus filtern. Dazu braucht man ein wie auch immer geartetes Protokoll. Zwei Möglichkeiten die sich als sehr brauchbar herausgestellt haben will ich hier einmal vorstellen:

1.) Escapte Zeichen

Dieses Protokoll orientiert sich indirekt an dem ASCII Zeichensatz. Alle Zeichen kleiner 0x20 (32) werden als Steuerzeichen definiert. Will man nun Daten die in diesem Bereich liegen übertragen, so muss man sie escapen, ihnen also zuerst ein Escape Zeichen (= 0x1b, siehe ASCII Zeichensatz) voranstellen. Man sendet also nicht einfach 0x03 sondern 0x1b 0x03. Der Empfänger muss dann natürlich diese Escape Zeichen wieder heraus filtern. Um das Ende der Nachricht zu kennzeichnen braucht man noch ein Pakettrennzeichen. Dafür könnte man zum Beispiel 0x00 wählen.

Eine vollständige Nachricht die drei Bytes (0x45 0x02 0xaf) sendet würde dann so aussehen:

0x45 0x1b 0x02 0xaf 0x00

Allerdings lässt sich dieses Protokoll nicht mehr so gut erweitern. Ich werde darauf im Vergleich der beiden vorgestellten Möglichkeiten noch einmal eingehen.

2.) Synchronisationsbytes

Im Gegensatz zum vorherigen Protokoll wird hierbei nicht das Paketende definiert, sondern der Anfang. Dazu müssten zuerst zwei Synchronisationsbyte gesendet werden. Was man dabei genau wählt ist eigentlich egal, von Vorteil ist es allerdings, wenn diese Zeichenkombination nicht sehr häufig in den gesendeten Daten auftritt, da sich sonst im allerschlechtesten Fall ein Teilnehmer am Anfang falsch synchronisieren könnte und so einmal eine falsche Nachricht empfangen würde. Nehmen wir einmal an das als Synchronisationsbytes 0x12 0x23 gewählt wurde. Um ein Nachricht zu verschicken sendet man also als erstes die beiden Synchronisationsbytes, dann ein Byte mit der Länge der Nachricht und dann die Daten selber. Die Nachricht mit den Daten von vorhin würde also folgendermaßen aussehen:

0x12 0x23 0x03 0x45 0x02 0xaf

Ein ähnlich aufgebautes Protokoll, das in der Industrie genutzt wird, ist zum Beispiel S.N.A.P. (Scaleable Node Address Protocol) der schwedischen Firma High Tech Horizont. Dieses wird unter anderem in Powerlinemodems verwendet.

Vergleich man die beiden Protokoll, so fällt zum Beispiel auf, dass man im ersten Beispiel ein Byte weniger senden muss. Wäre kein Datenbyte kleiner 0x20 dabei (müsste also kein Zeichen escaped werden), so wären es sogar zwei Bytes. Es hängt also davon ab wie viele der Datenbytes escaped werden müssen. Geht man von einer gleichmäßigen Verteilung der Daten über den ganzen Bereich aus, so wäre die wirkliche Nachrichtenlänge ab 10 Datenbytes mit dem zweiten Protokoll kürzer, da dies einen immer gleich bleibenden Overhead von drei Bytes hat. Meinen Erfahrungen nach ist es aber so, dass man überproportional viele Zeichen in diesem unterem Bereich sendet.

Einen weiteren Vorteil den das zweite Protokoll hat ist die leichte Erweiterbarkeit. Wie man am Beispiel von S.N.A.P. sieht kann man ohne großen Aufwand noch eine ganze Menge an zusätzlichen Funktionen einbauen. Nehmen wir zum Beispiel einmal eine Prüfsumme die noch hinzugefügt werden soll um feststellen zu können ob die Daten auch richtig übertragen wurden. Im einfachsten Fall kann dies zum Beispiel ein zusätzliches Byte sein das nach den eigentlichen Daten gesendet wird und die XOR-Summe der Datenbytes und der Länge enthält.

0x12 0x23 0x03 0x45 0x02 0xaf 0x12

Man kann natürlich auch bessere Prüfsummen wie CRC16 einbauen. Dies kann man natürlich auch beim ersten Protokoll machen, allerdings muss man dabei zwingend mit entsprechenden Puffer arbeiten und dann bei n übertragenen Bytes das n-1te Byte auswerten.

RS485

Will man mit dem UART Daten an mehrere Teilnehmer versenden so lohnt es sich einen Blick auf RS485 zu werfen. RS485 ist nur eine Festlegung zur Physikalischen Übertragung der Daten, anders als zum Beispiel CAN legt RS485 überhaupt kein Protokoll fest, man kann aber zum Beispiel die beiden vorgestellten Protokoll für den UART verwenden, wenn man sie um eine Sende bzw. Empfangsadresse erweitert. Auch S.N.A.P. ist hierfür hervorragend geeignet. Aber auch ganz viele andere Protokoll sind denkbar, zum Beispiel arbeitet DMX512 Bussystem das hauptsächlich in Bühnen- und Showtechnik eingesetzt wird) mit RS485 Pegeln. Grundsätzlich ist RS485 Multimasterfähig.

Es gibt zwei verschiedene Verschaltungformen: Full Duplex und Half Duplex. Bei Full-Duplex werden der Empfangskanal und der Sendekanal auf jeweils zwei Leitungen mit komplementären Pegeln übertragen. Man braucht also mindestens vier Leitungen. Die Sendeleitung des Master geht an die Empfangsleitungen der Slaves und die Sendeleitungen werden zusammen an die Empfangsleitung des Masters geführt. Der Master ist also immer sende berechtigt - alle Slaves empfangen nur die vom Master gesendeten Daten. Es darf immer nur ein Slave auf einmal senden.

Nur mit der Halb-Duplex Verschaltung ist ein eingeschränkter Multimaster Betrieb möglich. Die Daten werden als Differenzspannungen über zwei Leitungen übertragen, das erhöht zwar die Störsicherheit enorm (Kabellängen bis zu 1 km sind mit RS485 möglich) führt aber dazu, dass nicht gleichzeitig gesendet und empfangen werden kann (bei den meisten RS485 Treiber muss man über einen extra Pin zwischen Senden um Empfangen umschalten). Außerdem drüfen niemals zwei Teilnehmer gleichzeitig Daten senden, da es sonst zu Kollisionen auf dem Bus kommt und die Daten nicht mehr richtig übertragen werden. Allerdings hat der Sender keine Möglichkeit Kollisionen festzustellen. Das führt zu einen erheblichen Problem, welches sich nur über eine entsprechende Verwaltung lösen lässt.

Dabei gibt es zum Beispiel die zwei folgenden Möglichkeiten:

1.) Ein Master vergibt Sendeberechtigungen

Verabschiedet man sich von der Idee, dass alle Teilnehmer gleichberechtigt sein sollen, so kann das Problem mit den Kollisionen so lösen, dass man einen Teilnehmer zum Master erklärt. Dieser koordiniert dann das gesamte Netzwerk.
Wenn ein Teilnehmer dann eine Nachricht senden will, so muss er erst den Master dafür um Erlaubnis bitten. Dies kann man auf verschiedene Arten geschehen.

Entweder der Master fragt regelmäßig alle Teilnehmer ob sie etwas senden wollen und erteilt dann ihnen dann die Berechtigung, der Teilnehmer sendet die Nachricht und übergibt die Kontrolle des Buses wieder an den Master.
Eine andere Möglichkeit wäre auch mit Status-Leitungen zu arbeiten. Von jeden Teilnehmer geht also eine Leitung zum Master, wenn der Teilnehmer ein Nachricht senden will, dann zieht der diese Leitung auf low und wartet bis er die Berechtigung zum Senden bekommt. Damit müsste der Master nicht ständig den Bus abfragen, dafür müssen man zusätzliche Kabel verlegen.

2.) eine Art Tokenring

Ähnlich wie beim Tokenring wird hier ein Token von Teilnehmer zu Teilnehmer weitergereicht, allerdings enthält dies Token keine Nachrichten sondern eine Art Sendeberechtigung. Der Teilnehmer bei dem das Token gerade ist darf also beliebig Nachrichten über den Bus versenden. Sobald er damit fertig ist gibt er das Token an den nächsten Teilnehmer weiter, darauf hin darf dieser dann senden usw.

Allerdings hat diese Verfahren auch einige Nachteile: Man muss zum Beispiel für jeden Teilnehmer festlegen welcher der folgende Teilnehmer ist, damit das Token weitergereicht werden kann. Außerdem muss man festlegen was passiert wenn einmal ein Teilnehmer ausfällt bzw. nicht erreichbar ist. In dem Fall würde das Token ins Leere laufen und man müsste dies irgendwie erkennen und den Bus zurücksetzen.

Wie man sieht sind beide Möglichkeiten nicht ganz einfach zu realisieren und erfordern eine ganze Menge von Busbandbreite nur für die Verwaltung. Sehr viel einfacher geht es allerdings meiner Meinung nach nicht wenn man mit RS485 Daten zwischen allen Teilnehmern austauschen will. Ich lasse mich aber auch gerne eines Besseren belehren :-)

Wer also mehrere Mikrocontroller miteinander vernetzten will sollte sich vielleicht ersteinmal CAN anschauen und dann vergleichen was ihm geeigneter erscheint.

SPI

Im Gegensatz zum UART arbeitet SPI syncron, dass heißt es gibt neben den Datenleitungen auch noch eine Taktleitung. Die Daten können also beliebig langsam übertragen werden, nur nach oben ist die Geschwindigkeit meist beschränkt. Allerdings liegt diese Beschränkung meist sehr hoch, zum Beispiel wird der MCP2515 per SPI angesteuert und kann SPI Taktfrequenzen bis zu 10 MHz verarbeiten.
Diese hohe Geschwindigkeit ist allerdings meist nur über sehr kurze Entfernungen möglich, z.B. wenn Master und Slave auf der gleichen Platine sitzen. Bei längeren Leitungen muss die Geschwindigkeit dann herunter gesetzt werden.

Anders als z.B. bei I2C werden die Daten auf zwei Leitungen übertragen, also eine Leitungen für Daten zum Master (MISO(Master In Slave Out)) und eine für Daten zum Slave (MOSI(Master Out Slave In)). Dies führt dazu das theoretisch gleichzeitig gesendet und empfangen werden kann, allerdings wird dies in den meisten Fällen nicht so gemacht.

I2C (TWI)

I2C wurde von Philips entwickelt für kurze Verbindungen auf einer Platine. Mittlerweile gibt es eine vielzahl von I2C Bausteinen, so zum Beispiel Portexpander, Analog/Digital und Digital/Analog-Wandler, EEproms, Temperatursensoren, LCD Treiber, RAM Erweiterungen u.v.m.

Atmel bezeichnet aus Lizensrechtlichen Gründen die I2C Schnittstelle bei ihren Controllern als TWI, also Two Wire Interface, es ist aber eigentlich genau das selbe wie I2C.

Der I2C Bus arbeitet ähnlich wie SPI syncron, kommt aber ohne Chip Select Leitungen bzw. mit nur einer Leitungen für die Daten aus. Es werden also nur die zwei Leitungen SCL (Takt) und SDA (Daten). Grundsätzlich ist I2C Multimasterfähig, allerdings ist die nicht ganz einfach zu realisieren, so dass die meisten I2C Systeme als Master Slave System aufgebaut sind. Dabei kontrolliert der Master die Taktleitung und spricht die einzelnen Slave über deren voreingestellte Adresse an. Allerdings ist es so nicht möglich Daten direkt zwischen zwei Slaves auszutauschen. Dies muss immer über den Master geschehen.

I2C arbeitet im Gegensatz zum UART bedingt Paket orientiert.

I2C Master

Ein I2C Master ist per Software an zwei beliebigen Pins sehr einfach zu realisieren. Es finden sich auch im Internet eine ganze Menge an Beispielen dazu.

Allerdings sollte man ein bisschen aufpassen. Es gibt hin und wieder auch I2C Slaves die Gebrauch von der Möglichkeit des Clock Strechings machen, also durch ein Low ziehen der Taktleitung den Master anzeigen das sie mit dem verarbeiten der Daten noch nicht fertig sind. In dem Fall muss der Master warten bis der Slave die Leitung wieder frei gibt. Die meisten einfachen Implementierungen beachten dies gar nicht sondern senden stur die Daten. Dies funktioniert allerdings nur solange man langsam genug sendet, so dass der Slave Controller mit dem Empfangen und Verarbeiten der Daten immer schon fertig ist.

I2C Slave

Eine I2C Slave Schnittstelle per Software zu implementieren ist nicht ganz einfach und fast immer nur für geringe Geschwindigkeiten möglich, da der Slave ständig auf die I2C Leitungen horchen muss ob neue Daten empfangen werden sollen. Dieses Polling benötigt bei höheren Geschwindigkeiten (100 kbps o.ä.) die gesamte Rechenleistung des Mikrocontrollers, so dass es nicht mehr viel anderes nebenher tun kann.

Abhilfe schaffen hier nur Mikrocontroller die eine Hardware I2C Slave Schnittstelle bieten, wie etwa alle AVRs mit TWI oder USI Schnittstelle. Dadurch läuft das Empfangen der Daten Interruptgesteuert im Hintergrund ab und der Anwender muss fast nicht mehr daraum kümmern. Damit lassen sich dann auch komplexe I2C Slave Anwendungen realisieren.

Teilweise ist zu überlegen ob es sich überhaupt noch lohnt sich einen extra I2C Portexpander wie den PCF8574 zu kaufen. Bei Reichelt kostet er im Moment 1,7 Euro, ein ATTiny26 kostet nur 30 Cent mehr, ein ATTiny2313 gar 5 Cent weniger. Die beiden AVRs lassen sich ohne größeren Aufwand zu einem sehr flexiblen Portexpander, Analog/Digital-Wandler oder was immer man auch gerade braucht umprogrammieren.

[ Anmerkung ]

Ich habe es jetzt immer wieder in verschieden Foren gesehen, das Bausteine über I2C und UART angesprochen werden können sollen und dann das Protokoll für den UART gleich für I2C mit übernommen wurde. Es muss dann also vom Master zurerst die Adresse des Slaves, dann die Synchronisationsbytes und dann erst die Daten geschickt werden.

Dies ist allerdings meiner Meinung nach vollkommen unsinnig, da bei I2C ja schon komplette Pakete verschickt werden und im Gegensatz zum UART nicht erst in einem Datenstrom der Anfang der Nachricht gesucht werden muss. Dadurch wird lediglich die nutzbare Busbandbreite reduziert, ein anderen Zweck gibt es dafür nicht.

CAN

CAN ist das erste der vorgestellten Bussystemen das uneingeschränkt Multimasterfähig ist. Es wurde 1983 von Bosch für den Einsatz in Autos entwickelt um dort die großen Kabelbäume zu reduzieren und damit Gewicht zu sparen.
Mittlerweile ist CAN sehr weit verbreitet, was man auch daran sieht, dass es von fast allen großen Chipherstellern Produkte zum CAN Bus gibt. Selbst in extrem Sicherheitskritischen Bereichen wie dem Flugzeugbau werden CAN Busse eingesetzt. Dies hat für den Hobbyanwender den Vorteil das die Chip recht günstig und meist auch einfach zu beschaffen sind.

Auf die genaue Technik will hier jetzt nicht eingehen. Bei wikipedia.de wird diese aber recht gut erklärt.

Der CAN Bus hat meiner Meinung nach einige Eigenschaften die ihn fast ideal zum Vernetzen von vielen Controller machen:

“Protokoll im Chip”

Anders also zum Beispiel bei RS485 o.ä. legt CAN auch ein relativ komplexes Protokoll mit fest. Dies führt dazu das es mit einigem Aufwand verbunden wäre eine CAN Controller per Software nachbilden zu wollen. Möglich ist dies aber durchaus, wenn auch nur bei niedrigen Geschwindigkeiten (z.B. das “Caraca Projekt”:http://caraca.sourceforge.net/).

Andererseits gibt es aber auch spezielle Chips die einem genau diese Arbeit abnehmen. Man braucht zwar einen zustätzlichen Chip (bei Mikrocontroller mit integriertem CAN Controller wie dem AT90CAN128 oder dem PIC18F2680 nicht einmal mehr diesen), muss sich dafür aber überhaupt nicht mehr um die eigentliche Datenübertragung kümmern. Man füllt lediglich die entsprechenden Register und den Rest erledigt der CAN Controller.

Hohe Übertragungssicherheit

CAN verwendet bei der Nachrichtenübertragung CRC16-Checksummen. Wird eine Nachricht falsch übermittelt, so wird die Nachricht automatisch noch einmal gesendet.

Wenn ein Knoten ausfällt oder fehlerhaft initialisiert wurde (z.B. falsche Bitrate) so wird dieser automatisch vom Bus getrennt und stört die restliche Kommunikation nicht weiter.

Hohe Geschwindigkeiten
Es sind Geschwindigkeiten bis 1 MBaud bei maximal 40 m Leitungslänge möglich. Will man Daten über größere Strecken übertragen muss die Geschwindigkeit reduziert werden.
Multimastersytem mit priorisierten Nachrichten

Alle Knoten im CAN Bus können gleichzeitig senden, ohne das es zu Kollisionen und Datenverlusten kommt. Durch den Arbitrierungsvorgang haben alle Nachrichten unterschiedliche Prioritäten und werden auch entsprechend dieser Prioritäten gesendet.

Das bedeutet, dass man den Bus durch Nachrichten niedriger Priorität vollständig Auslasten kann und Nachrichten hoher Priorität immer noch fast so schnell verschickt werden wie wenn der Bus frei wäre.

Das CAN-Protokoll basiert nicht auf einem Datenaustausch durch Adressierung des Nachrichtenempfängers, sondern erfolgt durch Kennzeichnung einer übertragenen Nachricht über einen Identifier. Alle Knoten prüfen anhand der Kennung einer empfangenen Nachricht, ob diese für sie relevant ist. Nachrichten können daher von keinem, einem, vielen oder allen Teilnehmern übernommen werden. Es werden daher nicht Befehle im eigentlichen Sinne verschickt, sondern Ereignisse “gemeldet”, die entsprechenden Knoten müssen dann selbst wissen was sie darauf hin tun.

Die Vergabe des Buszugriffsrechts erfolgt nicht durch eine übergeordnete Steuereinheit wie zum Beispiel bei RS485 im Full-Duplex Betrieb. Vielmehr kann jeder Teilnehmer gleichberechtigt mit dem Senden einer Nachricht beginnen, sobald der Bus frei geworden ist. Während einer Arbitrierungsphase erhält dabei der Teilnehmer mit der Nachricht der höchsten Priorität (niedrigste ID) das Buszugriffsrecht. Jeder Teilnehmer kann damit ohne Einschränkungen direkt mit jedem anderen Teilnehmer kommunizieren. Da das Senden einer Nachricht von einem Knoten selbst veranlasst werden kann, erfolgt bei Ereignis-gesteuerter Nachrichtenübertragung eine Busbelegung nur dann, wenn neue Daten vorliegen. Damit erreicht man zum Beispiel gegenüber einem Master-Slave-System eine wesentlich niedrigere mittlere Busbelastung, da der Master nicht ständig überprüfen muss ob neue Nachrichten vorliegen (kein Polling).

Für einfache Sachen ist CAN natürlich etwas überdimensioniert. Niemand würde auf die Idee kommen einen einzelnen Portexpander per CAN an einen Mikrocontroller anbinden zu wollen (es sei den man hat schon ein bestehendes CAN Netzwerk). Für sowas eignen sich I2C und SPI wegen ihrer Einfachheit wesentlich besser.

USB

Die USB Schnittstelle habe ich nur hier mit aufgenommen, da einige neuere PICs von Microchip einen integrierten USB Slave Controller bieten. Für die Vernetztung von Controllern (jedenfalls im Hobbybereich) spielt USB keine Rolle, da man immer einen USB Host braucht an denen dann mehrere USB Slave Devices angeschlossen werden können.

Aufgrund der Komplexität des USB Hosts findet man fast keine 8-Bit Mikrocontroller die einen solchen integriert haben. Es gibt zwar Leute die es geschafft haben auch eine USB Host in einen AVR zu packen, allerdings sind solche Lösungen meist unpraktisch, da sie nur eine sehr niedrige Übertragungsrate erlauben (im Bereich von wenigen Byte pro Sekunde) und den Controller damit schon vollkommen auslasten.

Lediglich als Schnittstelle zum PC hin hat USB eine immer größere Bedeutung erlangt, da es immer mehr PCs ohne serielle Schnittstelle gibt, dafür aber mit vielen USB Anschlüssen. Am einfachsten kann die Anbindung dabei über einen extra Chip erfolgen wie den FT232 (USB zu Seriell Konverter) oder für höhere Datenraten den FT245 (USB zu Parallel) bzw. FT2232C (USB zu 2 mal Parallel/Seriell/SPI). Es gibt außerdem den genannten Chips von FTDI noch eine ganze Reihe anderer, allerdings sollte man bei der Entscheidung für einen Chip auch drauf achten wie gut er von PC Seite her unterstützt wird. Zu dem FT232BM Chip, mit dem ich bisher schon gearbeitet habe (siehe USB zu RS232 Adapter), gibt es zum Beispiel für Windows einen VCP Treiber, der dann, wie der Name schon sagt, einen virtuellen COM Port bereit stellt, der dann fast wie ein normaler COM-Port angesprochen werden kann. Linux unterstützt ihn sogar schon vom Kernel aus, man braucht also nicht einmal einen Treiber zu installieren.

Zum Anfang

Kommentare

# Dude meinte am 15. November 2007, 07:08 dazu:

Wirklich hilfreiche Seite, die auch noch optisch ansprechen aufgebaut ist. Lob!

# Werner meinte am 20. Juni 2010, 10:28 dazu:

Sehr gute Beschreibung und hilfreich bei der Auswahl einer Übertragung zwischen Mikrocontrollern.

# Tom meinte am 28. März 2013, 10:29 dazu:

Super Seite! Besten Dank für die ausführlichen Informationen!

# freelancer meinte am 9. Juli 2013, 16:52 dazu:

Einen Attiny2313 kann man leider nicht zu einem I2C-ADC umprogrammieren. Er besitzt gar keinen ADC.