Go Down

Topic: I2C Problem Master -> Slaves  (Read 409 times) previous topic - next topic

fetterspanier

Nov 14, 2017, 01:24 am Last Edit: Nov 14, 2017, 12:33 pm by fetterspanier
Hallo allerseits,

Ich habe Probleme mit meinem Master. Bzw. glaube ich momentan, dass das Problem beim Master liegt. Die Slaves empfangen keine nachrichten außer der ersten (MASTER_START).
Testaufbau besteht aus einem Master und zwei Slaves, alles UNOs.

Infos zur gewünschten Funktion:
Der Master soll anfangs automatisch erkennen wieviele Slaves angeschlossen sind bzw. gelöst werden müssen. Nach dem Aktivieren des Startbuttons läuft der Countdown und der Master wartet auf Strike oder Solved Signale der Slaves.
Sollten alle Slaves Solved senden bevor der Countdown abläuft, wird der Countdown gestoppt und der Master sendet das End-Signal an alle Slaves. Damit wird alles auf Anfang gesetzt.

Sollte der Countdown ablaufen bevor alle Slaves Solved senden, sendet der Master das Fail-Signal. Dieses soll das weitere lösen von Slaves unterbinden. In Beiden Fällen ist keine Eingabe über die Slaves mehr möglich bis der Master nicht wieder gestartet wird.

Sollte das Strikelimit (unabhängig von welchem Slave) überschritten werden, sendet der Master Unsolved an alle Slaves um selbst gelöste Slaves wieder lösbar zu machen. Sprich ist es wie nach der Aktivierung durch den Master. Mit dem Unterschied, dass der Countdown weiterläuft und nicht ebefalls neu startet.

Die Buttons am Master funktionieren soweit bzw werden die Serial Nachrichten in der Console angezeigt.

Leider werden die Slaves nicht "aktiviert" solange die Zeile im Loop mit while definiert ist.
Ändere ich while (started && !solved) auf if (started && !solved) funktionieren die Buttons an den Slaves. Dann werden Strikes sowie Solved Befehle an den Master gesendet. (Hier weiß ich schon nicht genau warum while nicht funktioniert.  :smiley-confuse: )

Dieser emfpängt sie auch aber handelt sie nicht komplett ab. Bzw. kommen keine neuen Befehle bei den Slaves an.

MASTER
Code: [Select]
#include <Wire.h>
extern "C" {
#include "utility/twi.h"
}
#include "Countimer.h"

#define NODE_MAX 15 //max slave address
#define START_NODE 2
#define NODE_READ_DELAY 1000
#define COUNTDOWN_MINS 1
#define COUNTDOWN_HOURS 0
#define COUNTDOWN_SECS 0
#define MASTER_ADDRESS 42
#define BIT_MASK 0x0F
#define STRIKE_MAX 3
#define MASTER_END 0x02
#define MASTER_FAIL 0x01
#define MASTER_UNSOLVE 0x04
#define MASTER_START 0x03
#define SLAVE_SOLVED 0x03 //deviceID+1 (filter with BIT_MASK)
#define SLAVE_STRIKE 0x02 //deviceID+2 (filter with BIT_MASK)

// constants won't change. They're used here to
// set pin numbers:
// 2 = stop button, 3 = start button

const int stopPin = 2;
const int startPin = 3;
Countimer timer;
// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status
int buttonStatered = 0;
int nDevices = 0;
bool devices[NODE_MAX];
bool solved[NODE_MAX];
int strike = 0;
int nSolved = 0;
void setup() {
  // initialize the pushbutton pin as an input:
  pinMode(startPin, INPUT);
  digitalWrite(startPin, HIGH);
  pinMode(stopPin, INPUT);
  digitalWrite(stopPin, HIGH);
  Serial.begin(9600);
  Wire.begin(MASTER_ADDRESS);
  Wire.onReceive(receiveEvent);
  timer.setCounter(COUNTDOWN_HOURS, COUNTDOWN_MINS, COUNTDOWN_SECS, timer.COUNT_DOWN, onComplete);
  timer.setInterval(refreshClock, 1000);
}

