VirtualWire: Byte in Integer umwanden... Bitte um Hilfe

Hallo,
ich habe ein kleines Problem. Ich habe eine kabellose 433mhz Verbindung aufgebaut.
Ziel ist es einen Poti-Wert von einem Arduino auf einen anderen zu übertragen und mit diesem einen Motor ansteuern.
Die Übertragung klappt mit der VirtualWire libary problemlos. Jedoch bekomme ich es einfach nicht hin den Empfangenen Wert in eine int zu verwandeln, um mit dieser den Motor zu Steuern.
Ich habe schon alles was mir eingefallen ist versucht, gegoogelt, Foren durchsucht usw. - jedoch leider Erfolglos.

Hier der auf das nötigste reduzierte Code des Senders:
X ist hier der Wert, der später den Poti darstellt.

// library
#include <VirtualWire.h>
int sensorValue;
char buffer [11];
long X=125;


void setup() 

{
  Serial.begin(9600); 

  // virtual wire
  vw_set_tx_pin(12); // pin
  vw_setup(2000); // bps

}

void loop()
{
  
   itoa (X,buffer,10);
  sendString(buffer, true); 
  delay(100); 
}

void sendString(String message, bool wait)
{
  byte messageLength = message.length() + 1; 

  // convert string to char array
  char charBuffer[messageLength]; 
  message.toCharArray(charBuffer, messageLength);

  vw_send((uint8_t *)charBuffer, messageLength); 

  if (wait) vw_wait_tx(); 

  Serial.println("gesendet: " + message); 
}

Hier der Code des Empfängers:
(Ich kann die empfangene Message im Seriellen Monitor Anzeigen lassen. Jedoch habe ich schon vieles Versucht (z.B. message.toInt). Aber ich kann diese message nicht in einen Brauchbaren Int übersetzen.)

// library
#include <VirtualWire.h>
int wert;
int X;

byte message[VW_MAX_MESSAGE_LEN]; // a buffer to store the incoming messages
byte messageLength = VW_MAX_MESSAGE_LEN; // the size of the message

void setup()
{
  Serial.begin(9600);
  Serial.println("device is ready...");

  vw_set_rx_pin(12);
  vw_setup(2000); // bps
  vw_rx_start();
}

void loop()
{
  if (vw_get_message(message, &messageLength)) // non-blocking
  {
    Serial.print("Empfangen: ");
    for (int i = 0; i < messageLength; i++)
    {
      Serial.write(message[i]);
    X=message;
    }
    Serial. print ("   X:");
    Serial.println(X);

  }
}

Kann mir bitte jemand zeigen, wie ich diese Message in eine verwendbare Int Übersetzen kann?
Das wäre wirklich Klasse.

Vielen Dank schon einmal
-Tobias

Hallo,

für solche Dinge gibt es viele fertige Stringfunktionen. So wie du itoa nutzt lautet das Gegenstück atoi :) http://en.cppreference.com/w/c/string/byte http://www2.hs-fulda.de/~klingebiel/c-stdlib/string.htm

Du musst jedoch noch selbst dafür sorgen das nach dem string einlesen der Nullteriminator \0 gesetzt wird. Sonst kann keine Stringfunktion das echte Ende des zu lesenden strings (char array) erkennen. Das ist ganz wichtig. Bufferüberläufe sind sonst vorprogrammiert.

Wieso mußt Du ihn in ein int umwandeln?

Ok t'schuldige Du willst ein Array in ein INT umwandeln. Also das umgekehrte was Du mit itoa machst.

atoi()

besser ist es Du zerlegst das INT in 2 Byte und sendest diese: Das kannst Du mit lowByte() und highbyte() oder mit LOW = INT%256 HIGH = INT/256 machen

zusammenfügen mit INT = HIGH*256+LOW

Grüße Uwe

uwefed: Wieso mußt Du ihn in ein int umwandeln?

Und wieso ist ein Byte kein Integer?

Ich bin schockiert!

Gregor

Hallo,

