www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Protokoll einbinden AVR


Autor: Phillip Hommel (philharmony)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin, ich möchte verschiedene Boards bauen mit denen ich per UART mit 
dem PC kommuniziere.
Dazu haben wir uns ein einfache Protokoll ausgedacht:

Adresse
Flag für "jetzt kommen Daten" oder "Jetzt kommt ein Command"
Startbyte
Entweder Data 1 oder Command
Entweder Data 2 oder Value
...
Endbyte

Funktioniert auch wunderbar, allerdings habe ich das ganze auf dem Atmel 
so implementiert, daß der Empfang Interruptgesteuert ist, und dann per 
Switch-Abfrage abhängig von einem Empfangszähler entschieden wird was 
ich mache (siehe code)
//USART-Empfangs Interrupt Handler
ISR(USART_RX_vect)
{
unsigned char puffer=UDR;    //als erstes das USART Data Reg leeren
  switch (RX_count)      //was gemacht wird hängt davon ab, was im wievielten byte steht
  {
    case 0 : if (puffer == adress) //wenn byte die richtige adresse zeigt
      {RX_count++;         //ist das ganze gültig und der zähler wird um 1 erhöht
      break;}             //break damit die anderen cases nicht ausgeführt werden
       else break;           //wenn nicht die adresse, dann wird verworfen
    case 1 : if (puffer == flag_control) //wir nehmen in diesem board nur controls an
      {RX_count++;        //dann gehts weiter
      break;}
      else            //sonst wird verworfen
      {RX_count = 0;
      break;}
    case 2 : if (puffer == flag_begin_of_data) //dann MUSS BOD kommen
      {RX_count++;
      break;}
      else
      {RX_count = 0;          //alles andere wird verworfen
      break;}
    case 3 : if (puffer == flag_command_reset)  //wenn jetzt ein reset verlangt wird
      {RX_command = flag_command_reset;    //wird das vorgemerkt
      RX_count++;                //und weiter gehts
      break;}
      else if (puffer == flag_command_send_again) //oder es wird ein erneutes senden gewollt
      {RX_command = flag_command_send_again;    //auch das wird gemerkt
      RX_count ++;
      break;}
      else
      {RX_count = 0;                //alles andere wollen wir nicht
      break;}
    case 4 : if (puffer == flag_end_of_data)    //nur wenn jetzt noch das EOD kommt
      {if (RX_command == flag_command_send_again) send_data(); //wird neu gesendet
      else if (RX_command == flag_command_reset) reset();    //oder resettet
      break;
      }
      else
      {RX_count = 0;    //sonst wird wieder verworfen
      RX_command = 0;    //und das vorgemerkte command gelöscht
      break;}
    default: 
      {RX_count = 0;   //wird ein anderer zählerstand erreicht stimmt was nicht
      break;}      //dann wird er auf null gesetzt. Sollte es nötig sein könnte man
  }            //hier auch noch das board resetten...
}              //außerdem könnte man ein timeout zwischen zwei RX-Vorgängen starten
              //der jedesmal wieder gestartet wird und bei ablauf alle daten verwirft
              //und eine meldung abschickt

Dieses Board kann jetzt aber auch nur die beiden Commands reset und send 
again, andere dagegen sollen deutlich mehr Commands verarbeiten und 
zusätzlich noch Daten empfangen.
Daher meine Frage, ob das ganze auch irgendwie eleganter geht, mit 
weniger Text.

Btw, kann man eine Switch-Abfrage auch in Bereiche einteilen?
Also
Switch (irgendwas)
{
case 1: blabla;
case 3 bis 27 blablabla;
case 28: blubb;
default : nochwasanderes;
}
?

Grüße
Phil

