Bit... Byte... serial übertragen

Moin,

ich habe hier einen Deltang TX1-K1 2,4GHz RC Sender.

Diesen muss per serial die einzelnen Poti und Schalter Positionen bekommen.
Aber hier hab ich ein Verständnis Problem.
In der Beschreibung steht

Byte 1 Checksum (sum of bytes 2-16 cast to 1 byte)
Byte 2 Not used (can be any value)
Bytes 3-16 2 bytes per channel with following struc
ture 0b000 CCC 9876543210

  • 000 = not used (normally zeros)
  • CCC = channel number (0=Thr, 1=Ail, 2=Ele, 3=Rud,
    4=Gear, 5=Aux1, 6=Aux2)
  • 9876543210 = 10bit channel position
    DT receivers with a serial output can be used to pr
    ovide an input to Tx1 for testing.

Dort steht ja immer was von Byte aber sind das nicht alles Bits,
Denn Zusammen (so wie ich es versteh sind es 16 Bits also 2 Byte oder ein Word)
Also wäre der komplette Datenstrom für Kanal 3=Rud in Mittlerstellung z.b. so
000 unbenutzt
010 für Kanal 3
100000000 512 für die Mittelstellung (0-1023)

Oder hab ich da einen Denkfehler?
Und wo kommt da jetzt die Checksumme hin?

Gruß Ingo

Die Checksumme ist die Summe aller Bytes auf Byte gecastet

Wenn man die Daten mal in Gruppen von 4 Bit aufspaltet sieht man etwas besser was was ist:
000C CC98 7654 3210
Also bekommst du die Nutzdaten einfach so:

byte high = ...;
byte low = ...;
unsigned int data = word(high, low);
data = data & 0x03FF;

Das & am Ende setzt die oberen 6 Bits auf 0

Das hat man dann 7 mal für alle Kanäle. Also 1 + 1 + 7 * 2 = 16 Bytes

Hi,
für mich sieht das so aus als ob bei jedem Sendevorgang alle 16 Byte übertragen werden müssten.

Soll heisen:
-Übertragung initalisieren
-Sende Byte 1 -> erwartete Checksumme der Bytes 2-16
-Sende Byte 2 -> ---
-Sende Byte 3 + Byte 4 -> Kanal 0 (Thr)
-Sende Byte 5 + Byte 6 -> Kanal 1 (Ail)
-Sende Byte 7 + Byte 8 -> Kanal 2 (Ele)
-Sende Byte 9 + Byte 10 -> Kanal 3 (Rud)
-Sende Byte 11 + Byte 12 -> Kanal 4 (Gear)
-Sende Byte 13 + Byte 14 -> Kanal 5 (Aux1)
-Sende Byte 15 + Byte 16 -> Kanal 6 (Aux2)
-Übertragung beendet

  • Checksum erzeugen
  • Checksum vergleichen

Dein Telegramm sähe dann in etwa so aus:
Byte 1 -> die Checksumme
Byte 2 -> beliebiger Inhalt
Byte 3 + Byte 4 -> beliebiger Inhalt
Byte 5 + Byte 6 -> beliebiger Inhalt
Byte 7 + Byte 8 -> beliebiger Inhalt
Byte 9 + Byte 10 -> 000 011 1000000000
Byte 11 + Byte 12 -> beliebiger Inhalt
Byte 13 + Byte 14 -> beliebiger Inhalt
Byte 15 + Byte 16 -> beliebiger Inhalt

Gruß,
Fennek

Hallo Fennek,
Danke für deinen Antwort.
Kling zu mindestens einleuchtend.

Ich habe das mal zum Teil in ein Beispiel umgesetzt.

int test; 
byte hi, lo; 
byte dumy = 0; // für Beyt 2 

//diese Werte müssen zum highByte dazu gerechnet werden (4=Kanal 1,... 28=Kanal 7) um den Kanal zu bestimmen.
int kanal[7] = {4, 8, 12, 16, 20, 24, 28};  
void setup(){
Serial.begin(9600);
}

void loop(){
   

  for (int i=0; i <= 6; i++){
    test=random(0, 1023); //zufallswert für die einzelnen Kanäle
    hi = highByte(test);  //in case you're wondering this should be 0xA
    lo = lowByte(test);    // and this should be 0xB. 
    hi=hi+kanal[i];
    Serial.print(hi, HEX);
    Serial.println(lo,HEX);
   } 

delay(1000);
Serial.println("#######");
}

Nun ist die Frage, ob ich das so richtig umgesetzt habe und wie erstelle ich jetzt die Checksumme?

Gruß Ingo

Oops, was ich oben geschrieben habe war für Empfangen. Er jetzt richtig kapiert, dass es nur ums Senden geht :frowning:

