Versenden von Sensor-Werten via 433mhz

Hallo und frohe Weihnachten,

ich bin recht neu in der Materie und habe daher ein paar Schwierigkeiten. Hauptproblem ist das Verstehen von Char und String und wie man sie am besten einsetzt. Leider finde ich darüber aber auch nur wenig auf Deutsch im Internet. Gibt es geeignete Bücher wo ihr empfehlen könnt? (Bei vielen höre ich viel negatives)

Zu meinem Problem, ich habe einen Code für einen Temperatursender geschrieben, und möchte diesen via 433mhz versenden. Dies wollte ich in einer Zeile machen und am Empfänger die nötigen Werte auslesen ( Temperatur, Spannung, Luftfeuchtigkeit). Leider will bei mir das RCSwitch-Senden von meinem String nicht funktionieren, was muss ich machen damit dies funktioniert? Ich hoffe ihr könnt mir das auf eine einfache Art erklären :).

//Temperatursender Version     //


//Benötigte Libarys
#include <RCSwitch.h> //RCSwitch-Libary einfügen
#include <DHT.h>  //DHT-Sensor Libary einfügen

//Variablen für DHT-Sensor
#define DHTPIN 7  //Definiere Sensor an PIN7
#define DHTTYPE DHT22 //Definiere DHT22 als Sensor
DHT dht(DHTPIN,DHTTYPE);  


//Variablen für Spannungsmessung
int voltinput = 0; //Definiere Variable Voltinput als 0
float vout = 0.0; //Definiere Variable Vout als 0
float vin = 0.0;  //Definiere Variable Vin als 0
float R1 = 100200.0;  //Definiere Wiederstand R1
float R2 = 9960.0;  //Definiere Wiederstand R2

//Variablen für Temperaturmessung
int value = 0;  //Definiere Value Pin als A0

//Variablen für Datenübertragung
int Data = 7;   //Definiere Data Pin als D7
RCSwitch mySwitch = RCSwitch();

void setup()
{
  Serial.begin(9600); //Sarte Serielle Verbindung
  pinMode(voltinput, INPUT);  //Definiere voltinput als Eingang

  pinMode(Data, INPUT); //Definiere Data-Pin als Input
  dht.begin();  //Starte Sensor-Messungen

}

void loop()
{
  Spannungsmessung(); //Führe void Spannungsmessung durch
  Temperaturmessung();	//Führe void Temperaturmessung durch
  delay(10000);	//Pause von 10Sekunden
}



void Spannungsmessung()
{
  //Read the value at analog input
  value = analogRead(voltinput);
  vout = (value * 4.65) / 1024.0; 
  vin = vout / (R2/(R1+R2));
  
  if (vin<0.09)
  {
     vin=0.0;
  }

  Serial.print("Spannung: ");
  Serial.print(vin, 1);
  Serial.println("V");
}


void Temperaturmessung()
{
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  int Temperatur = (t * 100);
  int Luftfeuchtigkeit = (h * 100);
  int Spannung = (vin * 100);
  
  String Auswertung = String('a' + Spannung + 'b' + Temperatur + 'c' + Luftfeuchtigkeit);
 
  Serial.println(Auswertung);

    
  //mySwitch.send(Auswertung, 2);
}

Auswertung.c_str

siehe hier in der Referenz

aber String-Objekte zu verwenden ist auf dem Arduino nicht zu empfehlen.

Besser du machst einen char Buffer, der gross genug ist und baust dir da den Text zusammen. C++ hat da umfangreiche Anweisungen für. Notfalls kannst du auch in PString streamen oder printen, wenn du es komfortabel willst

Cayn183:
... String ...

Wie der Spanier schon geschrieben hat, sind String-Strings ungünstig. Diese Strings sind zwar sehr komfortabel, aber viele Funktionen erwarten so genannte C-Strings (Arrays vom Typ char). Die Methode c_str() ergibt die C-String-Version eines String-Strings.

Der Umgang mit C-Strings ist zwar weniger komfortabel, aber sie belegen deutlich weniger Speicher. Ich stehe zwar auf Komfort, aber da ein Original-Arduino nicht allzu viel RAM hat, komme auch ich nicht darum herum, mit C-Strings zu arbeiten.

Gruß

Gregor

PS: Ja, blöde Sachen sind blöd.

Das ist die falsche Library um allgemeine Daten zu Senden. Verwende VirtualWire:
https://www.pjrc.com/teensy/td_libs_VirtualWire.html

Dann kannst du ganz einfach das machen zum Senden (nicht getestet und das Setup fehlt. Siehe Beispielcode auf der Seite):