vielleicht weil er ein int übertragen möchte und kein Byte, er muss demnach 2 Byte übertragen …
Wenn er nur Zahlenwerte und keine Srings übertragen möchte, dann kann er auf beiden Seiten auf die Wandlung in ein String verzichten. Das habe ich erst vor kurzem erfragt und es läuft 1A.

uwefed: besser ist es Du zerlegst das INT in 2 Byte und sendest diese: Das kannst Du mit lowByte() und highbyte() oder mit LOW = INT%256 HIGH = INT/256 machen zusammenfügen mit INT = HIGH*256+LOW

Vielen Dank erst einaml für deine Antwort. Das habe ich auch schon einmal versucht. Jedoch komme ich damit:

int X=125; byte LOW; byte HIGH; int Y;

void setup() { Serial.begin(9600); } void loop() { LOW=X%256; HIGH=X/256

Y=HIGH*256+LOW Serial.println(Y);}

auch nicht weit. Ich wüßte gerade auch nicht, wie ich dann 2 Bytes senden kann.

lg. Tobias

Doc_Arduino: vielleicht weil er ein int übertragen möchte und kein Byte, er muss demnach 2 Byte übertragen ... Wenn er nur Zahlenwerte und keine Srings übertragen möchte, dann kann er auf beiden Seiten auf die Wandlung in ein String verzichten. Das habe ich erst vor kurzem erfragt und es läuft 1A.

Ja, ich muss nur Zahlenwerte von 0-255 Übertragen. wie könnte ich das dann einfach machen? Ich kann wie gesagt den Zahlenwert im Seriellen Monitor Anzeigen lassen. die Übertragung läuft also. Nur brauche ich einen integer um mit dem Zahlenwert etwas anfangen zu können,... Aber danke schon einmal für deine Antwort :)

lg. Tobias

Tobi94: ... ich muss nur Zahlenwerte von 0-255 Übertragen. wie könnte ich das dann einfach machen?

Das könntest Du auch einfach dadurch lösen, dass Du - falls es vom Wertebereich her passt - Buchstaben überträgst und dann mit deren ASCII-Werten arbeitest. Oder Du kodierst Deine Übertragung und überträgst z. B. „FF“ statt die Zahl 255. Am anderen Ende musst Du das halt wieder dekodieren.

Viele Wege führen nach Rom :-)

Gruß

Gregor

Hallo,

jede Wandlung ist in dem Falle überflüssig und macht es nur unnötig kompliziert. Denn man benötigt in jedem Fall ein Übertragungsprotokoll mit definierten Start und Endekennung. Ich stand vor kurzem vor dem gleichen Problem. Das man Bytes schickt ist klar und dass man viele Bytes hintereinander schicken kann ist auch jeden klar. Jetzt kommt es nur darauf an das man alles in der richtigen Reihenfolge sendet und wieder empfängt und damit die empfangenen Bytes richtig “einsortiert”. Deswegen benötigt man immer ein vorher definiertes Übertragungsprotokoll.

Der Thread wo ich TO war ist der hier: http://forum.arduino.cc/index.php?topic=499791.0

Falls da jemand schwer durchblickt als “Querleser”, nochmal zusammengefasst. Danke nochmal an Serenifly u.a. für diese geniale union-struct Idee.

// definieren der Nachricht
union Nachricht
{
    struct
    {
       byte a;
       byte b;
       byte c;
    };
    byte asArray[3];          // muss der Summe aller struct Bytes entsprechen
} daten;

Jetzt kann man das union Byteweise hintereinander übertragen und empfangen. Ich habe die Funktionen zwecks besserer Übersicht hier vereinfacht. Ohne Checksumme usw.

void send_Nachricht ()
{       
      Serial1.write(STX);                            // Startkennung
      for (byte i=0; i < sizeof(Nachricht); i++) {
        Serial1.write(daten.asArray[i]);             // Bytes rausschieben
      }
      Serial1.write(ETX);                             // Endekennung
}



