8 Io´s auf 1 Byte zusammenfassen.

Hi zusammen

Wollte fragen ob jemand eine Idee hat wie man 8 digitale Eingänge auf ein Byte zusammen fassen kann und diese dann per UDP Befehl (wogegen das UDP Befehl senden nicht das Problem darstellt) zu versenden.

Als Beispiel: Nehmen wir mal an ich hab auf den Inputs eines Boards Fenstekontakte

Fenster Zustand Bit 1 geschl 0 2 offen 1 Würde ich diese Bits von oben nach unten in ein Byte konvertieren 3 geschl 0 Hätte ich ja die Zahl 2 4 geschl 0 5 g 0 6 g 0 7 g 0 8 g 0

Fenster Zustand Bit 1 geschl 0 2 offen 1 Würde ich diese Bits von oben nach unten in ein Byte konvertieren 3 offen 1 Hätte ich wieder um die zahl 142. 4 offen 1 5 g 0 6 g 0 7 g 0 8 g 1

Könnte ich nun Je einen UDP Befehl senden pro byte also 1. Befehl = 2 dann 2. Befehl = 142. Wenn ich diese 2 Bytes ind einem anderm Controller, System, Server oder wer auch immer UDP Befehle empfangen kann. Diese 2 Bytes dann wieder in diesem System, falls möglich, wieser zurückverwandeln dann hätte ich 16 Zustände mit 2 UDP Befehlen gesendet was meine Empfangsgerät sehr begrüßen würden, denke ich.

Bitte keine Belehrungen wie ich das mit Kabellänge und so machen will. Ich weß da alles drüber und hab schon ne Selbestgebastelte Lösung mit OK´s welche schon seit Jahren fehlerfrei (abgesehen tausch von einem OK für 0,70, den ich aufgrund von Mehrkauf bei dem Preis sofort verfügbar hatte.) Der Aufbau ist selbst für einen Laien durchzufüren.

Und wie gesagt hat seine Stabilität schon lägst bewiesen.

Wäre Euch also sehr dankbar für Hilfe bei dem oben Beschriebene Problem. Vieleicht eine kann jemand eine Lösung posten, falls jemand eine hat. Bin für jeden Vorschlag dankbar auch für Ideen!

Grüße Stefan

Schau dir mal BitSet() bitClear() bitWrite an

http://arduino.cc/en/Reference/BitSet http://arduino.cc/en/Reference/BitWrite http://arduino.cc/en/Reference/BitClear

Würde dir gerne das Beispiel dazu raussuchen, was ich mal in einem Projekt für eine Fernbedienung hatte, jedoch finde ich das hier im Forum nicht wieder.

Nachtrag, gefunden ;) http://forum.arduino.cc/index.php?topic=216685.15

byte readRPB() {
    byte sendByte;

    //Codierung 3
    bitSet(sendByte, 0);    // 1
    bitSet(sendByte, 1);    // 1
    bitClear(sendByte, 2);  // 0
    bitClear(sendByte, 3);  // 0

    bitWrite(sendByte, 4, ps2x.Button(PSB_TRIANGLE));
    bitWrite(sendByte, 5, ps2x.Button(PSB_CIRCLE));
    bitWrite(sendByte, 6, ps2x.Button(PSB_CROSS));
    bitWrite(sendByte, 7, ps2x.Button(PSB_SQUARE));

    return sendByte;
}

Waren nicht zwingend die besten Code Snippets dabei, aber ich denke man kann erkennen worum es geht. Hier ging es um einen PS2 Kontroller auswerten und die Tasterwerte über Bluetooth an einen Atmega zu senden. Die obersten 4 Bit waren für die Codierung damit ich die am Master zu ordnen konnte.

Hallo,

ich denke die beste Methode ist, eine Art Schieberegister für das benötigte Byte zubauen.
Mit den besagten Befehlen bitSet/bitClear geht das zwar auch, aber dann muß man immer unterscheiden, was rein kommt, entweder eine 0 oder eine 1 und dann den Befehl entsprechend wechseln. Macht auch Aufwand.

Ich habe mir für meine DS3231 eine Funktion gebaut um in irgendwelchen Bytes bestimmte Bit’s einzeln zu ändern. Laut meiner Meinung ist die universeller. Ich denke das wird Dir helfen. Wenn Du nachvollziehen kannst wie das funktioniert, wäre auch ich fröhlich. :wink: Ich denke die Bsp. Rechnung Kommentare dahinter sagen alles.

Deine Fensternummer wäre die “BitPosition” und der Fensterzustand der “BitWert” zur Übergabe