struct Daten
{
   float wert1;
   int wert2;
};

Daten daten;

void loop()
{
   daten.wert1 = ...;
   daten.wert2 = ...;

   vw_send((byte*)&daten, sizeof(daten));
   vw_wait_tx();

   delay(1000);
}

In das struct kannst du beliebige Datentypen packen. Es muss nur auf beiden Seiten gleich sein

Da sieht man auch dass man sich nicht durch Strings verwirren lassen darf. Der Beispiel Code ist da auch mit einem C String. Aber die Kommunikation findet wie bei praktisch allen anderen Übertragungsarten auch byte-weise statt. Und die Sende-Funktion möchte einen Zeiger auf ein Byte. Dadurch ist man nicht auf Strings beschränkt. Man muss nur die Adresse seiner Daten (egal ob eine ein elementarer Datentyp, ein Array oder ein struct ist) auf byte* casten

Und zum Empfangen das:

void loop()
{
    byte len = sizeof(daten);

    if(vw_get_message((byte*)&daten, &len))
    {
       ...
    }
}

Hey,

vielen Dank für die schnelle antwort. Hast du eine Buchempfehlung oder eine Quelle wo man sowas gut nachlesen kann? Will ja nicht bei jedem Problem das Forum zu rate ziehen müssen (wobei ich das sowieso nie mache bevor ich wirklich nicht weiter weiß).

Kannst du mir die Zeile: vw_send((byte*)&daten, sizeof(daten)); mal genauer erklären? Wie setzen sich dort die mehreren Variablen ein? können die wild gemischt werden?

Was hälst du allgemein von meinem Code? Wiegesagt habe erst damit angefangen und keinerlei erfahrungen mit C/C++ und kann daher evtl ein paar Tipps gebrauchen wo man am anfang garnicht so drauf kommt :slight_smile:

Mfg.

Deine Daten sind in einer Struktur:

Dass man beliebige Datentypen darin haben kann ist der Sinn der Sache. Strukturen bieten sich auch immer an um zusammengehörige Daten zu gruppieren und dabei ansprechende Namen zu haben.

Der Sende-Funktion übergibst du die Adresse dieser Struktur gecastet auf einen Zeiger auf Byte. Und die Größe der Struktur in Byte. Die Adresse ist ursprünglich erst mal ein Zeiger auf die Struktur. Durch den Cast gaukelst du der Funktion vor dass ein Zeiger auf Byte ist. Das geht eben weil die Daten intern sowieso Byte für Byte abgearbeitet werden. Das kann man so auch mit z.B. I2C machen

Habe ich das mit dem struct richtig so verstanden? und stimmt auch der vw_send...? Ich habe oft in dem zusammenhang noch was mit buffer etc gelesen, wann wird dieser hier benötigt und was soll er machen?
Wieviele nachkomastellen werden mir jetzt ausgegeben, da diese ja nirgends begrenzt werden?

//Temperatursender Version     //


//Benötigte Libarys
#include <VirtualWire.h>
#include <DHT.h>  //DHT-Sensor Libary einfügen

//Variablen für DHT-Sensor
#define DHTPIN 7  //Definiere Sensor an PIN7
#define DHTTYPE DHT22 //Definiere DHT22 als Sensor
DHT dht(DHTPIN,DHTTYPE);  


//Variablen für Spannungsmessung
int voltinput = 0; //Definiere Variable Voltinput als 0
float vout = 0.0; //Definiere Variable Vout als 0
float vin = 0.0;  //Definiere Variable Vin als 0
float R1 = 100200.0;  //Definiere Wiederstand R1
float R2 = 9960.0;  //Definiere Wiederstand R2

//Variablen für Temperaturmessung
int value = 0;  //Definiere Value Pin als A0

//Variablen für Datenübertragung
int Data = 7;   //Definiere Data Pin als D7


struct Daten
{
	float Spannung;
	float Temperatur;
	float Luftfeuchtigkeit;
};

Daten daten;


void setup()
{
  Serial.begin(9600); //Sarte Serielle Verbindung
  pinMode(voltinput, INPUT);  //Definiere voltinput als Eingang

  pinMode(Data, INPUT); //Definiere Data-Pin als Input
  dht.begin();  //Starte Sensor-Messungen

}

void loop()
{
  Spannungsmessung(); //Führe void Spannungsmessung durch
  Temperaturmessung();	//Führe void Temperaturmessung durch
  delay(10000);	//Pause von 10Sekunden
}



