RS485 mit Blankem MAX485 Chip

Grüße,

ich bin gerade dabei eine Verbindung von zwei Arduino mit RS485 einzurichten. ich habe da ein kleines Tutorial im netz gefunden bei dem ein Arduino Sender und einer Empfänger ist und das hat auch geklappt.

Nun wollte ich das Ganze mal im Wechsel betreiben und scheitere daran.

Die Idee ist:

ArduinoA sendet ein Int (0).
ArduinoB empfängt das Int und gibt es via Serial Print aus.
dann incrementiert er es und schickt es zurück.
ArduinoA empfängt das Int und gibt es via Serial Print aus.
dann incrementiert er es und schickt es zurück.
ArduinoB empfängt das Int und gibt es via Serial Print aus.
dann incrementiert er es und schickt es zurück.
ArduinoA empfängt das Int und gibt es via Serial Print aus.
dann incrementiert er es und schickt es zurück.
ArduinoB empfängt das Int und gibt es via Serial Print aus.
dann incrementiert er es und schickt es zurück.
USW.

Das versuche ich über diesen Code zu erreichen


/* Arduino Transmitter */
#define MODE 2
#define TRANSMIT 0
#define RECEVE 1
#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11);
// RX on digital pin 10
// TX on digital pin 11

int i = 0;
void setup() {
  Serial.begin(57600);
  mySerial.begin(57600);
  digitalWrite(MODE, TRANSMIT);
  mySerial.println(i);
  delay(1000);
  digitalWrite(MODE, RECEVE);
  delay(50);
}

void loop() {

  if (mySerial.available()) {
    i = (mySerial.read());

    Serial.print("Read:");
    Serial.println(i);
    i++;

    digitalWrite(MODE, TRANSMIT);
    delay(50);
    Serial.print("Send:");
    Serial.println(i);
    mySerial.println(i);
    delay(50);
    digitalWrite(MODE, RECEVE);
    delay(1000);
  }
}

mein Aufbau sieht so aus

Aber klappen tut es nicht.
meine Ausgabe sieht so aus:

15:00:02.584 -> Init:0
15:00:23.931 -> Read:48
15:00:23.931 -> Send:49
15:00:24.932 -> Read:45
15:00:24.932 -> Send:46
15:00:25.930 -> Read:10
15:00:25.930 -> Send:11
15:00:28.083 -> Read:48
15:00:28.083 -> Send:49
15:00:29.063 -> Read:45
15:00:29.063 -> Send:46
15:00:30.070 -> Read:10
15:00:30.070 -> Send:11

Also er liest irgendwas und sendet irgendwas aber eig sollte es so aussehen

15:00:02.584 -> Init:0
15:00:23.931 -> Read:0
15:00:23.931 -> Send:1
15:00:24.932 -> Read:2
15:00:24.932 -> Send:3
15:00:25.930 -> Read:4
15:00:25.930 -> Send:5
15:00:28.083 -> Read:6
15:00:28.083 -> Send:7
15:00:29.063 -> Read:8
15:00:29.063 -> Send:9
15:00:30.070 -> Read:10
15:00:30.070 -> Send:11

kann man schon so machen aber da musst ein wenig mehr gehirnschmalz reinstecken.

delay geht gar nicht.
Da wirst was nach "Blink Without Delay" mit millis() bauen müssen.

Für die Kommunikation schau dir mal das an:

Serial Input Basics - updated - Using Arduino / Introductory Tutorials - Arduino Forum

Damit klappt das einlesen super.

Außerdem musst du noch definieren, was passieren soll, wenn einer der Arduinos nichts mehr empfängt ... wieder holt der dann die alte zahl oder was soll da passieren?

das was du oben siehst ...
0 ist in ASCII 48.
der zweite addiert 1, und schickt 49
...

Achse ich dachte das so, wenn er nichts empfängt macht er halt nichts der loop lobt weiter bis er wieder was empfängt.

Aber das ist auch nur ein einfaches PingPong um mal zu gucken wie das funktioniert.

das ist mit ein wenig Serial-Input-Basics Example 4 und eben ein Transmit.

der recvWithEndMarker ruft direkt den showNewNumber auf,
setzt die previousMillis und ein flag
und der checkTimeToSend überprüft, dann ob was gesendet werden soll.