byte modifiziere_Byte (byte ByteVar, byte BitPosition, byte BitWert)
{
  byte Bitmaske = 0;
  
  if (ByteVar > 0xFF | BitPosition > 7 | BitWert > 1)  {  // grobe Plausibilität Prüfung
    Serial.println(F("falsche Parameterübergabe"));
    return ByteVar;    // Abbruch ohne Änderung
  }  
  
  if (BitWert == 0)  {             // Bsp. ByteVar ist            0b10101010                      
    Bitmaske = 1 << BitPosition;   // Bitmaske erstellen          0b00100000  (Bit 5 soll 0 werden)
    Bitmaske = ~Bitmaske;          // Bitmaske komplett negieren  0b11011111
    ByteVar = ByteVar & Bitmaske;  // UND Verknüpfung, Ergebnis   0b10001010
  }  
  
  if (BitWert == 1)  {             // Bsp. ByteVar ist            0b10101010       
    Bitmaske = 1 << BitPosition;   // Bitmaske erstellen          0b00000100  (Bit 2 soll 1 werden)
    ByteVar = ByteVar | Bitmaske;  // ODER Verknüpfung, Ergebnis  0b10101110
  }   

  return ByteVar;
}

Die byte Prüfung ob ByteVar > 0xFF ist, ist zwar etwas sinnlos, zugegeben, aber vielleicht für spätere Funktionsmodifizierungen oder Wertebereiche noch sinnvoll. :slight_smile:

Doc. hast du dir mal die Funktionsparameter von bitWrite angeschaut :sweat_smile:

Alternativ kann man das ganze aber auch noch ganz anders schreiben, so wie es in AVR-GCC meist üblich ist. Kommt auf selbe Dort ua. beim direkten Portzugriff ganz hilfreich. http://openbook.galileocomputing.de/c_von_a_bis_z/006_c_operatoren_005.htm#ix52a10106c9ec84c3ca0a914bc8d463f4

sschultewolter:
Alternativ kann man das ganze aber auch noch ganz anders schreiben, so wie es in AVR-GCC meist üblich ist.

Meistens macht man sich Makros dafür. Und das sind dann mehr oder weniger die selben die die Arduino IDE schon hat:

#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))

Der einzige Vorteil das selbst zu machen ist vielleicht das der Code ein klein wenig kompakter wird wenn man auf das UL verzichtet und statt dessen mit Bytes arbeitet. Wobei man auch das casten sollte, da standardmäßig int verwendet wird:
http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_intpromote

Moin Moin

Danke für die Antworten werde ich heute nach der Arbeit gleich ausprobieren. Gestern war gar nichts mehr möglich war total am Ende.

Grüße Stuff

Hallo,

Du meinst das ist fast das selbe? Kann sein, dafür ist meine Funktion selbst gemacht. :) Hatte paar Nächte gedauert, wegen der Bitmaske erstellen und der richtigen Verknüpfung. Ich finde meine Funktion schön und gelungen. :)

Was meinst Du mit Byte casten? Immer diese Fremdwörter. :(

BitSet und BitClear geht natürlich auch. :) Man muß aber auch hier immer erst unterscheiden was man nimmt, also ob eine 0 oder 1 rein soll und dann den richtigen Befehl verwenden.

Hallo,

hab ich dich richtig verstanden das du jeweils 8 Eingänge zu einem Byte zusammenfassen möchtest? Wenn ja, nutz doch einfach die Ports des AVR. Eingänge werden vom Controller doch sowieso immer nur Portweise zu je einem Byte gelesen. Du schaust einfach im Arduino Schaltplan nach welche Ausgänge auf welche AVR Ports geschaltet sind, nutz diese und liest einfach mit den Normalen AVR C Befehlen die Ports ein. Dann hast du die Automatisch in Byte. Das ist das doch das Grundwerkzeug was man für die µC’s braucht. Hoffe ich habe dich da nicht falsch verstanden, bin bisll irritiert weil hier alle mit BitWrite, BitSet und sowas kommen. Ein einfaches:

#include <avr/io.h>


uint8_t a = PINB;
uint8_t b = PINC;

sollte doch reichen um jeweils die IO’s von PORTB und PORTC einzulesen. Oder habe ich da was übersehen? Die Grundlagen gibt es hier:

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial

MFG

His

Hallo,

das mit dem gesamten Port ist keine schlechte Idee. Vorraussetzung man hat einen kompletten Port als Eingänge frei. Beim Uno geht das nur mit Port D, Pin 0 bis Pin 7. wenn man Pin 0 und 1 mit verwendet. Da muß man dann aufpassen was man macht. Geht aber. Beim Mega2560 hätte man mehr Möglichkeiten mit komplett freien Ports.

Mit der Bit-Schupserei kann man irgendwelche Eingänge zusammenwürfeln zu einem Byte. Man muß nicht zwingend einen kompletten Port frei haben. Das wäre der Vorteil für den Aufwand.

Hmm, ok, das die ports nicht frei sind hatte ich jetzt garnicht bedacht, da ich bei solchen Anwendungsfällen immer auf eine eigene Schaltung zurückgreife. also ich entwickle Testweise mit nem Mega und baue dann eine Schaltung für genau diesen Anwendungfall auf. Also meine fertigen Schaltungen laufen dann ohne Arduino mit eigenem µC.