void Spannungsmessung()
{
  //Read the value at analog input
  value = analogRead(voltinput);
  vout = (value * 4.65) / 1024.0; 
  vin = vout / (R2/(R1+R2));
  
  if (vin<0.09)
  {
     vin=0.0;
  }

  Serial.print("Spannung: ");
  Serial.print(vin, 1);
  Serial.println("V");
}


void Temperaturmessung()
{
  daten.Spannung = vin;
  daten.Luftfeuchtigkeit = dht.readHumidity();
  daten.Temperatur = dht.readTemperature();

  
  vw_send((byte*)&daten, sizeof(daten));
  vw_wait_tx();
}

Die Nachkommastellen einer Fließkommazahl sind ein reines Formatierungsproblem bei der Anzeige.

Intern gilt (nach Spec):

Floats have only 6-7 decimal digits of precision. That means the total number of digits, not the number to the right of the decimal point. Unlike other platforms, where you can get more precision by using a double (e.g. up to 15 digits), on the Arduino, double is the same size as float.

6-7 signifikante Ziffern.

Gruß Tommy

hallo Tommy56,

also wenn ich es richtig verstehe, kann man diese nicht genau definieren?
Sie haben in diesem fall immer 6-7 gesammt Stellen? d.h z.B.: 10.5689 oder -100.36?

Ja, so ist es. Wobei bei 3 Vorkommastellen mehr als 2 Nachkommastellen uch nur eingebildete Genauigkeit wäre.

Gruß Tommy

Kann man das wie bei Serial.print auf 2 nachkomastellen festschreiben wenn man struct verwendet?

Mfg.
Cayn183

Nochmal: Die 2 Nachkommastellen sind ein reines Problem bei der Ausgabe für den Menschen davor, Die ändern nichts am Zahlenwert.
Da gibt es mehrere Varianten der Formatierung. Da kommt es darauf an, was Du machen willst.

dtostrf wäre ein passendes Suchwort.

Gruß Tommy

Es fehlt noch die Konfiguration/Initialisierung von VirtualWire!

Cayn183:
Ich habe oft in dem zusammenhang noch was mit buffer etc gelesen, wann wird dieser hier benötigt und was soll er machen?

Braucht man wenn man mit Byte Arrays, bzw. C Strings arbeiten will. Der Puffer ist Empfangs-Code um die Daten reinzuschreiben. Hier hast du aber schon eine Struktur.

Du kannst auch das machen:

union Daten
{
  struct 
  {
     float Spannung;
     float Temperatur;
     float Luftfeuchtigkeit;
 };
 byte asArray[sizeof(float) * 3];
};

Bei einer Union belegen alle Elemente den gleichen Speicherplatz. So kann man Variablen sowohl unter ihrem Namen als auch explizit als Array ansprechen (mit daten.asArray). Dann braucht man auch keinen Cast der Adresse auf byte* sondern kann direkt das Array übergeben. Und beim Empfang liest man in das Array

Letztlich kommt es aber auf das Gleiche hinaus. Nur syntaktisch etwas anders

 Spannungsmessung(); //Führe void Spannungsmessung durch

Void ist ein Datentyp. Die Dinnger heißen "Funktion". void sagt hier dass die Funktion nichts zurück gibt.

So ich habe nochmal etwas rumprobiert und bin auf die nächsten Probleme gestoßen.

Beim Sendeteil, habe ich nun die Konfiguration und Initialisierung von VirtualWire nachgetragen, nur wie geht es denn dann mit dem Empfängerteil weiter? Sowie ich es verstanden habe, muss ich die "struct" genauso zum Empfängerteil rüber nehmen? Wie werden die daten dann ausgewertet?

Ich möchte sie nur mal im Seriellen Monitor ausgeben.

Sendeteil:

//Temperatursender Version     //


//Benötigte Libarys
#include <VirtualWire.h>
#include <DHT.h>  //DHT-Sensor Libary einfügen

//Variablen für DHT-Sensor
#define DHTPIN 7  //Definiere Sensor an PIN7
#define DHTTYPE DHT22 //Definiere DHT22 als Sensor
DHT dht(DHTPIN,DHTTYPE);  


//Variablen für Spannungsmessung
int voltinput = 0; //Definiere Variable Voltinput als 0
float vout = 0.0; //Definiere Variable Vout als 0
float vin = 0.0;  //Definiere Variable Vin als 0
float R1 = 100200.0;  //Definiere Wiederstand R1
float R2 = 9960.0;  //Definiere Wiederstand R2

//Variablen für Temperaturmessung
int value = 0;  //Definiere Value Pin als A0

//Variablen für Datenübertragung
int Data = 7;   //Definiere Data Pin als D7


