Go Down

Topic: 433MHz virtualWire Datentypen (Read 1 time) previous topic - next topic

Mahimus

Ich vermute, Du hast das ganze Prinzip nicht verstanden.

Klär mich auf!

michael_x

#16
Nov 21, 2019, 12:55 am Last Edit: Nov 21, 2019, 01:37 am by michael_x
char Data[] {'P', 165};
vw_send(Data, strlen(Data)); // falsch
vw_send(Data, sizeof(Data)); // richtig, bei dieser Definition von Data

Außerdem ist sizeof keine Funktion, deren Ergebnis erst zur Laufzeit ermittelt wird, sondern kann schon vom Compiler optimiert werden (wird durch 2 ersetzt).

Ob du byte (0..255) oder char (-128..127) verschickst, merkt keiner. Der erste Parameter wird als uint8_t* interpretiert, kann auch Nullen enthalten, muss daher die Länge mit übergeben bekommen. Da du den zweiten Wert 165 nennst, wäre byte Data[] übrigens sowieso besser gewesen. 

Dass der falsche Code bei dir funktioniert, kannst du Glück oder Pech nennen.
Irgendwann, nach einer Änderung ganz woanders, kann es sein, dass es nicht mehr funktioniert. Wäre erheblich besser gewesen, du hättest den Fehler gleich bemerkt, daher seh ich es als 'Pech'.



Code: [Select]
char[] quiz {"Hell\0 World "};
Serial.write(quiz, sizeof(quiz));  // guck mal in die reference, das gibt's auch.
Serial.println(quiz);  // Hell
Serial.println(strlen(quiz)); // 4
Serial.println(sizeof(quiz)); // 13

Mehr fällt mir zum unverstandenen Prinzip jetzt auch nicht mehr ein


Serenifly

Das einzige was ich noch für sinnvoll gehalten hätte ware das als byte zu verschicken und nicht als char.
Die Methode möchte einen Zeiger auf Byte. Dadurch kann man völlig beliebige Daten versenden. Ein Array, bzw. ein C String liegt da durch die Verwandtschaft von Arrays und Zeigern am nächsten, aber es sind nicht die einzigen Optionen. Man kann auch die Adresse einer beliebigen Variable nehmen und diese auf uint8_t* casten. Oder man nimmt eine Union aus einem Datentyp und einem Byte-Array gleicher Länge

Mahimus

#18
Nov 21, 2019, 10:58 pm Last Edit: Nov 21, 2019, 11:04 pm by Mahimus
Danke euch für die Ausführungen. Ich habe hier nochmal den Ausgangscode wie er war bevor ich daran rumgespielt habe, mit Zeiger im vw_send, das habe ich nun verstanden.

Code: [Select]

#include <VirtualWire.h>
#include <VirtualWire_Config.h>

// 433 MHz Sender mit der VirtualWire Library  V 1.27
// Matthias Busse 17.5.2014 Version 1.0
// Daten > D4


char *msg = "Hallo Welt";// Nachricht
const byte DatenPin = 4;


void setup() {
  
  pinMode(DatenPin, OUTPUT);
  vw_setup(2000);             // Bits pro Sekunde
  vw_set_tx_pin(DatenPin);     // Datenleitung
}
 
void loop(){
  
  vw_send((uint8_t*)msg, strlen(msg));
  vw_wait_tx();                         // warten bis alles übertragen ist
  delay(1000);
}



Seh ich es richtig, dass die chars ohnehin hier zu bytes gemacht werden
Code: [Select]
(uint8_t*)msg
?
Kann ich demnach in meinem Code das hier machen bzw. würdet ihr den absegnen?

Sender (liest Joystick aus und sendet Wert als byte):

Code: [Select]
#include <VirtualWire.h>
#include <VirtualWire_Config.h>


const byte DatenPin = 4;
//char *msg = "Hallo Welt";  // Nachricht
byte Power[] = {1, 0, 0};   // byte0 ist Kennung, byte1 enthält Wert, byte2 markiert Ende und ist immer "0"



void setup() {

  pinMode(DatenPin, OUTPUT);
  vw_setup(5000);             // Bits pro Sekunde
  vw_set_tx_pin(DatenPin);     // Datenleitung
}

void loop() {

  uint16_t Joystick_x = analogRead(A7); //hohe Werte unten
  uint16_t Joystick_y = analogRead(A6); //hohe Werte links

  Joystick_x = constrain(Joystick_x, 0, 1016);
  Joystick_x = map(Joystick_x, 0, 1016, 255, 0);
  Joystick_y = constrain(Joystick_y, 0, 1016);
  Joystick_y = map(Joystick_y, 0, 1016, 255, 0);

  Power[1] = Joystick_x;
  send_433(Power);


}