bool read_Serial_1()
{
  static byte index = 0;
  static bool state_Read = false;
    
  if (Serial1.available() > 0)  {
    byte c = Serial1.read();
    if (c == ETX && index > (sizeof(Nachricht)-1) ) {         // Ende-Kennung ?
      state_Read = false;
      return true;
    }
    
    if (state_Read == true && (index < sizeof(Nachricht))) {
      daten.asArray[index++] = c;                              // ins union hintereinander einsortieren
    }
    
    if (c == STX && state_Read == false) {                     // Start-Kennung ?
      state_Read = true;
    }
    
  }  
  return false;
}



void handle_Serial_1 ()
{
  if ( read_Serial_1() == true)  {                
    Serial.println(F("Serial hat empfangen:"));  
    Serial.print(daten.a); Serial.print('\t');
    Serial.print(daten.b); Serial.print('\t');
    Serial.print(daten.c); Serial.print('\t');
    Serial.println("komplett");
    Serial.println();
  }  
}

Als Start und Endekennung habe ich mich für diese entschieden. Gefällt mir einfach, diese Bitfolge. Praktisch spielt das keine Rolle welche Kennnung man nimmt. Wenn die Nachrichtenlänge bekannt ist, kann man sogar auf das Ende verzichten. Ich habs drin gelassen.

const byte STX = '\xCC';      // Startkennzeichen der Nachricht
const byte ETX = '\xEE';      // Endkennzeichen der Nachricht

Wenn du ein int übertragen möchtest, zum Bsp. soll c ein int sein, dann sieht das Nutzdatenprotokoll so aus

// definieren der Nachricht
union Nachricht
{
    struct
    {
       byte a;
       byte b;
       int c;
    };
    byte asArray[4];          // muss der Summe aller struct Bytes entsprechen
} daten;

und wenn alle 3 Werte int sein sollen, dann eben so

// definieren der Nachricht
union Nachricht
{
    struct
    {
       int a;
       int b;
       int c;
    };
    byte asArray[6];          // muss der Summe aller struct Bytes entsprechen
} daten;

Es muss “nur” beim Sender und Empfänger gleich definiert sein!
Ansonten ruhig mal den verlinkten Thread lesen, da gibts ein Bsp. wo ich auf meinem Mega mit 2 Seriellen “Daten Ping Pong” spiele.

Ich habe die obigen Codes jetzt nicht auf 100% Syntaxfehlerfreiheit überprüft. Habs im Editor nur abgeändert. :slight_smile:

Hallo,

habe mir nochmal Mühe gegeben. Lokales Daten Ping-Pong in aktueller Form. Viel Spass. :slight_smile:

/*
  Doc_Arduino - german Arduino Forum
  IDE 1.8.13
  Arduino Mega2560

  19.09.2017

  Ein Nachrichtenpaket wird auf der einen seriellen gesendet und auf der anderen empfangen.
  Gesendet wird jede Sekunde.
  Eine einfache Checksummen Funktion ist enthalten.
  Damit man zeitliche Übertragungsprobleme mitbekommt ist ein 5ms Antwort Timeout eingebaut.
  Wird dieser aktiv wird die Übertragung gestoppt und LED13 leuchtet dauerhaft.
*/
                                
typedef enum {FREE, WAIT, BUSY, FEHLER, STOP} sUART;    // Steuerzustände
sUART state_UART = FREE;

unsigned long countErrorsUART;        // uart Fehlerzähler

unsigned long last_millis;

const byte Led_UartTimeout = 13;

const byte STX = '\xCC';      // Startkennzeichen der Nachricht
const byte ETX = '\xEE';      // Endkennzeichen der Nachricht
  
byte addr_Slave = 44;
// definieren der Nachricht
union Nachricht
{
    struct
    {
       byte a;
       byte b;
       byte c;
       byte checksumme;
    };
    uint8_t asArray[4];          // Summe aller struct Datentypen
}; 
Nachricht sendDaten;
Nachricht empfDaten;

void setup()  {
  Serial.begin(250000);
  Serial1.begin(9600);        // Serial1 gekreuzt mit Serial2 verbunden
  Serial2.begin(9600);

  pinMode(Led_UartTimeout, OUTPUT);

  sendDaten.a = addr_Slave;
  sendDaten.b = 34;
  sendDaten.c = 234;  
}