void loop() {
  // read the state of the pushbutton value:
  timer.run();
  buttonState = digitalRead(startPin);
  buttonStatered = digitalRead(stopPin);
  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonStatered == LOW) {

    for (int i = 0; i < NODE_MAX; i++) {
      if (devices[i] == 1) {
        while(Wire.available()){
          Wire.beginTransmission(i);
          Wire.write(MASTER_END);
          Wire.endTransmission();
        }
      }
    }
    clearAll();
  }
  if (buttonState == LOW && timer.isStopped()) {
    nDevices = 0;
      timer.start();
    byte data = 0;
    for (byte addr = 2; addr <= 9; addr++) {
      byte rc = twi_writeTo(addr, &data, 0, 1, 1);
      if (rc == 0 ) {
        Serial.println("device found at address ");
        Serial.println(addr, DEC);
        devices[addr] = true;
        nDevices++;
        Wire.beginTransmission(addr);
        Wire.write(MASTER_START);
        Wire.endTransmission(addr);
      }
    }
    delay(100);
  }
}

void testSolved() {
  for (int j =  0; j < NODE_MAX; j++) {
    if (devices[j] == true & solved[j] == true) {
      Serial.print("Solved addr: ");
      Serial.println(j, DEC);
      nSolved++;
    }
  }
  delay(100);
  if (nSolved == nDevices) {
      for (int i = 0; i < NODE_MAX; i++) {
    if (devices[i] == 1) {
      if (Wire.available() != 0) {
        Wire.beginTransmission(i);
        Wire.write(MASTER_END);
        Wire.endTransmission();
      }
    }
  }
    Serial.print("All Devices solved!");
    delay(150);
    clearAll();
  }
}
void clearAll(){
  timer.stop();
  nSolved=0;
  strike=0;
  nDevices=0;
  for (int i = 0; i < NODE_MAX; i++) {
    devices[i]=false;
    solved[i]=false;
  }
 
}
void receiveEvent(int bytes) {
  byte b;
  if (Wire.available() != 0) {
    for (int i = 0; i < bytes; i++) {
      b = Wire.read();
    }
  }
  delay(100);
  if ((b & BIT_MASK) == SLAVE_SOLVED) {
    nSolved = 0;
    byte temp = (b >> 4);
    if(solved[(int)temp]==false){
    solved[(int)temp] = true;
   
    testSolved();
   
    }
    /* OPTIONAL:
        if(solved[deviceID]){
        //Do ...
        }
    */
  }
  else if ((b & BIT_MASK) == SLAVE_STRIKE) {
    strike++;
    Serial.println("Strike!");
    if (strike == STRIKE_MAX) {
      for (int j = 0; j < NODE_MAX; j++) {
        solved[j] = false;
      }
    for (int i = 0; i < NODE_MAX; i++) {
    if (devices[i] == 1) {
      if (Wire.available() != 0) {
        Wire.beginTransmission(i);
        Wire.write(MASTER_UNSOLVE);
        Wire.endTransmission();
      }
    }
  }
      Serial.println("Max Strikes reached, unsolved slaves");
      strike = 0;
    }
  }
}

void refreshClock() {
  Serial.print("Current count time is: ");
  Serial.println(timer.getCurrentTime());
}


void onComplete() {
  Serial.println("Time is up!");
  for (int i = 0; i < NODE_MAX; i++) {
    if (devices[i] == 1) {
      if (Wire.available() != 0) {
        Wire.beginTransmission(i);
        Wire.write(MASTER_FAIL);
        Wire.endTransmission();
      }
    }
  }
  delay(100);
  timer.stop();
  asm volatile("jmp 0");

}



SLAVES
Code: [Select]
#include <Wire.h>

#define MASTER_END 0x02
#define MASTER_FAIL 0x01
#define MASTER_START 0x03
#define MASTER_UNSOLVE 0x04
#define MASTER_ADDRESS 42
#define SLAVE_STRIKE 0x02
#define SLAVE_SOLVED 0x03