void send_433(byte Data[]) {

  vw_send(Data, sizeof(Data));  
  vw_wait_tx();                 // warten bis alles übertragen ist
}



Empfänger dazu:

Code: [Select]
#include <VirtualWire.h>
#include <VirtualWire_Config.h>


const byte DatenPin = 2;
int i;
byte Data[] = {0, 0, 0};
byte Power = 0;


void setup() {

  Serial.begin(9600);
  vw_setup(5000);         // Bits pro Sekunde
  vw_set_rx_pin(DatenPin);     // Datenleitung
  vw_rx_start();          // Empfänger starten
}

void loop() {

  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;

  if (vw_get_message(buf, &buflen)) {  // überprüfen ob eine Nachricht eingegangen ist
    for (i = 0; i < buflen; i++) {  
      Data[i] = buf[i];         // Nachricht aus buf
    }
    Power = Data[1];
    Serial.println(Power);
  }
}



Funktionieren tut das wiederum derzeit so wie es ist. Da ich eurem Rat vertraue und versucht habe alle Vorschläge umzusetzen wollte ich der Funktion vw_send eigentlich einen Zeiger geben, dann blieb der Wert aber konstant auch wenn ich den Joystick bewegt habe. Sollte ich das noch ändern und wenn ja wie kann ich den Wert dennoch variieren?

Wenn ihr sonst noch was zu meckern habt gerne sagen und im besten Fall Gegenvorschläge machen!

michael_x

Quote
void send_433(byte Data[]) {

  vw_send(Data, sizeof(Data));
Problem ist, dass dem Aufrufparameter byte Data[] die Größeninfo fehlt.

Über die zwei üblichen Möglichkeiten das zu lösen, haben wir uns ja schon ausgelassen:
A) Wenn 0 immer nur Endekennung ist, geht char* msg als einziger Parameter. Die 0 wird da übrigens nicht mit übertragen.
B) Zwei Parameter (byte* data, size_t len)
    der formal richtige DatenTyp size_t könnte natürlich in der Praxis auch auf ein byte reduziert werden.

Mahimus

Ok, ich hab eine brauchbare Anleitung zu Zeigern gefunden und es nochmal versucht:

Sender:
Code: [Select]
#include <VirtualWire.h>
#include <VirtualWire_Config.h>


const byte DatenPin = 4;
byte Power[] = {1, 0};    // byte0 ist Kennung, byte1 enthält Wert
byte *Z_Power = &Power[0];   // Z_Power zeigt auf Power[0]



void setup() {
  Serial.begin(9600);
  pinMode(DatenPin, OUTPUT);
  vw_setup(5000);             // Bits pro Sekunde
  vw_set_tx_pin(DatenPin);     // Datenleitung
}

void loop() {

  uint16_t Joystick_x = analogRead(A7); //hohe Werte unten
  uint16_t Joystick_y = analogRead(A6); //hohe Werte links

  Joystick_x = constrain(Joystick_x, 0, 1016);
  Joystick_x = map(Joystick_x, 0, 1016, 255, 0);
  Joystick_y = constrain(Joystick_y, 0, 1016);
  Joystick_y = map(Joystick_y, 0, 1016, 255, 0);

  Power[1] = Joystick_x;

  vw_send(Z_Power, sizeof(Power));  // (Zeiger, Größe des Array)
  vw_wait_tx();                 // warten bis alles übertragen ist
}



Funktionieren tut das wiederum im Test.

Ich meine nun verstanden zu haben, dass ich die 0 am ende nur brauche wenn ich die funktion strlen() nutzen möchte.
Weiterhin noch die Frage:
Wenn ich in der Initialisierung direkt schreibe

byte *Power = {1, 0};

habe ich dann gleichzeitig das array und einen gleichnamigen Zeiger erstellt?

MfG

Tommy56

#21
Nov 22, 2019, 07:05 pm Last Edit: Nov 22, 2019, 07:07 pm by Tommy56
Nein, dann hast Du ins Blaue geschrieben. Ein Zeiger zeigt auf etwas. Er hat reserviert keinen Speicher für die Inhalte, nur für sich selbst.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

michael_x