Hallo alle

@Hiswif: Nein da hast Du mich nicht falsch verstanden. Und 'Deine Lösung ist die Eleganteste sowie für mich als Arduino Anfänger auch am Einfachsten zu verstehen. Also wenn ich Dich richtig verstanden habe dann wäre beim mega PB0 bis PB7 ein byte bzw eine Speicheradresse (bei uint_8 wäre das dann ja 1Byte) im Arduino, PC0 bis PC7 (am Mega dann Pin 37-30), PD0 bis PD7 usw usw oder?

Hallo,

genau. Beim Mega2560 sehe ich mehrere komplett freie Ports.

Port.A: Pin 22 ...29 Port.C: Pin 30 ... 37 Port.L: Pin 42 ... 49 Port.F: Pin A0 ... A7 Port.K: Pin A8 ... A15

Port.B wäre noch frei, wenn man kein Hardware SPI nutzt.

Guck mal in die pighixxx Pinout Übersicht. Beitrag #22. http://forum.arduino.cc/index.php?topic=259877.new;topicseen#new

Hallo alle!

Ja dass ich nicht alle verwenden kann ist mir schon aufgefallen aber beim Mega gibts ja genug freie pins und ports. Sry wenn ich etwas blöd frage aber ich würde es gerne verstehen und nicht nur dumm abtippen.

Also meine Frage ist das ganze kommt natürlich in den Deklarationsteil des Sketches ist klar und um beim Beispiel zu bleiben heißt: uint_8 a = PINB ist eine Variable mit dem Namen a ist auch klar und PINB bezieht sich direkt auf die Eingangspins PB0-PB7. Wenn ich jetzt uint_8 i = PINL würde sich das zusammengesetzte byte, namens i, aus den Eingangspins PL0-PL7 bilden, habe ich das richtig verstanden? Davon dass die pins eventuell für andere Funktionen benötigt werden mal abgesehen.

Danke für die Hilfe und viele Grüße

Noch eine Frage.
Die Pins sind ja standardmäßig als Eingänge definiert. Wenn ich jetzt mit den verwendeten Eingängen im Arduino keine Logik ausführen möchte, sondern nur den Status an einen anderen Controller senden will.
Genügt es dann die Variable zu deklarieren oder wird dann ein Syntax auch noch benötigt?

Hallo,

uint_8 a = PINB; bzw. uint_8 i = PINL; ist richtig verstanden von Dir. Es wird immer das volle Register vom Port eingelesen. Alle 8 Bit oder anders gesagt, alle 8 Eingänge vom Port.

Deine letzte Frage verstehe ich nur teilweise.

Wenn die entsprechenden Pins Eingänge bleiben, ohne der Nutzung der µC eigenen Pullup Widerstände, dann reicht es aus mit obigen Befehlen den Portzustand einzulesen.

Syntax ist übrigens alles was Du schreibst in der IDE. Und wenn man die Befehle so schreibt wie es der Compiler haben möchte und versteht, dann erhält man auch keine Syntaxfehler. Du meintest bestimmt ob Du noch etwas definieren mußt.

Ja genau, laut Arduino Datenblatt sind ja alle Pins standardmäßig als Eingänge deklariert. Muss ich dann im Setup noch ein Array für die entsprechenden Pins anlegen oder reicht es den Port nur auszulesen? Und danke für die Erklärung mit Syntax, wußte ich auch nicht.

Grüße Stefan

Dann musst du sonst nichts machen

Wenn du die Richtung eines gesamten Ports ändern wolltest, kannst du das aber auch bequem mit dem DDR Register machen (Data Direction Register): 1 = Ausgang, 0 = Eingang.
Das ist auch der Grund weshalb die standardmäßig Eingänge sind. Alle Register sind anfangs mit 0 initialisiert (wobei die Arduino Software da am Anfang viel im Hintergrund macht)

Dann gibt es noch das PORTn Register für Ausgänge

Tip: eine 1 auf das Eingangsregister PINn zu schreiben ist der schnellste Weg einen Pin zu toggeln

Moin moin

Funktioniert tadellos dank Eurer fleißigen Hilfe. Dass nenn ich ne Codeverkürzung, spitzenmäßig vor allem kann ich jetzt mit 4 UDP Befehlen alle Eingänge, die ich im anderen Controller benötige, übermitteln.

Schöne Grüße Stefan

Freut mich das es jetzt bei dir läuft. Von der Theorie her könntest du den Code sogar noch weiter einkürzen. Du musst die Ports vor dem versenden eigentlich nicht in Variablen speichern sondern könntest sie auch direkt versenden. PseudoCode:

UDP.send(PINX);
UDP.send(PINY);

Ist jetzt nur Pseudocode, da ich nicht weiß was du für das UDP für funktionen hast, aber vom Prinzip her sollte das möglich sein.