/* 
   Arduino Receive and Transmit with RS485
   Receiver based on Example 4 of https://forum.arduino.cc/t/serial-input-basics-updated/382007/3
   https://forum.arduino.cc/t/rs485-mit-blankem-max485-chip/1288711/2
   2024-08-05 by noiasca
*/

#include <SoftwareSerial.h>

constexpr uint8_t rxPin {2};
constexpr uint8_t txPin {3};
constexpr uint8_t enablePin {11};
/*
  constexpr uint8_t rxPin {10};    // RX on digital pin 10
  constexpr uint8_t txPin {11};    // TX on digital pin 11
  constexpr uint8_t enablePin {2}; // "mode" pin
*/

SoftwareSerial mySerial(rxPin, txPin);

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data
uint16_t dataNumber = 0;        // the payload to be transmitted vice versa
uint32_t previousMillis = 0;    // last time received something
bool isActive = false;

// transmit data
void transmit(uint16_t data) {
  digitalWrite(enablePin, HIGH);
  mySerial.println(data);
  digitalWrite(enablePin, LOW);
}

void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;
  if (mySerial.available() > 0) {
    rc = mySerial.read();
    if (rc != endMarker) {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;                   // fürs nächste lesen
      showNewNumber();           // weils reingekommen ist
      previousMillis = millis(); // Timer Zeit aufziehen
      isActive = true;           // Timer aktivieren
    }
  }
}

void checkTimeToSend() {
  if (isActive && millis() - previousMillis > 1000) {
    dataNumber++;
    transmit(dataNumber);
    isActive = false;
  }
}

void showNewNumber() {
  dataNumber = 0;
  dataNumber = atol(receivedChars);
  Serial.print("This is just in ... ");
  Serial.println(receivedChars);
  Serial.print("Data as number ... ");
  Serial.println(dataNumber);
}

void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
  pinMode(enablePin, OUTPUT);
  transmit(dataNumber);
}

void loop() {
  recvWithEndMarker();
  checkTimeToSend();
}
//

Vorsicht, hab andere Pins und Baudraten.

1 Like

danke für das Code Beispiel.

ich habe meinen noch einmal angepasst und dafür die Arduinos erstmal ohne die MAX485 verbunden um eine Fehlerquelle weniger zu haben.

bislang funktioniert es auch ganz gut aber...

Ich fang mal von vorn an.

Ich habe zwei Arduinos die direkt mit RX und TX verbunden sind.

A sendet ein Packet aus einem""und zwei bytes (das Läuft)
B empfängt diese. (das läuft)
B nimmt die beiden bytes auseinander und entnimmt informationen (das läuft)
B sendet die bekommenen Daten an A zurück (das Läuft)
A kontrolliert ob er von B zurück bekommt was er B geschickt hat (das läuft)

Das ganze ist ein Modularer System mit acht Slave Arduinos(B0-B7) und einem Master Arduino(A)
Nun kann es vorkommen das nicht alle Salzes angeschlossen sind und entsprechend auch keinen wert zurück geben.

daher wollte ich ein while mit millis bauen damit der Master einfach weiter macht wenn nach 5 Sek. keine Nachricht vom Slave B kommt.
Das wollte ich damit machen.

unsigned long now=(0);
        unsigned long wait=(1000);
        while((mySerial.available()==0||(now>wait))){
          now=millis();
          Serial.print(now);Serial.print(" > ");Serial.println(wait);

Für mich steht da
Print mills bis eine Nachricht kommt oder millis größer ist als wait.

Das Ergebnis ist

Now > wait
950 > 1000
962 > 1000
974 > 1000
987 > 1000
1000 > 1000
1013 > 1000
1027 > 1000
...

Schau Dir nochmal an, was millis() macht, Du brauchst kein while und einige Klammern sind auch überflüssig.
Bearbeite das Beispiel BlinkWithoutDelay in der IDE und verstehe es.

Gruß Tommy

Wenn das keine theoretische Spielerei mehr sein soll, dann besser du beschreibst was das am Ende genau werden soll.

Was schickt der Master?
Was macht der Slave damit?
Was schickt der Slave retour?
Was macht der Master mit den Daten der 8 Slaves?

Vor allem sind es mittlerweile einige Threads, wo keiner weiß, ob und wie die zusammen gehören oder nicht und jeder behandelt ein Salamischeibchen.
Also nun mal Klartext.

Gruß Tommy

Also, ich habe das ganze noch einmal umgebaut.

Hardware technisch hat sich nichts verändert außer das ich den Eingang RE dauerhaft auf GND ziehe. Ich habe an mehreren Stellen gelesen das könne man so machen und dann nur DE HIGH und LOW schalten.

Ich hatte die MAX 485 abmontiert und bei meinen Arduinos die TX und RX der SoftwareSerial (10 und 11) miteinander verbunden

11->10
10->11

Ich möchte von einem Arduino A aus zwei Byte an Arduino B senden . Byte 1 ist eine ID byte 2 beschreibt die Zustände an 8 Digitaloutputs.

Danach soll B diese Digitaloutputs setzen und den bekommenen Wert+ ID zurück an A senden, damit A weis das alles richtig empfangen wurde.

Das sieht für arudino A So aus:

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11);
// RX on digital pin 10
// TX on digital pin 11
byte blockstate=0b00000000;
byte    data [2];
uint8_t value =0;
int returnID=-1;
int returnvalue=-1;