Autor: rene (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, das macht man so. Als PC Beispiel :
http://www.ibrtses.com/embedded/shortmsgprotocol.html

Man kann immer weniger schreiben. Es gibt Leute die schreiben alles auf 
eine Zeile...

Autor: rene (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Phillip Hommel (philharmony)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, vom reinen Protokoll her ist das ja im Prinzip das, was wir auch 
machen, außer daß wir keine CRC bilden, weil diese nach bisherigen 
Versuchen nicht notwendig war (hatten noch nicht einen einzigen 
Übertragungsfehler).
Allerdings setzt Dein Beispiel vorraus, daß der Slave nicht von sich aus 
sendet sondern nur auf Abfrage reagiert, was in unserer Anwendung aber 
nicht sinnvoll ist.
Meine Frage bezog sich eher darauf, wie man am geschicktesten im Source 
des Controllers die Empfangs-interrupt.routine so kurz wie möglich hält 
und darin die Kontrolle der ankommenden Bytes ermöglicht.
Wenn ich jetzt Daten mit 256 Bytes empfange, dann möchte ich ja nicht 
eine 256-Stellige Case-Abfrage schreiben die 253mal den selben Inhalt 
hat.
Das Board um das es Aktuell geht hat zwei extensions, einmal eine mit 32 
8bit Output-Treiber-Schieberegistern um LEDs oder andere Lasten 
anzusteuern, das andere Board hat 32 8bit input schieberegister wo 
diverse Schalter und ein Paar andere Logiken angeschlossen sind.
Das Board soll nun kontinuierlich die Schalter-Extension auslesen und 
bei veränderung die seit dem letzten senden veränderten Bits im Format 
[Bitnummer] [new value] sofort und selbständig an den Rechner senden.
Da sich durch die Logiken auch mehrere Bits verändern können, ist dieser 
String verschieden lang.
Gleichzeitig soll das Bitweise empfangene im Controller zum 
ensprechenden String zusammengebaut werden, bzw in Sequenz sinnvoll 
ausgewertet werden und die AUsgangsextension bei veränderung 
entpsrechend neu angeseteuert werden um eben die LEDs leuchten zu lassen 
oä.
Das Ankommend eist eben auch im Format [adresse] [announce daten] 
[startbyte] [bitnummer] [new value]...[endbyte]...

Autor: 6635 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine Statusmaschine im Interrupt dauert nicht laenger, nur weil's viel 
Text ist. Das wird ein Register gelsen, eine Wert in eine Sprungtabelle 
eingegeben und dann noch ein paar Instruktionen. Man muss den jeweile 
laengsten Pfad im Auge haben, sowie dessen Haeufigkeit. Der laengste 
Pfad limitiert die Interrupt rate.

Autor: Phillip Hommel (philharmony)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, das macht sinn.
Das heißt mit der Case Abfrage bin ich auf dem Richtigen Kurs?
Kann ich denn darin nun Bedingungen zusammenfassen?
Also "case (2 bis 17) : ... " ?

Autor: 6635 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ueblicherweise nicht, dh so wie ich C kenne nicht. Das ist eine Frage 
des Compilers. Wenn eine Sprungtabelle verwendet wird, was am 
schnellsten ist, dann sollten nicht zuviele Eintrage nichts enthalten. 
Was gehen sollte, ist eine Aufzahleung anstelle eines Bereiches. Dh

Switch (irgendwas)
{
case 1: blabla; |
case 3,
case 4,
case 5,
..
case 27 :blablabla; |
case 28 : blubb; |
default : nochwasanderes; |
}

Die andere Moeglichkeit ist den Switch als repetitiven If else zu 
implementieren, und dann ist vieles mehr moeglich, auch nicht-ordinale 
Vergleiche.

Autor: PP (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nimm einfach eine extra Variable für die Statemachine (em besten per 
enum :).
Da hast dann die verscheidenen Zustände (zB Adresse, Datenlänge, Daten 
Empfangen, Ende, Warten auf Daten) und für jede  ein case.

Autor: 6635 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So ganz nebenbei. Falls ein Protokoll nicht Master-Slave ist, kann es 
Kollisionen geben. Die muss man detektieren koennen. Dann ist ein CRC 
schon Pflicht, da eine Kollision sich als CRC Fehler bemerkbar machen 
koennte. Falls nun von gleichwertige Teilnehmern eine Kollision 
detektiert wurde muss es weitergehen. Da braucht es Konzepte. zB eine 
zufaellige verzoegerte Wiederholung.

Autor: Phillip Hommel (philharmony)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach ja, logisch, ich kann ja alle ereignise von x bis y einfach ohne 
break aufzählen, dann fallen sie einfach bis y durch und dann wird y 
ausgeführt klick ;)

Aber warum es zu kollisionen kommen sollte verstehe ich noch nicht so 
ganz.
Selbst wenn der Controller etwas vom PC empfängt während er etwas 
sendet, der USART ist ja eh Hardware, arbeitet also auch bei einem 
Interrupt seine Aufgabe ab.
Der Empfang dauert jeweils nur ein byte, bei 4mhz Controllertakt und 
115200 Baud ist das so kurz, daß in der Zwischenzeit wieder gut ein 
Stück weitergearbeitet wird bevor evtl wieder ein neues Byte ein 
Interrupt auslöst.
Der Timeout vom PC UART sollte doch lang genug sein, und wenn nicht: den 
Fall fange ich ab.
Oder mache ich hier einen Denkfehler?

Autor: rene (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Master-Slave bedeutet der Master, meist der PC, bestimmt die 
Kommunikation, Saemtliche Kommunikation wird vom Master initiiert, der 
Slave antwortet nur. Dies ist relativ einfach zu implementieren, ist 
aber nicht in allen Faellen geeignet. Bei gleichwertigen 
Kommunikationspartnern gibt es zwei Moeglichkeiten, Das 
Kollosionsdetektion/Retry oder das Token Verfahren. Beim ersteren blaest 
jeder mal seine Nachricht raus und versucht eine Kollision zu 
detektieren. Bei einer Kollision versuchen es beide an der Kollision 
beteiligten Partner eine zufaellige Zeit spaeter nochmals. Beim Token 
verfahren bestimmt ein Faehnchen (Token) wer senden darf, und das 
Faehnchen wird im Kreis rum gegeben. Das Tokenverfahren hat die bessere 
Auslastung der Bandbreite ist aber aufwendiger zu implementieren. zB 
muss das Token regeneriert werden falls es verloren geht.

Autor: Phillip Hommel (philharmony)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, das ist mir soweit klar, aber der UART is doch duplex-fähig,
warum sollte es da zu kollissionen kommen?

Autor: rene (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Na, wenn zwei Stationen gleichzeitig senden gibt es eine Kollision. 
RS232 ist uebrigens nur punkt-zu-punkt. Das geht hier nicht, Ein 
Standardansatz is RS485 und das ist nur halb duplex. Ein RS422 waere 
fullduplex und busfaehig. Es wird fuer Master-Slave auch verwendet, bei 
multimaster hat man aber die Schwierigkeit welche Richtung nun verwendet 
werden soll.

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ein Standardansatz is RS485 und das ist nur halb duplex.
Richtig.

>Ein RS422 waere fullduplex und busfaehig.
Nö, RS422 ist RS232 symmetrisch/differentiell.
Fullduplex schon, aber auch nur Punkt zu Punkt.


Es gibt noch RS485-4-wire. Das ist ein fullduplex-Bus.

Autor: 6635 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
RS422 is Busfaehig. Ein Paar geht in die eine Richtung, das andere Paar 
geht in die andere Richtung. Eben fuer Master-Slave. Der nicht sendende 
Slave schaltet seinen Transmitter Tristate.

Autor: JojoS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
eine Prüfsumme macht auch bei einer einfachen RS232 Sinn weil die 
Verbindung damit robuster wird. Wenn Müll übertragen wird weil z.B. die 
Bitraten nicht richtig stehen können zufällig falsche Kommandos 
ausgelöst werden. Und auch wenn die Stecker abgezogen oder aufgesteckt 
werden können Zeichen generiert werden die als Fehler erkannt werden 
müssen. Noch sicherer wird es wenn man ein Timeout für eine Message 
implementiert um zu verhindern das unvollständige Telegramme die 
Schnittstelle blockieren.

Autor: Phillip Hommel (philharmony)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, dann füg ich das mal meinem Wissen hinzu ;)
Wie gesagt, bei bisherigen Anwendungen war es nicht nötig weil bei 
vielen Tausend versendeten Paketen nicht ein einziger Fehler aufgetreten 
ist.
Sollten sich im Betrieb aber welche zeigen, ist unser System flexibel 
genug um nachträglich diverse Prüf- und Sicherungsverfahren einzubauen.
Danke erstmal für die vielen Tips und Hinweise.
Grüße
Phil

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>RS422 is Busfaehig. Ein Paar geht in die eine Richtung, das andere Paar
>geht in die andere Richtung. Eben fuer Master-Slave. Der nicht sendende
>Slave schaltet seinen Transmitter Tristate.

Nö...
http://de.wikipedia.org/wiki/RS422
Das was du beschreibst, ist der RS485-4-Wire-Bus.
RS422-Transceiver haben keine Richtungspins.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  6635 (Gast)

>RS422 is Busfaehig.

Nope. du verwechselst das Mit Multi-Drop. Ein Sender, mehrere Empänger. 
DMX wäre somit klassisches RS422, auch wenn es oft als RS485 bezeichnet 
und realisiert wird. Die Unterschiede sind eher gering.

http://www.maxim-ic.com/appnotes.cfm/appnote_number/723/

MfG
Falk

Autor: 6635 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja. wie auch immer. Ich empfehle den ADm489 Treiber fuer Master-Slave, 
aka multidrop. Kostet um die 1.10 @ 100. Fuer Multi Master geht der 
nicht.

Autor: Phillip Hommel (philharmony)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für meine Anwendung aber alles etwas sehr überdinemsioniert ;)
Es geht um ca 200 Schalter und 200 Lampen...

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Phillip Hommel (Firma hs-bremen) (philharmony)

>Für meine Anwendung aber alles etwas sehr überdinemsioniert ;)

Was ist daran überdimensioniert? Ein kleiner 8 Piner und gut ist.

>Es geht um ca 200 Schalter und 200 Lampen...

Ja eben! Und da die sicherlich räumlich etwas auseinander liegen, 
sollte man einen robusten Kommunikationsstandard wählen. RS485.

MFG
Falk

Autor: 6635 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja. Ohne RS485 geht's nicht. Da kann man den ADm483 fuer 1.14 @100 (auch 
dollar) nehmen. Ein Tiny26 oder so dazu und gut ist.