Die Kanal Nummer kann man sehr viel einfacher mit Bit-Schieben hinzufügen

byte high = 0x03;

for(int i = 0; i < 7; i++)
{
  byte val = (i << 2) | high;
  Serial.println(val, BIN);
}

Ergebnis:

00000011
00000111
00001011
00001111
00010011
00010111
00011011

Binärdarstellung mit BIN statt HEX hilft vielleicht auch

Insgesamt dann:

void loop()
{
   byte data[16];
   data[1] = 0;

   for(int i = 0; i < 7; i++)
   {
       unsigned int value = random(0, 1024);    //der zweite Parameter ist bei rnd() Funktion meistens exklusiv!

       byte high = highByte(value) | (i << 2);
       byte low = lowByte(value);

       data[i * 2 + 2] = high;
       data[i * 2 + 3] = low;

       Serial.print(high, HEX);
       Serial.println(low, HEX);
   }

    delay(10000);
}

Die Check-Summe geht meiner Meinung nach so:

unsigned int checksum = 0;

for(int i = 1; i < 16; i++)
{
    checksum += data[i];
}
data[0] = (byte)checksum;

100%ig sicher bin ich mir da aber nicht

Das sind die Min, Mid und Max Werte die ich pro Kanal übertragen kann.

Kanal Kanal Name Min String Mitte Strg Max Strg
Word Wert Wort Wert Wort Wert
0 Gas / Pitch 0x0000 0x01FF 0x03FF
1 Querruder 0x0400 0x05FF 0x07FF
2 Höhenruder 0x0800 0x09FF 0x0BFF
3 Sitenruder 0x0C00 0x0DFF 0x0FFF
4 Fahrwerk 0x1000 0x11FF 0x13FF
5 Aux 1 0x1400 0x15FF 0x17FF
6 Aux 2 0x1800 0x17FF 0x1BFF

Wenn ich alle Kanäle auf Max ausgebe will hab ich den Code von Serenifly so angepasst

void setup(){
  Serial.begin(9600);
}


void loop()
{
   byte data[16];
   data[1] = 0;

   for(int i = 0; i < 7; i++)
   {
       unsigned int value = 1023;    

       byte high = highByte(value) | (i << 2);
       byte low = lowByte(value);

       data[i * 2 + 2] = high;
       data[i * 2 + 3] = low;

       Serial.print(high, HEX);
       Serial.print(low, HEX);
       Serial.print(" ");
       Serial.print(high, BIN);
       Serial.println(low, BIN);
   }
  unsigned int checksum = 0;

  for(int i = 1; i < 16; i++)
  {
    checksum += data[i];
  }
  data[0] = (byte)checksum;
  Serial.print("Checksumme = ");
  Serial.print(data[0], HEX);
  Serial.print(" ");
  Serial.println(data[0], BIN);
  delay(10000);
  Serial.println("test");
  Serial.write(data, 16);// send 16 bytes from serial 
  Serial.println("testende");
}

Dann bekomme ich diese Ausgabe auf dem Serial Monitor

byyyyyyytestende
3FF 1111111111
7FF 11111111111
BFF 101111111111
FFF 111111111111
13FF 1001111111111
17FF 1011111111111
1BFF 1101111111111

Checksumme = 62 1100010

Die y in der ersten teile sind eigentlich Sonderzeichen y mit Pünktchen drüber.
Lasse ich mir die Daten auf einem andern Serial Monitor im RAW Format ausgeben wird folgendes angezeigt.

test<0D><0A>b<00><03><07><0B><0F><13><17><1B>testende
hier finde ich aber die 62, von der Checksumme nicht wieder.

Der Arduino Serial Monitor erwartet ASCII. Der kann mit rohen Binärdaten nichts anfangen.

Das geht da also nicht:

Serial.write(data, 16);

Du kannst das machen:

for(int i = 0; i < 16; i++)
{
    Serial.print(data[i]);
    Serial.print(",");
}

Danke,

aber dafür habe ich ja das Externe Programm genommen was dies kann.
Daher meine frage wegen der Checksumme. Diese müsste doch dann auch auftauchen
oder habe ich dann wieder einen Denkfehler?
Gruß ingo

Jetzt sehe ich es. Hat lange gedauert:

<0A>b<00>

Rate mal was 'b' in ASCII ist?

Aber keine Ahnung wieso er das als ASCII interpretiert

jep ich hab es auch gerade gesehen.
Nach dem mir eingefallen ist das ich ja Zeilenumbruch habe (Serial.println) als als Raw Daten 0d 0a
da kam mir der Gedanke, dass es bei dem b ja laut Zeichentabelle ja Hex werte gibt, und dementsprechend ist es 62.