//Currently DEVICE_ID= 2-15 supported
#define DEVICE_ID 2 //decimal, start at 2, don't go lower
const int strikeButton = 2;
const int solveButton = 3;
bool started = false;
bool solved = false;
const byte strikeCode = (DEVICE_ID << 4) + SLAVE_STRIKE;
const byte solvedCode = (DEVICE_ID << 4) + SLAVE_SOLVED;
void setup() {
  // put your setup code here, to run once:
  pinMode(strikeButton, INPUT);
  digitalWrite(strikeButton, HIGH);
  pinMode(solveButton, INPUT);
  digitalWrite(solveButton, HIGH);
  Wire.begin(DEVICE_ID);
  Wire.onReceive(receiveEvent);
  Serial.begin(9600);
}

void loop() {
  //Wire.onReceive(receiveEvent);
  // put your main code here, to run repeatedly:
  int buttonStateStrike = digitalRead(strikeButton);
  int buttonStateSolved = digitalRead(solveButton);
  while (started && !solved) {
    //DO THINGS
    if (buttonStateStrike == LOW) {
      Serial.println("Strike!");
      Wire.beginTransmission(MASTER_ADDRESS);
      Wire.write(strikeCode);
      Wire.endTransmission();
    }
    else if (buttonStateSolved == LOW) {
      Serial.println("Solved!");
      Wire.beginTransmission(MASTER_ADDRESS);
      Wire.write(solvedCode);
      Wire.endTransmission();
      //Serial.print(solvedCode, HEX);
      solved = true;
    }
   }
    delay(150);
  }

  void receiveEvent(int bytes) {
    byte b;
    if (Wire.available() != 0) {
      for (int i = 0; i < bytes; i++) {
        b = Wire.read();
        //Serial.println(b, HEX);
      }
    }
    if (b == MASTER_START) {
      started = true;
      solved = false;
    }
    if (b == MASTER_UNSOLVE) {
      asm volatile("jmp 0");
      //started = true;
      //solved = false;
    }
    else if (b == MASTER_END) {
      started = false;
    }
    else if (b == MASTER_FAIL) {
      //FULL RESET
      asm volatile("jmp 0");
    }
  }

HotSystems

Deine Aussage "Ich habe Probleme mit dem Master" ist nicht hilfreich.
Beschreibe mal genauer, was deine Probleme sind.

Und ganz wichtig, setze deinen Sketch in Code-Tags, Schaltfläche </> oben links im Editorfenster.
Dann können wir deinen Sketch besser lesen.
Auch auf mobilen Geräten.
I2C = weniger ist mehr: weniger Kabel, mehr Probleme. 8)

uwefed

Code: [Select]
  asm volatile("jmp 0");
Wieso resetierst Du den Arduino?

HotSystems

#3
Nov 14, 2017, 11:14 am Last Edit: Nov 14, 2017, 11:25 am by HotSystems
Danke an Uwe.
Jetzt erkenne ich, dass innerhalb des Sketches auch eine Beschreibung steht.

Leider ist der Copy&Paste-Sketch sehr unübersichtlich, es fehlen einfach Erklärungen im Sketch.

Warum fragst du nicht den Autor, welches Problem dich bedrückt ?

Edit:
Bei I2C muss der Slave dem Master mitteilen, wenn er Daten hat und der Master muss diese vom Slave abholen. Das kann ich leider aus deinem Sketch nicht erkennen.

Und anhand dieser Beispiele kannst du sehen, wie Master/Slave aufgebaut werden können.
I2C = weniger ist mehr: weniger Kabel, mehr Probleme. 8)

fetterspanier

Sry für das Chaos, habe es erstmal in überschaubare Bahnen gelenkt.

Code: [Select]
  asm volatile("jmp 0");
Wieso resetierst Du den Arduino?
Welche Stelle genau meinst du? Da der Reset an einigen Stellen auftaucht.

fetterspanier

Habe oben noch eine ausführlichere Beschreibung ergänzt. Sry war Gestern einfach shcon zu spät  :)