#22
Nov 22, 2019, 07:33 pm Last Edit: Nov 22, 2019, 07:33 pm by michael_x
Quote from: Tommy56
dann hast Du ins Blaue geschrieben
Die Zusatzfrage übersetzt nicht mal
scalar object 'Power' requires one element in initializer

Du hast ein Element vom Typ byte*, dem kannst du auch nur 1 Element zuweisen.
Außerdem sind das keine byte* sondern zwei Zahlen.
Wieder ein Beispiel wo man sieht, dass Zeiger und Array was unterschiedliches sind.

Im Beispiel hingegen sieht es gut aus.
Der Zeiger Z_Power zeigt auf 2 reservierte Byte Power[0] = 1; und Power[1] = _x und nur diese werden übertragen.

Wobei Z_Power überflüssig ist, denn Power an sich kann man im folgenden als byte* verwenden.

vw_send(Power, 2);  // (Zeiger, Größe des Array)

&Power[0] und Power sind insofern gleichwertig.

Tommy56

Ich habe es nicht kompiliert, weil es sowieso sinnlos war.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

Mahimus

byte *Power = {1, 0};

Das hier dachte ich wäre das äquivalent zu

char *msg = "Hallo Welt";

aber offenbar liegt da einer der Unterschiede zwischen strings und arrays.



&Power[0] und Power sind insofern gleichwertig.

Das heißt sobald ich ein Array erstelle, z.B. mit

byte Power[] = {1, 42};

ist Power automatisch der Zeiger aufs erste Element?



Tommy56

Ja und "Hallo Welt" ist ein Zeichenkettenliteral, auf dessen Anfang man einen Pointer setzen kann.
Du solltest anfangen, die Grundlagen zu lernen.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

combie

#26
Nov 22, 2019, 10:43 pm Last Edit: Nov 22, 2019, 11:41 pm by combie
Quote
ist Power automatisch der Zeiger aufs erste Element?
Nein, aus meiner Sicht nicht.

Power  ist ein ganz normaler Bezeichner.
Ein typisierter Bezeichner.
Er benennt ein Array.
Aus ihm kann man die Adresse, den Type der Arrayelemente und ihre Anzahl extrahieren.

Und ja, wenn du ihn als Zeiger benutzt, dann zerfällt er auch gerne (für dich) zu einem Zeiger auf das erste Element.
Verliert aber so das Array Attribut, und damit auch die Anzahl.
Irgendwie doof...(manchmal)

Also nein, er "ist" kein Zeiger auf das erste Element.
Kann aber dazu werden, wenn du das erzwingen möchtest.

--
Das mag dir pingelig erscheinen, ....
Aber ich halte die Differenzierung für notwendig.
Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

michael_x

#27
Nov 22, 2019, 10:56 pm Last Edit: Nov 22, 2019, 11:02 pm by michael_x
Quote
solltest anfangen, die Grundlagen zu lernen
Da ist mahimus doch gerade dabei :)
Und combies Hinweis auf die subtilen Unterschiede (und Gemeinsamkeiten) zwischen Zeigern und Arrays sind schon "fortgeschrittene Grundlagen".

Wo wir grade dabei sind, und wenn du genau guckst, liefert übrigens
char *msg = "Hallo Welt";
eine Warnung, denn eigentlich sollte "Hallo Welt" ein konstanter Text sein.
warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]

const char* msg = "Hallo"; // wäre richtig ,
aber nach deiner Definition ist im Code z.B. sowas erlaubt:
msg[2] = 0;
Serial.println(msg); // Ergibt "Ha"


Das geht, weil der Text auf den msg zeigt, im RAM liegt, bzw. vor dem Start von setup() dorthin kopiert wird.
Und weil umgekehrt ein Zeiger auch als Array interpretiert werden kann,
und also msg[2] das gleiche ist wie *(msg+2)


Tommy56

Aber ich halte die Differenzierung für notwendig.
Über die bin ich in C++ auch schon gestolpert. In ANSI-C war das noch kompatibel.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

combie

#29
Nov 22, 2019, 11:06 pm Last Edit: Nov 22, 2019, 11:09 pm by combie
Auch in den C Standards gibt es die Äquivalenz zwischen Zeiger und Arrays.
Die ist festgeschrieben(in Stein gemeißelt).
Wurde wie vieles andere in C++ übernommen.

Aber Äquivalent, heißt nicht , dass es das gleiche ist, oder gar das selbe.

> und also msg[2] das gleiche ist wie *(msg+2)
Äquivalent, nicht gleich.
2[msg] ist auch dazu Äquivalent
Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

Go Up