Probleme mit RS485

Hallo Gemeinde
ich habe da ein großes Problem, ich habe mir 3 Nanos mit RS485 zusammengebaut funktioniert auch gut die unterhalten sich und LED gehen an und aus. Nun würde ich gerne float Daten übertragen. Sensor Daten vom DS18B20. Also der Slave soll die Daten zum Master senden. Damit ich die im Master weiterverarbeiten kann.

Also buf[0] soll die Adressen sein
buf[1] der absender
und ab buf[2] … buf[?] sollen die Sensor daten

Master:

#include "RS485_protocol.h"
#include <SoftwareSerial.h>

const byte ENABLE_PIN = 4;


SoftwareSerial rs485 (2, 3);  // receive pin, transmit pin

// callback routines
  
void fWrite (const byte what)
  {
  rs485.write (what);  
  }
  
int fAvailable ()
  {
  return rs485.available ();  
  }

int fRead ()
  {
  return rs485.read ();  
  }

void setup()
{
  rs485.begin (28800);
  Serial.begin(9600);
  pinMode (ENABLE_PIN, OUTPUT);  // driver output enable
  pinMode (LED_PIN, OUTPUT);  // built-in LED
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
}  // end of setup

//-------------------------------------------------------
void loop()
{
  delay(4000);
  // assemble message
  for(int i=1; i < 3; i++)
  {
  byte msg [] = 
  { 
     i,    // device 1
     2    // turn light on
     //level // to what level
  } ;

  // send to slave  
  digitalWrite (ENABLE_PIN, HIGH);  // enable sending
  sendMsg (fWrite, msg, sizeof msg);
  digitalWrite (ENABLE_PIN, LOW);  // disable sending

  // receive response  
  byte buf [10];
  byte received = recvMsg (fAvailable, fRead, buf, sizeof (buf));
  digitalWrite (LED_PIN, received == 0);  // turn on LED if error 



if(received)
{
  if(buf[0] !=0)
  {return;}
  
  if (buf[1] == 1)
  {
  blink11();
  }
  if (buf[1] == 2)
  {
  blink12();
  }
 }
  } 
                // end of loop
void blink12()
{
digitalWrite(12,HIGH);
delay(200); // Wartezeit abha¨ngig von blinkRate-Wert value
digitalWrite(12,LOW);
delay(200);
}
void blink11()
{
digitalWrite(11,HIGH);
delay(200); // Wartezeit abha¨ngig von blinkRate-Wert value
digitalWrite(11,LOW);
delay(200);
}

Slave:

#include <SoftwareSerial.h>
#include "RS485_protocol.h"

const byte ENABLE_PIN = 4;
const byte LED_PIN = 13;

SoftwareSerial rs485 (2,3);

void fWrite (const byte what)
{
  rs485.write (what);
}
int fAvailable ()
{
    return rs485.available();
}
int fRead ()
{
    return rs485.read ();
}
void setup()
{
  Serial.begin(9600);
  rs485.begin(28800);
  pinMode (ENABLE_PIN, OUTPUT);
  pinMode(12, OUTPUT);
}

void loop()
{   
    byte buf[10];
    byte received = recvMsg(fAvailable, fRead, buf, sizeof (buf));
    
    if(received)
    {
        if(buf[0] != 1)
        {
          digitalWrite(12, LOW);
          return;
        }
        if(buf[1] != 2)
        {
            return;
        }
        
    //digitalWrite(12, HIGH);  // set light level  
      blink();
    byte msg [] = {0,2};
    
    delay (1);  // give the master a moment to prepare to receive
    digitalWrite (ENABLE_PIN, HIGH);  // enable sending
    sendMsg (fWrite, msg, sizeof msg);
    digitalWrite (ENABLE_PIN, LOW);  // disable sending
    
    
   }
   
}  // end of loop
void blink()
{
digitalWrite(12,HIGH);
delay(200); // Wartezeit abha¨ngig von blinkRate-Wert value
digitalWrite(12,LOW);
delay(200);
}

der andere Slave hat den gleichen Sketch nur mit der anderen Adresse. Habe schon viel gelesen und probiert aber noch keinen Erfolg. Kann mir bitte jemand helfen. Danke

write kennt noch eine andere Variante:

write(buf, len)

Damit kannst Du auch mehrere Bytes in einem Rutsch übertragen.
Schau mal in die Doku zu Serial. Das Verhalten ist gleich.

Wenn Du mehrere (verschiedene) Werte zusammen fassen willst, könnte die Beschäftigung mit struct oder Arrays und sizeof() für Dich interessant sein.

Gruß Tommy

anderen Tread gelöscht.
Uwe

Hi,
also ich habe die Arduino IDE 1.6.9 und da funktioniert es.
Tommy
kannst du mir ein Tip geben wie ich das in den code einfügen kann "write(buf, len)" da muss doch die zeile "sendMsg(fWrite, msg, sizeof msg);" bestimmt geändert werden.

Gruß Mike

Multipliziere die Temperaturen mit 10 und dividiere sie beim Empfänger wieder, dann brauchst du kein Float zu übertragen.

Gruß

So genau hab ich da nicht hingeschaut, ich mache das halt generell so :grinning:

Doc_Arduino:
Du musst “nur” mit der Zeigeradresse vom msg struct arbeiten. So ähnlich wie hier. Also wie im Link.

Genau so kann man es machen, wenn man verschiedene Datentypen übertragen will. Da mir RS485_non_blocking besser gefällt1), habe ich es damit realisiert:

Sender (liest Daten von A0):

#include <RS485_non_blocking.h>
#include <SoftwareSerial.h>

const byte RX_PIN = 2;  // software serial pins
const byte TX_PIN = 3;  // software serial pins
const byte XMIT_ENABLE_PIN = 4;  // transmit enable
SoftwareSerial rs485 (RX_PIN, TX_PIN);  // receive pin, transmit pin

size_t fWrite (const byte what)
{
  return rs485.write (what);
}

RS485 myChannel (NULL, NULL, fWrite, 0);

void setup ()
{
  Serial.begin(9600);
  Serial.println("Anfang");
  rs485.begin (4800);
  myChannel.begin ();
  pinMode (XMIT_ENABLE_PIN, OUTPUT);
  digitalWrite (XMIT_ENABLE_PIN, HIGH);  // enable sending
}  // end of setup

struct {
  const byte absender = 25;
  float wert = 0;
} msg;

void loop ()
{
  msg.wert = analogRead(A0) * 1.0;
  myChannel.sendMsg ((byte *)&msg, sizeof (msg));
  Serial.print(msg.absender);
  Serial.print(' ');
  Serial.print(msg.wert);
  Serial.println();
  delay (1000);
}  // end of loop

Empfänger:

#include <RS485_non_blocking.h>
#include <SoftwareSerial.h>

const byte RX_PIN = 2;  // software serial pins
const byte TX_PIN = 3;  // software serial pins
const byte XMIT_ENABLE_PIN = 4;  // transmit enable
SoftwareSerial rs485 (RX_PIN, TX_PIN);  // receive pin, transmit pin

int fAvailable ()
{
  return rs485.available ();
}

int fRead ()
{
  return rs485.read ();
}

RS485 myChannel (fRead, fAvailable, NULL, 20);

void setup ()
{
  Serial.begin(9600);
  Serial.println("Anfang");
  rs485.begin (4800);
  myChannel.begin ();
  pinMode (XMIT_ENABLE_PIN, OUTPUT);  // driver output enable
  digitalWrite (XMIT_ENABLE_PIN, LOW);  // disable sending
}  // end of setup

struct {
  const byte absender = 0x25;
  float wert = 0;
} msg;

void loop ()
{
  if (myChannel.update ())
  {
    memcpy (&msg, myChannel.getData (), myChannel.getLength ());
    Serial.print("Absender: ");
    Serial.print(msg.absender);
    Serial.print('\t');
    Serial.print("Wert: ");
    Serial.print(msg.wert);
    Serial.println();
  }
}  // end of loop