uwefed

#6
Nov 14, 2017, 01:43 pm Last Edit: Nov 14, 2017, 01:43 pm by uwefed
Welche Stelle genau meinst du? Da der Reset an einigen Stellen auftaucht.
Alle Stellen.

DrDiettrich

Der Code ist - sagen wir mal - recht abenteuerlich. Hat da jemand I2C etc. nicht richtig verstanden, oder nur von jemand abgeschrieben, der vieles nicht verstanden hat?

Frage für den Anfang: wie verteilst Du die IDs an die Slaves?

DrDiettrich

Bei I2C muss der Slave dem Master mitteilen, wenn er Daten hat und der Master muss diese vom Slave abholen. Das kann ich leider aus deinem Sketch nicht erkennen.
Jeder Knoten ist Bus-Master, so lange er Daten verschickt. Genaugenommen sollte man hier zwischen logischen Server und Clients unterscheiden, die Daten beliebig senden und empfangen können. Dann schickt der Server Kommandos an die Clients, und die Clients schicken Statusmeldungen an den Server. So soll das zumindest irgendwann ablaufen, wenn der Code bereinigt ist :-]

fetterspanier

Frage für den Anfang: wie verteilst Du die IDs an die Slaves?
Die IDs werden beim Hochladen vorher fest vergeben, also geändert und dann hochgeladen. Eine automatische Generierung wäre mir natürlich lieber aber das ist eine andere Baustelle.

Der ursprüngliche Code wurde durch jemanden erstellt, der den auftrag hatte diese Kommunikation herzustellen. Dieses wurde dann abgeliefert und leider ist die Person nicht mehr erreichbar um es zu retten. Das Projekt lag daher eine Weile in der Ecke, wird nun aber doch gebraucht. Leider kann ich ihn selber nicht 100% durschauen, daher fällt mir die Behebung deutlich schwerer. Ich weiß nicht was leichter wäre an dieser Stelle. selber neu anfangen oder mit dem Gerüst arbeiten?!


combie

#10
Nov 14, 2017, 06:40 pm Last Edit: Nov 14, 2017, 06:41 pm by combie
Quote
Genaugenommen sollte man hier zwischen logischen Server und Clients unterscheiden,
Natürlich nicht!
Das ist das völlig falsche Vokabular.
Die Semantik ist kaputt.

Es heißt Master und Slave.
Damit sind die Rollen klar verteilt.

Nachweis:
Quote
Dann schickt der Server Kommandos an die Clients
Wenn schon Klient und Server, dann muss bitte der Klient die Kommunikation anstoßen.
Ein Server wird NIE aus eigener Kraft aktiv.


"Freiheit, Gleichheit, Brüderlichkeit!"
Aber wie gelangen wir zu den Tätigkeitswörtern?
Quelle: Stanislaw Jerzy Lec

agmue

#11
Nov 14, 2017, 06:58 pm Last Edit: Nov 14, 2017, 06:59 pm by agmue
SLAVES erzeugt folgende, wohl auch ernstzunehmende Warnung:

Test_Forum.ino: In function 'void receiveEvent(int)':
Test_Forum.ino:75:10: warning: 'b' may be used uninitialized in this function [-Wmaybe-uninitialized]

fetterspanier

SLAVES erzeugt folgende, wohl auch ernstzunehmende Warnung:

Test_Forum.ino: In function 'void receiveEvent(int)':
Test_Forum.ino:75:10: warning: 'b' may be used uninitialized in this function [-Wmaybe-uninitialized]

Die Meldung bekomme ich nicht. Komisch.

combie

Die Meldung bekomme ich nicht. Komisch.
In den Einstellungen kannst du die Anzeige der Meldungen aktivieren.
"Freiheit, Gleichheit, Brüderlichkeit!"
Aber wie gelangen wir zu den Tätigkeitswörtern?
Quelle: Stanislaw Jerzy Lec

fetterspanier

In den Einstellungen kannst du die Anzeige der Meldungen aktivieren.
Ah thx, jetzt sehe ich es auch.

Go Up