void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
 Serial.println("Arduino2 Start RS485 RT Test");
 digitalWrite(2,HIGH);
}

void loop() {

    for (uint8_t IDB=0;IDB<=7;IDB++){                        //for each valveblock
        value=0b00000000;                                    //reset valvestates

//Set Valvechannelstates//
        for(uint8_t IDC=0; IDC<=7;IDC++){                    //for each channel of one valveblock
            value=(value<<1);                                //shift value left
            //read Channelstate//
            value=(value|=(1<<0));                           //add new valvechannelstate(static for now)
            value=0b10010110;      
        }//FOR IDC   

//Send State to block
        digitalWrite(2,HIGH);
        while(!digitalRead(2)){};
        mySerial.write('/');                                 //send initial char
        mySerial.write(IDB);                                 //send ID of vlaveblock
        mySerial.write(value);                               //send valvechannelstates
        Serial.print("I Send ");Serial.print(value,BIN);                                          //debugprinting
        Serial.print(" To ID ");Serial.println(IDB);                                              //debugprinting


        digitalWrite(2,LOW);
        while(digitalRead(2)){}

        //Serial.print(digitalRead(2));
        mySerial.readBytesUntil('|',data,2);                 //read return
 
        
     
     bool validreturn=false;                                  //declare Bool for Valid Return
     validreturn=((mySerial.readBytesUntil('|',data,2))==2);  //Set Bool for Valid Return
     if(validreturn){                                         //If Bool is true
 
        returnID=data[0];                                     // Set return ID
        returnvalue=data[1];                                  // Set Value
      }
      else{                                                   //If Bool is false
          returnID=-1;                                        //set Return ID to default
          returnvalue=-1;                                     //set Return value to default
}

if((IDB==returnID)&&(value==returnvalue))                     //if compare Send and Return is true
{              
digitalWrite(7,HIGH);                                         //green LED On
digitalWrite(6,LOW);                                          //yellow LED OFF 
digitalWrite(5,LOW);                                          //red LED OFF  
Serial.println("Correct Return Value");                                                                              //debugprinting                 
}//ifEqual

if((returnID==-1)||(returnvalue==-1)){                             // if return ID and Value =-1
digitalWrite(5,LOW);                                          //green LED OFF  
digitalWrite(6,LOW);                                         //yellow LED On
digitalWrite(7,HIGH);                                          //red LED OFF  
Serial.println("No Device");                                  //debugprinting 
}//if-1
if((!((returnID==-1)||(returnvalue==-1)))&&(!((IDB==returnID)&&(value==returnvalue))))//if compare Send or Return is false but not -1
{
digitalWrite(5,LOW);                                          //green LED OFF  
digitalWrite(6,HIGH);                                         //yellow LED On
digitalWrite(7,LOW);                                          //red LED OFF 
Serial.println("BAD Return VALUE");                                  //debugprinting 
}//if bad value not -1
     }//For IDB
  }//LOOP

und für Arduino B so:

#include <SoftwareSerial.h>



SoftwareSerial mySerial(10, 11);
// RX on digital pin 10
// TX on digital pin 11
String sendMessage;
String receivedMessage;
uint8_t ID    =0;
int     readID=0;
int     value =0;
byte    data [2];
void setup() {

  pinMode(7,INPUT);
  pinMode(6,INPUT);
  pinMode(5,INPUT);

  Serial.begin(9600);
  mySerial.begin(9600);
  Serial.println("Arduino1 Start RS485 RT Test");
  digitalWrite(2,LOW);  
  }