Anm:

  1. Die Bibliothek RS485_protocol führt zusammen mit IDE 1.8.6 leider zu Warnungen.

Doc_Arduino:
@ Scherheinz:
float hat auch nur 4 Bytes. Sein Problem ist das er bis jetzt ein reines Byte Array hat. Da passt weder ein long noch ein float rein.

Man kann ja immer noch die Nachkommastellen wegfallen lassen. Dann kann man mit einem Byte Werte im Bereich -128 bis 127 darstellen. Sollte reichen für einen Europäischen Sommer...

Hi

Eigentlich reicht's aus, wenn man ein einzelnes Bit sicher übertragen bekommt - der Rest ist auch nur eine Anreigung Erstgenannter.

Klar aber, daß das Übertragen eines struct sowohl mit einem Byte funktioniert, wie mit komplizierter aufgebauten Datenhappen.
Und man wird wohl öfter 'Mehr' übertragen wollen.

MfG

Doc_Arduino:
Hallo,

seltsamer Hinweis. Nur weil man nicht weiß wie man alles andere als Bytes über die Leitung jagt, soll man sich sein ganzes Leben auf Bytes einschränken ... ? :o Bitte nicht.

Jetzt möchte ich mal gerne sehen wie du eine serielle Datenübertragung, nicht auf Bytes runtergebrochen, realisierst.

Rintin:
Man kann ja immer noch die Nachkommastellen wegfallen lassen. Dann kann man mit einem Byte Werte im Bereich -128 bis 127 darstellen. Sollte reichen für einen Europäischen Sommer...

Zur Erinnerung. Manche brauchen wohl immer das Zitat, sonst drehen sie alles rum.

Gruß Tommy

Hi agmue
hab noch keine zeit gehabt es auszuprobieren.
aber eine frage kann man statt analog.read auch digital.read nehmen.

Mike0207:
Nun würde ich gerne float Daten übertragen.

Ja, man kann, beispielsweise in dem man Absender und float Daten in eine Struktur packt.

Mike0207:
aber eine frage kann man statt analog.read auch digital.read nehmen.

Nein. Um einen veränderlichen Wert zu erhalten, habe ich ein Poti an A0 angeschlossen und mittels analogRead gelesen. Da Du aber Temperaturen lesen möchtest, mußt Du die Zeile

msg.wert = analogRead(A0) * 1.0;

durch das Lesen der Temperatur ersetzen. Das hängt dann von der verweneten Bibliothek ab, möglicherweise so:

msg.wert = sensors.getTempCByIndex(0);

Man zerlegt den zu sendenden Mehr-Byte-Wert mittels Mod und Div oder Shift und AND und setzt ihn nach dem Empfang wieder per Multiplikation und Addition oder Shift und OR zusammen.

Um das auszuprobieren muss man nicht mal wirklich was senden, das geht über 4 lokale Variablen (oder ein Array) und zwei Funktionen ...

Hi Agmue,
vielen Dank, habe es gerade ausprobiert und es klappt.
Bin jetzt dabei das senden und empangen bei Master und Slave einzubauen.
Kann ich in den struct noch ein "const byte empfaenger = 2;" einfügen.
und kann ich
if(msg.absender !=0)
{
return;
}
in der art verwenden um die daten der verschiedenen Slave zu erhalten.

Gruß Mike

Mike0207:
vielen Dank, habe es gerade ausprobiert und es klappt.

Freut mich!

Mike0207:
Kann ich in den struct noch ein "const byte empfaenger = 2;" einfügen.

Ja, Du kannst beliebige Datentypen ergänzen, auch Zeichenketten. Logischerweise müssen die Strukturen auf Sender- und Empfängerseite immer gleich sein.

Der Absender gibt den Sensor an, von dem die Temperatur stammt. Ich würde daher eher positiv abfragen:

if(msg.absender == 1)
  {
    Temp1 = msg.wert;
  }