Wenn ich es so ausgebe wie du es oben geschrieben hast.

for(int i = 0; i < 16; i++)
{
    Serial.print(data[i],HEX);
    Serial.print(",");
}

bekomme ich es ja so ausgegeben.

62,0,3,FF,7,FF,B,FF,F,FF,13,FF,17,FF,1B,FF,
Laut Vorgabe ist für die Übertragung ja LSB first angegeben.
Wäre das dann so richtig?

Da die Seriale Schnittstelle vom Sendemodul nicht mit 5 V arbeitet,
habe ich ein level shifter hier nach gebaut.

Kann man das so machen ?
Gruß ingo

Um von 5V auf 3,3V zu kommen ja.

Hier sind andere Optionen:
http://www.mikrocontroller.net/articles/Pegelwandler#5_V_.E2.87.92_3.2C3_V

Aber der Spannungsteiler tut es bei sowas langsamem wie Seriell :slight_smile:

Ok,
dann werde ich mal schauen was passiert, wenn ich alles miteinander verbinde.

Bin gespannt ob es dann klappt.

Cu Ingo

So habe es jetzt erfolgreich mit Zufallswerten getestet.
Vielen Dank noch mal an Serenifly für die Unterstürzung

/* the TX requires 16 bytes

Byte 1 Checksum (sum of bytes 2-16 cast to 1 byte)
Byte 2 Not used (can be any value)
Bytes 3-16 2 bytes per channel with following structure 0b000 CCC 9876543210
- 000 = not used (normally zeros)
- CCC = channel number (0=Thr, 1=Ail, 2=Ele, 3=Rud, 4=Gear, 5=Aux1, 6=Aux2)
- 9876543210 = 10bit channel position

so send something like:

sum   needs calculated
0x00  second byte is not used

B000000PPPPPPPPPP // all chan send same data PPPPPPPPPP is a 10 bit int or 8 would be easier depending on the accuracy you need
B000001PPPPPPPPPP
B000010PPPPPPPPPP
B000011PPPPPPPPPP
B000100PPPPPPPPPP
B000101PPPPPPPPPP
B000111PPPPPPPPPP

*/

void setup(){
  Serial.begin(115200);
}

void loop()
{
   byte data[16]; // Array of 16 Byte
   data[1] = 0; 

   for(int i = 0; i < 7; i++) 
   {
       unsigned int value = random(0, 1023);    //The Random Value for each channel.    

       byte high = highByte(value) | (i << 2); //Hige and
       byte low = lowByte(value);              //Low Byte from the 10 Bit of Channlel Value 

       data[i * 2 + 2] = high;        // Storing the high and 
       data[i * 2 + 3] = low;         // low share of each channel in byte array 
   }
  unsigned int checksum = 0;         // Checksumme set to 0

  for(int i = 1; i < 16; i++)       // Current calculate checksum
  {
    checksum += data[i];
  }
  data[0] = (byte)checksum;
  delay(500);                       // can be determined even reduced or eliminated
for(int i = 0; i < 16; i++)
{

}

Serial.write(data,16);        // Output of the byte array at the transmitter module
}

Zum Binden des Empfängers muss der Bindestecker auf dem Empfänger gesteckt werden und dann mit Strom versorgt werden.
Dann wird das Sendemodule mit Strom versorgt (Der Arduino muss dafür nicht angeschlossen werden).
Jetzt muss Pin 1 vom Sendemodul mit GND für ca. 2 Sec. verbunden werden (Obere und Untere Pin NICHT den Mitlernen Pin !!!)
Pinbelegung und Beschreibung -> http://www.micronradiocontrol.co.uk/docs/dt/dt-tx1-k1-1.pdf
wen der Bindevorgang abgeschlossen ist, den Empfänger ausschalten und den Bindestecker entfernen.

Nun kann das Sendemodul mit Strom und dem Aruino verbunden werden. zum Schluss den Empfänger mit Strom versorgen.
Wenn alles glatt gegangen ist, solltet ein Angeschlossenes Servo zufällige Positionen anfahren.

Hier ein Video vom Aufbau und Test.

Huge success :slight_smile:

Winzige Kleinigkeit:
deine Zufalls-Werte gehen nur bis 1022. Der zweite Parameter ist exklusiv, d.h. rnd(0, n) erzeugt Zahlen von 0 bis n-1. Keine Ahnung wieso, aber das ist auch in einigen anderen Sprachen so.

Ok, danke für den Hinweis.
Ob ich mir das bis zum nächsten mal merken kann :roll_eyes:
Die Zufallswerte brauch ich j für mein eigentliches Ziel nicht.

Als nächstes muss ich das mit den Analog Joystick probieren.

Gruß Ingo