Autor: Phillip Hommel (philharmony)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nope, liegen alle auf einem Panel, werden von 2 Man bedient und in 
ersten Versuchen ging es mit RS232 Fehlerfrei.
Direkt auf der Plattine mit dem Atmega ist auch ein FTDI UM232R-Modul 
dran, von da an ists eh ne USB-Leitung.
Die eigentlich Leitung wo ich 5V UART betreibe ist ca 5cm Lang.
Meine Frage bezog sich wirklich nur darauf, wie ich die Abfrage des 
Protokolls eleganter Lösen kann.

Autor: 6635 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit RS232 kann man aber keinen Bus bedienen. Allenfalls kann man auf 
einer Leiterplatte die Signale in TTL-Level fuehren, und die nicht 
betroffenen Tristaten. 200 Stueck benoetigen aber satte Bustreiber. HC 
oder TTL alleine ist nicht genug.

Autor: Phillip Hommel (philharmony)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
???
Die RS 232 bedient auch nicht den BUS sondern schickt dem ATmega nur ein 
Paar Daten, welche der Schieberegister er wie setzen soll.
Wie gesagt:
ES FUNKTIONIERT GENAU SO!!!! Ich weiß das weil ichs aufgebaut habe und 
es tadellos sendet und empfängt.
Ich wollte nur wissen ob man das PROTOKOLL anders einbinden kann bzw man 
den switch-Befehl optimieren kann.
Alles andere ist doch schon lange gelöst...

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Phillip Hommel (Firma hs-bremen) (philharmony)

>Ich wollte nur wissen ob man das PROTOKOLL anders einbinden kann bzw man
>den switch-Befehl optimieren kann.

Kann man. Erstmal das Startbyte erkennen, dann immer die Daten in einen 
Puffer schreiben bis das Endzeichen erkannt wird. Dann erst den 
empangenen String/Datenblock dekodieren.

MFG
Falk

Autor: Phillip Hommel (philharmony)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Falk,
Danke, macht Sinn!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.