void loop() {

  ID =(digitalRead(5)<<2);
  ID +=(digitalRead(6)<<1);
  ID +=(digitalRead(7));
    
     digitalWrite(2,LOW);
      while(digitalRead(2)){}
   
    mySerial.readBytesUntil('/',data,2);


    if(readID!=data[0]){
       
      Serial.print("My ID is: ");Serial.print(ID);
    readID=data[0];
    value=data[1];
    Serial.print(" readID= ");Serial.print (readID);
    Serial.print(" Value= ");Serial.println(value,BIN);
  if(readID==ID){
digitalWrite(2,HIGH);
while(!digitalRead(2)){
Serial.println(digitalRead(2));

};
Serial.println(digitalRead(2));
    Serial.print("SET VALVES to ");Serial.println(value,BIN);
        mySerial.write('|');
        mySerial.write(readID);
        mySerial.write(value);
        
        
    Serial.print("I return ID: ");Serial.print(readID);Serial.print(" and value: ");Serial.println(value,BIN);
  }
  }

}

Das Ergebnis sieht so aus:

Arduino A:

I Send 10010110 To ID 0
No Device
I Send 10010110 To ID 1
No Device
I Send 10010110 To ID 2
No Device
I Send 10010110 To ID 3
No Device
I Send 10010110 To ID 4
Correct Return Value
I Send 10010110 To ID 5
No Device
I Send 10010110 To ID 6
No Device
I Send 10010110 To ID 7
No Device

und bei Arduino B sieht es so aus:

My ID is: 4 readID= 0 Value= 10010110
My ID is: 4 readID= 1 Value= 10010110
My ID is: 4 readID= 2 Value= 10010110
My ID is: 4 readID= 3 Value= 10010110
My ID is: 4 readID= 4 Value= 10010110
1
SET VALVES to 10010110
I return ID: 4 and value: 10010110
My ID is: 4 readID= 5 Value= 10010110
My ID is: 4 readID= 6 Value= 10010110

So gesehen gehe ich mal davon as das mein Code richtig ist.

aber wenn ich die MAX485 Basteine verwende bekomm ich kein Return vom Arduino B

falsch verkabelt.
Aber ohne Schaltplan und ohne aussagekräftige Bilder musst du das selber suchen.




Das letzte bild ist die Direktverdrahtung die funktioniert.

Mit den drei weißen kabeln lege ich die Adresse des Arduino B fest.

Schaltplan folgt morgen das schaffe ich jetzt nicht mehr

Hier noch der Schaltplan, ich hab Kicks grad nicht zur Hand ich hoffe es ist trotzdem verständlich

aus meiner Sicht musst du DE und RE umschalten.
Daher hab ich die bei mir einfach gebrückt.
Außerdem fehlt der Abblock Kondensator je IC bei dir

hier ein Ausschnitt von meinem Nano Board:

1 Like

Alles klar das passe ich dann nachher an

EDIT: wobei es mich verwundert., das bei komplett identischen Aufbau das A->B funktioniert und das B->A nicht

Ist dir der Unterschied zwischen einem BUS RS485 und einer Punkt zu Punkt (RS232) Verbindung bekannt?

Ich denke schon, deswegen will ich die Kommunikation ja mit dem rs485 machen.

Es werden ja beide Leitungen Für beide Wege verwendet nicht wie beim rs 232 wo eine Leitung zum senden und eine zum empfangen gedacht ist. Ob gesendet oder empfangen wird hängt ja von den Enable Pins am max485 ab.

Ich hab grad gesehen das ich vergessen habe pin D2 als Output zu definieren, vllt ist das auch schon des Rätsels Lösung

Nein nicht nur, A zu B ist falsch, wenn gut in errinerug.

damit meint er die Kommunikation von Node A zu Node B und vice versa.
Nicht die Verkabelung!
Die siehst ja im Schaltplan und im Bild, dass A mit A und B mit B verbunden wurde.

Ja tut mir leid ich habe mich falsch ausgedrückt

Die Ausgangsleitungen sind natürlich A<->A und B<->B Verbunden.

ich habe nur die beiden uno unoA und unoB genannt

unoA->unoB geht
undB->unoA geht nicht

sry Doppelverwendung von bezeichnen ist schon nicht so clever