void loop() {

  read_Serial_2_to_Serial_0();

  check_Uart_Receive_Timeout();

  if (millis() - last_millis > 999) {
    last_millis = millis();
      
    if (state_UART == FREE) {  
      send_Nachricht();                     // sendet auf Serial_1
      sendDaten.a += 2;
      sendDaten.b += 4;
      sendDaten.c += 8;                          
    }
  }
  
    
  
} // loop Ende


// ****** Funktionen ******* //
bool read_Serial_2()
{
  static byte index = 0;
  static bool state_Read = false;
  static bool state_Complete = false;
    
  if (Serial2.available() > 0)  {
    byte c = Serial2.read();
    //Serial.println(F("read"));  
    if (c == ETX && index > (sizeof(Nachricht)-1) ) {         // alle Bytes eingetroffen inkl. Ende-Kennung ?
      state_Read = false;
      state_Complete = true;
    }
    
    if (state_Read == true && (index < sizeof(Nachricht))) {
      empfDaten.asArray[index++] = c;
    }
    
    if (c == STX && state_Read == false) {                     // Start-Kennung ?
      state_Read = true;
    }
    
    if (state_Complete == true) {                              // Übertragung fertig ?
      index = 0;
      // Checksumme korrekt ?
      if ( empfDaten.checksumme == calc_Checksumme(empfDaten.asArray, sizeof(Nachricht)) ) {
        state_Complete = false;
        state_UART = FREE;
        digitalWrite(Led_UartTimeout, LOW);  // Debug LED
        return true;
      }
    }
  }  
  return false;
}


void read_Serial_2_to_Serial_0 ()
{
  if ( read_Serial_2() == true)  {
    Serial.println(F("Serial_2 hat empfangen:"));  
    Serial.print(empfDaten.a);    Serial.print('\t');
    Serial.print(empfDaten.b);   Serial.print('\t');
    Serial.print(empfDaten.c);       Serial.print('\t');
    Serial.print(empfDaten.checksumme); Serial.println();
    Serial.println();
  }  
}


void check_Uart_Receive_Timeout ()
{ 
  static unsigned long timeout = 0;
  static unsigned long UartTimeoutStart;
    
  if (state_UART == WAIT) {
    state_UART = BUSY;
    UartTimeoutStart = millis(); 
    digitalWrite(Led_UartTimeout, HIGH);  // Debug LED
  }

  if (state_UART == BUSY) {
    timeout = millis() - UartTimeoutStart;   
    if (timeout > 4) {              // 5ms Timeout
      state_UART = FEHLER;
    } 
  }
  
  if (state_UART == FREE) {  
    //Serial.print("Debug ms"); Serial.print('\t'); Serial.println(timeout);
  }  

  if (state_UART == FEHLER) { 
    countErrorsUART++; 
    Serial.print(F("UART TIMEOUT")); Serial.print('\t'); Serial.println(timeout);
    Serial.print(F("UART Errors"));  Serial.print('\t'); Serial.println(countErrorsUART);
    state_UART = STOP;              // zum debugen auf 'FREE' setzen
  }  
}


void send_Nachricht ()
{       
      sendDaten.checksumme = calc_Checksumme(sendDaten.asArray, sizeof(Nachricht)) ;        
      Serial.println(F("Serial 1 sendet:"));                    // Debug
      Serial.print(sendDaten.a);   Serial.print('\t');   // Debug
      Serial.print(sendDaten.b);   Serial.print('\t');   // Debug
      Serial.print(sendDaten.c);   Serial.print('\t');   // Debug
      Serial.print(sendDaten.checksumme); Serial.println();     // Debug
    
      Serial1.write(STX);    
      for (byte i=0; i < sizeof(Nachricht); i++) {
        Serial1.write(sendDaten.asArray[i]);
      }
      Serial1.write(ETX); 
      Serial1.flush();      
      state_UART = WAIT;
}

      
byte calc_Checksumme (byte feld[], byte length)        
{
  byte Checksumme = 0;
      
  for (byte i=0; i<length-1; i++) {                 // nur Nutzdaten aufsummieren
    Checksumme = Checksumme + feld[i];              // ohne Rücksicht auf Überlauf
  }
   
  return Checksumme;                                  
}