struct Daten
{
	float Spannung;
	float Temperatur;
	float Luftfeuchtigkeit;
};

Daten daten;


void setup()
{
  Serial.begin(9600); //Sarte Serielle Verbindung
  pinMode(voltinput, INPUT);  //Definiere voltinput als Eingang

  pinMode(Data, INPUT); //Definiere Data-Pin als Input
  dht.begin();  //Starte Sensor-Messungen
  
  vw_setup(2000); // Bits per sec
  vw_set_tx_pin(12);// Set the Tx pin. Default is 12

}

void loop()
{
  Spannungsmessung(); //Führe Spannungsmessung durch
  Temperaturmessung();	//Führe Temperaturmessung durch
  delay(10000);	//Pause von 10Sekunden
}



void Spannungsmessung()
{
  //Read the value at analog input
  value = analogRead(voltinput);
  vout = (value * 4.65) / 1024.0; 
  vin = vout / (R2/(R1+R2));
  
  if (vin<0.09)
  {
     vin=0.0;
  }

  Serial.print("Spannung: ");
  Serial.print(vin, 1);
  Serial.println("V");
}


void Temperaturmessung()
{
  daten.Spannung = vin;
  daten.Luftfeuchtigkeit = dht.readHumidity();
  daten.Temperatur = dht.readTemperature();

  
  vw_send((byte*)&daten, sizeof(daten));
  vw_wait_tx();
}

Empfängerteil:

//Temperatur-Empfänger version 		//


//Benötigte Libarys
#include <VirtualWire.h>

struct Daten
{
	float Spannung;
	float Temperatur;
	float Luftfeuchtigkeit;
};
Daten daten;

void setup()
{
	Serial.begin(9600);
	vw_set_rx_pin(0);
	vw_setup(2000);
	vw_rx_start();
}

void loop()
{
byte len = sizeof(daten);	

	if(vw_get_message((byte*)&daten, &len))
	{

	}
}

Wie werden die daten dann ausgewertet?

Das ist wie beim Senden nur umgekehrt. Da hast du es doch auch geschafft die Daten reinzuschreiben

Du kannst aber nicht auf Pin 0 empfangen! 0 und 1 ist die serielle Hardware Schnittelle!

Danke für die Hilfe, manchmal sieht man die Lösung vor lauter Code nicht :wink:

Beim UNO ist es doch wenn ich mich nicht verlesen habe wenn ich auf Pin2 stecke und dann als Pin0 definiere ist das doch ein Interrupt Pin oder nicht? Kann ich diesen nicht verwenden? Ich hatte nämlich eine Testübertragung mit Zahlen vorher gemacht, da ist es nur gegangen wenn ich auf die Interupt Pins gegangen bin.

//Temperatur-Empfänger version 		//


//Benötigte Libarys
#include <VirtualWire.h>

struct Daten
{
	float Spannung;
	float Temperatur;
	float Luftfeuchtigkeit;
};
Daten daten;

void setup()
{
	Serial.begin(9600);
	vw_set_rx_pin(0);
	vw_setup(2000);
	vw_rx_start();
}

void loop()
{
byte len = sizeof(daten);	

	if(vw_get_message((byte*)&daten, &len))
	{
	
	float WertSpannung = daten.Spannung;
	float WertTemperatur = daten.Temperatur;
	float WertLuftfeuchtigkeit = daten.Luftfeuchtigkeit;
	
	Serial.println(WertSpannung, 2);
	}
}

Hi

Cayn183:
auf Pin2 stecke und dann als Pin0 definiere

Wie ist diese Aussage zu interpretieren?
Verstehe ich nämlich nicht :confused:

MfG

Ja etwas unverständlich ausgedrückt.
So wie ich es verstanden haben kann man Pin 2 entweder als Pin 2 oder Pin 0 ansprechen, bei Pin 0 wird er als Interrupt-Pin gesehen und als Pin 2 als normaler Pin.
Oder habe ich da einfach nur was falsch verstanden?

Aaahhh ... jetzt dämmert's

Der Pin 2 ist der INT0, der Pin3 ist der INT1 (wenn ich's gerade korrekt im Kopf habe).

Der Interrupt-Pin 0 entspricht dem Digital-Out-Pin 2 des Arduino.

Klick Mal hier drauf:

Gegen diese ganze Nummers-hin-und-herwerferei kannst Du auch
digitalPinToInterrupt(interruptPin)
benutzen.
Dort wird der Arduino-Pin eingetragen (also in Deinem Falle 2), intern wird daraus die Nummer 0, für den ersten Interrupt.

MfG

okey aber stimmen tut es dann so wie ich es mache oder nicht? :confused: