Guten Morgen, ich arbeite gerade an einem Testprojekt bei dem 5 Mega328 über CAN-Bus miteinander kommunizieren. Dabei habe ich die Lib von Fabian Greif (kreatives Chaos) im Einsatz. Das System ist so konfiguriert, dass ein Master die Kommunikation steuert. Die Abfrage an die Slaves erfolgt zyklisch und genau so werden auch Kommandos übergeben. Senden und Empfangen, sowie Filterkonfiguration klappen soweit ganz gut und der Bus läuft stabil. Zwischen jedem Sendevorgang, den der "Master" durchführt habe ich noch 5ms delay eingebaut, um die Antwort eines jeden "Slaves" abzuwarten. Schema: Master sendet --> Slave1 --> Slave1 sendet Antwort zurück an Master Master sendet --> Slave2 --> Slave2 sendet Antwort zurück an Master Master sendet..... Nutzen: Bei diesem Projekt soll eine Lichtsteuerung bzw. Rolladensteuerung realisiert werden. Die Tasterzustände der einzelen Teilnehmer werden vom Master abgefragt und wenn ein Taster eines Teilnehmers betätigt wird, soll eine Aktion ausgeführt werden (Licht ein/aus, Rollladen rauf/runter). Meine konkrete Frage: Wie würdet ihr die Datenverarbeitung des Mastercontrollers am effizientesten lösen? - State-Machine? - Scheduler? - sofortige Auswertung der Daten nach Empfang? - Zwischenspeicherung der Daten in einem Array und danach Bearbeitung? Wie gesagt, die Kommunikation, wie ich sie im Moment betreibe funktioniert sehr gut. Unsicher bin ich mir, wie und wann ich die Daten am besten verarbeite. Vielleicht könnt ihr mir hierzu ein paar Tips geben, um ein vernünftiges Management aufbauen zu können. Achja, hier noch einige Eckdaten: Controller: mega328 16MHz Can Controller: MCP2515 16MHz (Chinamodul) Busgeschwindigkeit: 125kBpS Filter: Master - keine Filter Slave - jeweils nur für ihn bestimmte Nachrichten. Ich freue mich auf eure Tipps - Danke im Voraus! Markus
Markus W. schrieb: > Das System ist so konfiguriert, dass ein Master die Kommunikation > steuert. Die Abfrage an die Slaves erfolgt zyklisch und genau so werden > auch Kommandos übergeben. Mit dem CAN-Bus hat dein Protokoll wenig zu tun. Bei der Datenübertragung in einem CAN-Bus werden keine Knoten adressiert, sondern der Inhalt einer Nachricht (z. B. Schalterzustand oder Sensorwert) wird durch einen eindeutigen Identifier gekennzeichnet. Der Identifier legt auch die Priorität der Nachricht fest.
Es ist überhaupt nicht nötig einen Master oder Slaves zu haben. Entweder sagst du deinen "Slaves" sie sollen die Infos zyklisch ausgeben oder nur bei Zustandsänderung. Bei einer einfachen Rolladen/Lichtsteuerung wirst du nie in Bereiche kommen das der BUS überlastet wird. Ansosten könnte man auch einen µC mit integriertem CAN-Controler nehmen z.B. ATMega16M1,32M1......
Markus W. schrieb: > Das System ist so konfiguriert, dass ein Master die Kommunikation > steuert. Die Abfrage an die Slaves erfolgt zyklisch und genau so werden > auch Kommandos übergeben. Du hast also selber noch ein eigenes Protokoll obendrauf gesetzt, den CAN kennt von sich aus keinen Master oder Slave. Welchen Zweck hat dieses Protokoll? > Master sendet --> Slave1 --> Slave1 sendet Antwort zurück an Master > Master sendet --> Slave2 --> Slave2 sendet Antwort zurück an Master > Master sendet..... Bei CAN wird nicht an einen bestimmten Knoten gesendet. Alle Botschaften sind Broadcasts, und wer immer sich für einen bestimmten Wert interessiert, lauscht auf der entsprechenden ID. > Meine konkrete Frage: > > Wie würdet ihr die Datenverarbeitung des Mastercontrollers am > effizientesten lösen? > - State-Machine? > - Scheduler? > - sofortige Auswertung der Daten nach Empfang? > - Zwischenspeicherung der Daten in einem Array und danach Bearbeitung? Die empfangenen CAN-Botschaften in eine Queue stecken und dann abarbeiten. Irgendwo liegt eine Datenstruktur, die die in der Botschaft enthaltenen Werte aufnimmt und in der immer der aktuellste Wert drin steht. Thomas O. schrieb: > Es ist überhaupt nicht nötig einen Master oder Slaves zu haben. Entweder > sagst du deinen "Slaves" sie sollen die Infos zyklisch ausgeben oder nur > bei Zustandsänderung. Oder beides, also z.B. zyklisch einmal pro Sekunde und zusätzlich sofort bei jeder Zustandsänderung. So kann man die Buslast gering halten, aber der "Master" bekommt trotzdem alle Werte mit, wenn er irgendwann erst später eingeschaltet wird. > Bei einer einfachen Rolladen/Lichtsteuerung wirst du nie in Bereiche kommen > das der BUS überlastet wird. Genau. Im Auto werden auf die Weise Tausende von Werten über einen CAN-Bus geschickt.
Ich habe vor einiger Zeit mit RS-485 gearbeitet. Daher bin ich noch etwas auf die Master-Slave-Kommunikation fixiert. Wolfgang schrieb: > in einem CAN-Bus werden keine Knoten adressiert, > sondern der Inhalt einer Nachricht (z. B. Schalterzustand oder > Sensorwert) wird durch einen eindeutigen Identifier gekennzeichnet. Natürlich arbeite ich nicht mit Adressen sondern mit Identifieren. Thomas O. schrieb: > Bei einer einfachen Rolladen/Lichtsteuerung wirst > du nie in Bereiche kommen das der BUS überlastet wird. Wenn alle meine "Slaves" oder "Nodes" zyklisch senden, besteht da nicht die Gefahr dass der "Master" überlastet wird? Der bekommt ja schließlich Nachrichten von allen Teilnehmern und muss diese Verarbeiten. Ich denke man kann auch das nur zeitgesteuert realisieren. Welche Intervallzeiten wären denn da sinnvoll? Rolf M. schrieb: > CAN kennt von sich aus keinen Master oder Slave. Welchen Zweck hat > dieses Protokoll? Das soll kein Protokoll sein, sondern nur eine Vorgehensweise, bei der der so genannte Master alle Vorgänge steuert. Weiters sollen zB. Öffnungs- und Schließzeiten der Rolläden vom "Master" vorgegeben werden. Narürlich läuft die Kommunikation entsprechend des CAN-Protokolls ab (Identifier, Prioritäten usw.) Rolf M. schrieb: > Die empfangenen CAN-Botschaften in eine Queue stecken und dann > abarbeiten. Irgendwo liegt eine Datenstruktur, die die in der Botschaft > enthaltenen Werte aufnimmt und in der immer der aktuellste Wert drin > steht. Für mich sehr wichtige Info - Leider kenne ich den Begriff "Queue" nicht. Könntest Du mir das bitte etwas erklären bzw. einen kurzen Code-Snipped zeigen wie so etwas aussieht?
Bei CAN können alle gleichzeitig lossenden es kommt aber nur die Nachricht mit der niedrigsten ID durch die anderen Knoten Stellen das Senden ein und wiederholen das Senden wenn die andere Nachricht fertig ist. Schau dir mal im Wiki den Abschnitt Arbitrierung durch.
:
Bearbeitet durch User
Markus W. schrieb: > Thomas O. schrieb: >> Bei einer einfachen Rolladen/Lichtsteuerung wirst >> du nie in Bereiche kommen das der BUS überlastet wird. > > Wenn alle meine "Slaves" oder "Nodes" zyklisch senden, besteht da nicht > die Gefahr dass der "Master" überlastet wird? Der bekommt ja schließlich > Nachrichten von allen Teilnehmern und muss diese Verarbeiten. Das muss er doch sowieso. Nur muss er bei deiner Master/Slave-Kommunikation zusätzlich noch die Anfragen verschicken. > Ich denke man kann auch das nur zeitgesteuert realisieren. Welche > Intervallzeiten wären denn da sinnvoll? Das kommt darauf an, welche Verzögerungszeiten du für akzeptabel erachtest. Wenn der "Slave" einfach so senden kann, kannst du die Zykluszeit relativ lang machen und dann spontan in dem Moment senden, in dem der Taster gedrückt wird, um eine sofortige Reaktion auszulösen. Übrigens: Das hier: Markus W. schrieb: > Senden und Empfangen, sowie Filterkonfiguration klappen soweit ganz gut > und der Bus läuft stabil. Zwischen jedem Sendevorgang, den der "Master" > durchführt habe ich noch 5ms delay eingebaut, um die Antwort eines jeden > "Slaves" abzuwarten. bedeutet ja, dass der "Slave" in maximal 5 ms auf die Anfrage geantwortet haben muss. Was passiert denn, wenn die Antwort später kommt? > Das soll kein Protokoll sein, sondern nur eine Vorgehensweise, bei der > der so genannte Master alle Vorgänge steuert. Genau sowas nennt man Protokoll :) > Rolf M. schrieb: >> Die empfangenen CAN-Botschaften in eine Queue stecken und dann >> abarbeiten. Irgendwo liegt eine Datenstruktur, die die in der Botschaft >> enthaltenen Werte aufnimmt und in der immer der aktuellste Wert drin >> steht. > > Für mich sehr wichtige Info - Leider kenne ich den Begriff "Queue" > nicht. Eine Warteschlange. https://de.wikipedia.org/wiki/Warteschlange_(Datenstruktur)
:
Bearbeitet durch User
Markus W. schrieb: > Natürlich arbeite ich nicht mit Adressen sondern mit Identifieren. Es hörte sich aber so an, als ob dein Master die Slaves der Reihe nach abfragt. Soll dein Identifier dann ein "Poll"-Identifier sein und der Nachrichteninhalt wäre die Slave Adresse? Oder wie ist das gemeint? Das würde doch genau einer individuellen Adressierung entsprechen und nichts mit dem grundsätzlichen Broadcast-Konzept vom CAN zu tun haben, zumindest bezogen auf die Antworten deiner Slaves. Irgendwie mischt du da zwei Konzepte.
Dein Master Slave Konzept ist gut für andere Halbduplex Leitungen, bei CAN eher über. Zur Frage: mach einfach. Du brauchst Erfahrung. Bei master/slave wirst Du feststellen, dass es egal ist, bzw alles gleich: du kannst direkt auswerten, es wird dadurch nicht langsamer, im Gegenteil. Dann wirst Du feststellen, das CAN viel besser ist und keinen Master braucht. Je nach Art der Nachrichten und Leistung deines uControllers brauchst Du dann Fifos: vielleicht reichen die im CAN-Controller, vielleicht eigene im uC. Manche nur Zustände (den letzten, ältere überschreiben, dafür mehrere parallel), manche Aufträge (keiner darf verloren gehen)
@all vielleicht ist das von mir nicht richtig rüber gekommen. Das Senden und Empfangen seitens CAN funktioniert so weit sehr gut. Ich habe mich in die Thematik CAN-Bus eingelesen (darunter auch die Arbitrierung) und mich mit der von mir verwendeten Lib (Fabian Greif - kreatives Chaos) vertraut gemacht. Wahrscheinlich muss ich mich aber noch von der bis jetzt angewendeten Master-Slave-Kommunikation lösen, um die Vorteile von CAN besser nutzen zu können. Mein Problem besteht allerdings wie ich die empfangenen Daten am besten und effektivsten verarbeite. Ich möchte jetzt bewusst nicht mehr die Begriffe "Master" und "Slave" verwenden. Also, wenn ein Teilnehmer von verschiedenen anderen Knoten Daten erhält, wie realisiere ich dieses Handling am besten. Rolf hat mir hierzu einen guten Hinweis gegeben - die Queue. Könntest Du mir vielleicht ein kurzes Beispiel zukommen lassen? Ich hoffe ich konnte mich jetzt etwas klarer ausdrücken.
Zum Master/Slave wurde jaschon ausreichend gesagt dass dies bei CAN eher fehl am Platz ist. Markus W. schrieb: > Wie würdet ihr die Datenverarbeitung des Mastercontrollers am > effizientesten lösen? Der MCP2515 löst ja nach Empfang einer Nachricht einen Interrupt aus. Daraufhin liest man die Botschaft schnell aus und speicert diese in eine Zwischenspeicher. Bei jedem Durchlauf der Hauptschleife schaut man nun ein oder zweimal nach ob eine neue Botschaft im Zwischenspeicher liegt und wenn ja so arbeitet diese ab. So mache ich das jedenfalls.
Markus W. schrieb: > Mein Problem besteht allerdings wie ich die empfangenen Daten am besten > und effektivsten verarbeite. Lass einfach alle Knoten in einem festen Raster ihre Zustände (Taster etc) oder Kommandos (Rolladen, Licht) senden - pro Knoten möglichst alles in einer Botschaft. Ich schätze ein 20ms Raster sollte hier reichen und die uCs nicht überfordern. Für mich lesen sich deine Anforderungen so, als wäre eine Queue hier nicht erforderlich. Queues nutzt man, wenn jede einzelne Nachricht bearbeitet werden muss. Hier scheint es mir aber so als würde es ausreichen, wenn du nur jew. die aktuelle Nachricht bearbeiten musst: alle 10ms: CanDatenEinlesen(); Verarbeiten(); CanDatenAusgeben(); Wenn du keine Nachricht verpassen willst oder darfst: Lies im Interrupt die relevanten CAN Frames ein, schreibe sie in einen Ringbuffer und dann: CanDatenAusRingbufferVerarbeiten(); CanDatenAusgeben(); Anregung dazu: Nimm in jede CAN Botschaft einen Botschaftszähler auf. So merkst du, ob du eine aktuelle Botschaft verarbeitest oder eine ältere. Das kann aufgrund von Taskzyklus-Jitter vorkommen und ist absolut normal. Mit dem Zähler kannst du auch Ersatzreaktionen auslösen (Ausfall des Busteilnehmers). Wenn du über den Bus ein Protokoll fährst, kannst du so auch die Zustandsautomaten zurücksetzen. > Rolf hat mir hierzu einen guten Hinweis gegeben - die Queue. > Könntest Du mir vielleicht ein kurzes Beispiel zukommen lassen? Queue vs. Ringbuffer: Ich kenne nicht alle deine Anforderungen, aber im Normalfall nimmt man einen Ringbuffer. Wenn du mit einer Queue arbeitest, musst du Leser und Schreiber synchronisieren (Interruptsperre o.ä.). Wenn du einen Ringbuffer nimmst, müssen Schreiber und Leser nicht gegeneinander gesperrt werden, sofern die Ringbuffer-Implementierung etwas taugt.
Nachtrag: Wenn dein System hochläuft hat noch kein Knoten Daten empfangen. Daher solltest du einen Init-Zustand (never-received) festlegen, mit dem das System hochkommt und zu Beginn erstmal 100ms warten bevor du empfangene CAN-Daten verarbeitest. Wenn nach Ablauf der 100ms immer noch nichts empfangen wurde, kannst du in den Zustand Timeout wechseln und ggf mit Ersatzwerten arbeiten oder Ersatzreaktionen aufschalten - was auch immer in deinem Fall gerade sinnvoll ist...
Heinz schrieb: > Wenn du mit einer Queue arbeitest, musst du Leser und Schreiber > synchronisieren (Interruptsperre o.ä.). Wenn du einen Ringbuffer nimmst, > müssen Schreiber und Leser nicht gegeneinander gesperrt werden, sofern > die Ringbuffer-Implementierung etwas taugt. Das ist falsch. Beide Konzepte sind geeignet und Standard, um verschiedene Tasks zu synchronisieren. Der Unterschied: Queues händel in der Regel externe Speicherblöcke, die gesondert verwaltet werden müssen. Ring-Puffer sind direkt der Puffer, jedoch muss meist byteweise oder semiblockweise rein und rausgeschrieben werden. Sie sind daher eher für byteorientierte Kommunikation (seriell) geeignet. Bei CAN könnte der Ring-Puffer auch nachrichtenorientiert sein. Dann spricht man aber einfach von Fifo und kümmert sich nicht die Implementierung
Was mir auch schon geholfen hat: Anhand der Bitrate und Größe der Nachrichten ausrechnen, wie schnell Nachrichten überhaupt kommen können. Dann kannst du gegenrechnen, wie viel Zeit pro Nachricht für das Abholen über SPI verbraucht wird und wie viele CPU-Cycles du dann noch übrig hast zur Verarbeitung. Ich bin so teilweise zum Schluss gekommen, dass ich keine zusätzliche Empfangswarteschlange brauche und sogar auf das Abholen in der ISR verzichten kann. Dazu kommt, dass der MCP2515 2 Empfangspuffer hat und, sebst wenn beide voll sind, gleichzeitig noch eine dritte Nachricht empfangen kann.
A. S. schrieb: > Das ist falsch. Beide Konzepte sind geeignet und Standard, um > verschiedene Tasks zu synchronisieren. Queue: Beim Einhängen und ausklinken von Elementen aus einer Queue werden die Queuepointer auf Vorgänger- und Nachfolgerelement geändert. Prinzip-bedingt ist eine atomare Bearbeitung der Queuepointer nicht möglich. Daher muss synchronisiert werden (Interruptsperre, Semaphore, Spinlock..) Ringbuffer: Der Schreiber ändert den Schreibindex, der Leser ändert den Leseindex - keine Synchronisation erforderlich, sofern die Ringbuffer-Implementierung etwas taugt. Soweit mein langjähriger Kenntnisstand, aber ich lerne gerne dazu (keine Ironie!!). Kennt hier jemand eine Queue-Implementierung, bei der Leser und Schreiber asynchron laufen dürfen?
Heinz schrieb: > Queue: Beim Einhängen und ausklinken von Elementen aus einer Queue > werden die Queuepointer auf Vorgänger- und Nachfolgerelement geändert. Wieso Vorgänger? > Ringbuffer: Der Schreiber ändert den Schreibindex, der Leser ändert den > Leseindex - keine Synchronisation erforderlich, sofern die > Ringbuffer-Implementierung etwas taugt. Und wenn die Indizes gleich sind und somit der Schreiber den Eintrag verändert, den der Leser gerade liest? Oder der Leser liest schneller als der Schreiber schreibt? Mir ist nicht so ganz klar, wo für dich der fundamentale Unterschied zwischen einer Queue und einem Ringpuffer ist. Ich würde sagen, ein Ringpuffer ist eine gängige Art, eine Queue zu implementieren.
> Wieso Vorgänger? Ich ging von einer doppelt verketteten Liste aus, damit man vorwärts und rückwärts iterieren kann. > Mir ist nicht so ganz klar, wo für dich der fundamentale Unterschied > zwischen einer Queue und einem Ringpuffer ist. Queues sind für meine Begriffe flexibler. Man kann bspw. mitten drin Elemente einhängen oder entfernen. Der wichtigste Unterschied ist für mich aber: Ringbuffer können ohne weitere Synchronisation in ISRs befüllt und von anderer Stelle geleert werden, sofern die Implementierung etwas taugt.
Rolf M. schrieb: > Und wenn die Indizes gleich sind und somit der Schreiber den Eintrag > verändert, den der Leser gerade liest? Dann ist aus Sicht des Lesers der Ringbuffer noch leer. > Oder der Leser liest schneller als der Schreiber schreibt? Das sollte der Normalfall sein. Der Leser liest einfach, bis nichts mehr drin ist.
Wow, danke erstmals an alle, da waren jetzt sehr viele nützliche Infos und gute Tips dabei. Das hat wirklich sehr geholfen. Es gibt eurer Ansicht nach mehrere Wege, wie man die Verarbeitung lösen kann, was natürlich von der Menge der zu verarbeitenden Daten abhängig ist. Sollten meine Daten vielleicht mehr werden bzw. die Erfordernis eintreten, jede einzelne Nachricht bearbeiten zu wollen/müssen, müsste ich mir also Gedanken über eine gute Implementierung eines Ringpuffers machen. Kann mir vielleicht jemand von euch so eine Implementierung empfehlen, bzw. ein kleines Beispiel zukommen lassen, da ich auf diesem Gebiet überhaupt keine Erfahrung habe. Auf alle Fälle bedanke ich mich noch einmal recht herzlich für die zahlreichen tollen Tips von euch. Grüße Markus
Markus W. schrieb: > Sollten meine Daten vielleicht mehr werden bzw. die Erfordernis > eintreten, jede einzelne Nachricht bearbeiten zu wollen/müssen, müsste > ich mir also Gedanken über eine gute Implementierung eines Ringpuffers > machen. Dein CAN ist jetzt wie schnell? 100kBit/s? Licht- und Rolladen-Steuerung bedeutet das sind lange Strecken, also muss die Datenrate eher niedrig angesetzt sein. Edit: bäh, überlesen, also 125kBit/s. Überlegt mal, wie lange eine einzelne Nachricht auf dem Bus unterwegs ist. Eine 1-Byte Botschaft mit 11 Bit Identifier ist schon mindestens 44 Bits lang. Das sind 352µs bei 125kBit/s, weniger Zeit kann zwischen zwei CAN-Frames mit 1 Byte Nutzdaten gar nicht vergehen. Auch wenn ich jetzt ein Bit unterschlagen oder zwei zu viel habe, das ist selbst für einen Mega328 mit SPI-Nadelöhr dazu ziemlich viel. Klar kann man den SPI auch auf 1MHz oder gar niedriger einstellen, wenn man das unnötig langsam haben will. Ich kenne den MCP2515 nicht, ich habe nur gerade das Datenblatt auf. Nutzt man nur den /INT Pin braucht man wohl erst ein Read Status Kommando, das sind zwei Bytes auf dem SPI. Ein Byte Nutzdaten zu lesen mit dem Read RX Buffer Kommando sind auch wieder nur zwei Bytes auf dem SPI. Also selbst bei 1MHz auf dem SPI sollte das in <33µs durch sein. Nutzt man /RX1BF und/oder /RX0BF braucht man das Status Register nicht. Edit: ist der Empfangs-Puffer völlig offen braucht man noch die ID, okay, das sind dann 7 Bytes auf dem SPI, Kommando und lesen von RXB0SIDH bis RXB0D0. Bei 1MHz SPI so um die 60µs. So langsam wie das ist könnte man auch alle 250µs oder so das Status Byte pollen und ohne Empfangs-Interrupt auskommen.
:
Bearbeitet durch User
Danke Rudolf auch für Deine sehr umfangreiche Erklärung. So wie ich das lese, gehe ich davon aus, dass Du der Meinung bist, dass ich hier ohne Ringpuffer auskomme.
Naja, Anforderungen bestimmen, Nachrechnen, Implementieren, Testen. Interessant ist da noch was so ein Controller noch so machen soll und wie viel Overhead die wofür-auch-immer-überhaupt "libs" verursachen. Der SPI von dem Mega328 läuft mit 8MHz, der MCP2515 kann das auch und mit mehr als einem Datenbyte auf dem CAN wird es tendenziell auch nicht schlimmer.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.