RFID Reader scheint Funksender Inputs zu blockieren oder zu überschreiben

Hallo meine Lieben,

seid 3 Tagen versuche ich nun mein Problem zu beheben. Erfolglos. Ich hoffe ihr könnt mir weiterhelfen.

Platinenbeschreibung:
Arduino Nano
Der Funksender und Empfänger XLC-RF-5V (Sender an Pin 10, Empfänger an Pin 2)
ein Relais das eine JBL GO Box ein/ausschaltet (Pin A3)
ein RFID Reader RDM6300 (TX an Pin 5)
DFPlayerMini (RX an 9, TX an 11)
12V zu 5V Step Down Converter
Elkos und Dioden zur Absicherung gegen Spannungsspitzen etc

Projektbeschreibung:
Das Projekt lässt einen Papagei in einem Käfig zum Leben erwecken. Aktuell kann er wenn er das Funksignal dazu erhält, verschiedene Songs/Sounddateien zum besten geben. Außerdem kann per Funk die Box aus/eingeschaltet werden. Wenn nun ein RFID Chip (In einer Gurke verbaut) in den Futternapf gelegt wird, so wird eine spezielle Sounddatei mehrfach (Aktuell auf 3x beschränkt) ausgegeben.
Soweit so gut, dass funktioniert auch alles.

Problem:
Sobald die Gurke im Futternapf liegt, wird sie permanent ausgelesen. Wenn währenddessen ein Funksignal eintrifft, so wird dies nur in seltenen Fällen ausgelesen. Sollte aber zuverlässig ausgelesen werden, auch wenn die Gurke im Futternapf liegen bleibt.

Hier mein Code, es kann sein das ein zwei Fehleranalysezeilen noch dazwischen hängen, die dürft ihr gerne überlesen.

#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
#include <RCSwitch.h>

const int BUFFER_SIZE = 14; // RFID DATA FRAME FORMAT: 1byte head (value: 2), 10byte data (2byte version + 8byte tag), 2byte checksum, 1byte tail (value: 3)
const int DATA_SIZE = 10; // 10byte data (2byte version + 8byte tag)
const int DATA_VERSION_SIZE = 2; // 2byte version (actual meaning of these two bytes may vary)
const int DATA_TAG_SIZE = 8; // 8byte tag
const int CHECKSUM_SIZE = 2; // 2byte checksum
SoftwareSerial ssrfid = SoftwareSerial(5,8);
uint8_t buffer[BUFFER_SIZE]; // used to store an incoming data frame
int buffer_index = 0;

RCSwitch mySwitchEmpfang = RCSwitch(); // Funkempfänger
RCSwitch mySwitchSender = RCSwitch(); //Funksender

SoftwareSerial mySoftwareSerial(9,11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);

#define Box A3

int freundlichkeit, gurkencount = 0; //0 = Kinderfreundlich - 1 = nicht kinderfreundlich
unsigned long gurkenzeitpunkt, jetzt, zuletztrfid;

void setup()
{
  Serial.begin(115200);
  
  mySoftwareSerial.begin(9600);
  
  pinMode(Box, OUTPUT);
  digitalWrite(Box, HIGH);
  delay(1000);
  digitalWrite(Box, LOW);
  
  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
  
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while(true);
  }
  
  myDFPlayer.setTimeOut(500); //Set serial communictaion time out 500ms
  myDFPlayer.volume(20);  //Set volume value (0~30).
  myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);

  ssrfid.begin(9600);
  ssrfid.listen();

  mySwitchEmpfang.enableReceive(0);  // Empfänger ist an Interrupt-Pin "0" - Das ist am UNO der Pin2
  mySwitchSender.enableTransmit(10);  // Der Sender wird an Pin 10 angeschlossen
}

void loop(){
  // Funkempfänger abfrage  
 if (mySwitchEmpfang.available()) // Wenn ein Code Empfangen wird...
  {
    int value = mySwitchEmpfang.getReceivedValue(); // Empfangene Daten werden unter der Variable "value" gespeichert.
  
    if (value == 0) // Wenn die Empfangenen Daten "0" sind, wird "Unbekannter Code" angezeigt.
    {
      Serial.println("Unbekannter Code");
    } else {
      Serial.print("Empfangen: ");
      Serial.println( value );

    switch(value){
      case 9000:      //Kinderfreundlich
        mySwitchSender.send(9001, 24); // Bestätigung senden
        freundlichkeit = 0;
        break;
        
      case 9010:      //unfreundlich
        mySwitchSender.send(9011, 24); // Bestätigung senden
        freundlichkeit = 1;
        break;
          
      case 9015:      //Box Schalter betätigen
        digitalWrite(Box, HIGH);
        delay(1000);
        digitalWrite(Box, LOW);
        break;
        
      case 9020:      //Gurkenhinweis ausgeben
        mySwitchSender.send(9021, 24); // Bestätigung senden
        myDFPlayer.play(1);
        break;
  
      case 9030:      //Spruch 1
        mySwitchSender.send(9031, 24); // Bestätigung senden
        myDFPlayer.play(2);
        break;
      
      case 9040:      //Spruch 2
        mySwitchSender.send(9041, 24); // Bestätigung senden
        myDFPlayer.play(3);
        break;
        
      case 9050:      //Spruch 3
        mySwitchSender.send(9051, 24); // Bestätigung senden
        myDFPlayer.play(4);
        break;
        
      case 9060:      //Spruch 4
        mySwitchSender.send(9061, 24); // Bestätigung senden
        myDFPlayer.play(5);
        break;
        
     case 9070:      //Spruch 5
        mySwitchSender.send(9071, 24); // Bestätigung senden
        myDFPlayer.play(6);
        break;
  
      default:
        Serial.println("Ungültiges Kommando");
        break;
  }
    }
    mySwitchEmpfang.resetAvailable(); // Hier wird der Empfänger "resettet"
  }

  //RFID Abfrage
  static unsigned long jetzt2, letzte = 0;
  jetzt2 = millis();
    if ((ssrfid.available() > 0) && (letzte + 500 < jetzt2)) {
       bool call_extract_tag = false;
       int ssvalue = ssrfid.read(); // read
       if (ssvalue == -1) { // no data was read
         return;
       }
       if (ssvalue == 2) { // RDM630/RDM6300 found a tag => tag incoming
         buffer_index = 0;
       } else if (ssvalue == 3) { // tag has been fully transmitted
         call_extract_tag = true; // extract tag at the end of the function call
       }
       if (buffer_index >= BUFFER_SIZE) { // checking for a buffer overflow (It's very unlikely that an buffer overflow comes up!)
         Serial.println("Error: Buffer overflow detected!");
         return;
       }
  
       buffer[buffer_index++] = ssvalue; // everything is alright => copy current value to buffer
       if (call_extract_tag == true) {
        letzte = millis();
         if (buffer_index == BUFFER_SIZE) {
           unsigned tag = extract_tag();
             //Kontrolle ob es der richtige Chip zur aktuellen Reihenfolgenposition ist
             if (tag == 33672) {
              jetzt = millis();
              //Kontrolle wie oft der Sound bereits abgespielt wurde
              if(gurkencount < 3) {
                 if((gurkenzeitpunkt == 0) || (gurkenzeitpunkt + 10000) < jetzt) {
                   Serial.println("Herzlichen Glückwunsch Sie haben die Gurke in den Futternapf gelegt.");
                   gurkenzeitpunkt = millis();
                   gurkencount++;
                   myDFPlayer.play(1);
                   while (ssrfid.available() > 0) {
                      ssrfid.read();
                    }
                 }
              } else {
                //Es wurde 3x abgespielt & es ist Zeit vergangen
                if(((gurkenzeitpunkt + 10000) < jetzt) && ((zuletztrfid + 5000) < jetzt)) {
                  gurkencount = 0;
                  gurkenzeitpunkt = 0;
                }
              }
              zuletztrfid = jetzt;
             } else {
               Serial.print("Der Falsche aufgelegt: ");
               Serial.println(tag);
             } 
         } else { // something is wrong... start again looking for preamble (value: 2)
           buffer_index = 0;
           return;
         }
       }
    }
   
//Der restliche Code im nächsten Post

Wenn ihr mich der Lösung näher bringt, wäre ich dafür sehr dankbar, nach 20h Fehlersuche, bin ich einfach gefrustet.

Liebe Grüße,
Faror

ps.: Da mein Post die 9000 Zeichen überschreitet, verschiebe ich einen Teil des Codes in den folgenden Post

  if(Serial.available()){
    readCommand();
  }

  if (myDFPlayer.available()) {
    printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states.
  }
}

void readCommand(){
  char cmd = ' ';
  int value1, value2 = 0;
  cmd = Serial.read();
  value1 = Serial.parseInt();
  value2 = Serial.parseInt();
 
  switch(cmd){
    case 'h': 
      printHelp();
      break;
      
    case '>':
      myDFPlayer.next();
      break;
      
    case '<':
      myDFPlayer.previous();
      break;
      
    case 'p':
      if(value2 == 0) myDFPlayer.play(value1);
      else if(value1 != 0) myDFPlayer.playFolder(value1, value2);
      break;

    case 'P':
      if(value2 == 0) myDFPlayer.playMp3Folder(value1); 
      else if(value1 != 0)myDFPlayer.playLargeFolder(value1, value2);
      break;
    
    case '+':
      myDFPlayer.volumeUp(); 
      break;
      
    case '-':
      myDFPlayer.volumeDown();
      break;
      
    case 'v':
      myDFPlayer.volume(value1);
      break;
      
    case 'b':
      myDFPlayer.pause();
      break;

    case 's':
      myDFPlayer.start();
      break;
          
    case 'z':
      myDFPlayer.sleep();
      break;
      
    case 'L':
      if(value1 == '0') myDFPlayer.enableLoopAll();
      else myDFPlayer.loopFolder(value1);
      break;
    
    case 'l':
      if(value1 == '0') myDFPlayer.disableLoopAll();
      else myDFPlayer.loop(value1);
      break;
    
    case 'A':
      myDFPlayer.advertise(value1);
      break;
    
    case 'a':
      myDFPlayer.stopAdvertise();
      break;
    
    case 'q':
      if(value1 == 1) Serial.println(myDFPlayer.readState()); 
      else if(value1 == 2) Serial.println(myDFPlayer.readVolume());
      else if(value1 == 3) Serial.println(myDFPlayer.readEQ());
      else if(value1 == 4) Serial.println(myDFPlayer.readFileCounts());
      else if(value1 == 5) Serial.println(myDFPlayer.readFolderCounts());
      else if(value1 == 6) Serial.println(myDFPlayer.readCurrentFileNumber());
      break;
    default:
      Serial.println("Ungültiges Kommando");
      break;
  }

}

void printDetail(uint8_t type, int value){
  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerUSBInserted:
      Serial.println("USB Inserted!");
      break;
    case DFPlayerUSBRemoved:
      Serial.println("USB Removed!");
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }  
}
unsigned extract_tag() {
  uint8_t msg_head = buffer[0];
  uint8_t *msg_data = buffer + 1; // 10 byte => data contains 2byte version + 8byte tag
  uint8_t *msg_data_version = msg_data;
  uint8_t *msg_data_tag = msg_data + 2;
  uint8_t *msg_checksum = buffer + 11; // 2 byte
  uint8_t msg_tail = buffer[13];
  // print message that was sent from RDM630/RDM6300
  /** Serial.println("--------");
  Serial.print("Message-Head: ");
  Serial.println(msg_head);
  Serial.println("Message-Data (HEX): ");
  for (int i = 0; i < DATA_VERSION_SIZE; ++i) {
    Serial.print(char(msg_data_version[i]));
  }
  Serial.println(" (version)");
  for (int i = 0; i < DATA_TAG_SIZE; ++i) {
    Serial.print(char(msg_data_tag[i]));
  }
  Serial.println(" (tag)");
  Serial.print("Message-Checksum (HEX): ");
  for (int i = 0; i < CHECKSUM_SIZE; ++i) {
    Serial.print(char(msg_checksum[i]));
  }
  Serial.println("");
  Serial.print("Message-Tail: ");
  Serial.println(msg_tail);**/
  Serial.println("--");
  long tag = hexstr_to_value(msg_data_tag, DATA_TAG_SIZE);
  Serial.print("Extracted Tag: ");
  Serial.println(tag);
  long checksum = 0;
  for (int i = 0; i < DATA_SIZE; i += CHECKSUM_SIZE) {
    long val = hexstr_to_value(msg_data + i, CHECKSUM_SIZE);
    checksum ^= val;
  }
  Serial.print("Extracted Checksum (HEX): ");
  Serial.print(checksum, HEX);
  if (checksum == hexstr_to_value(msg_checksum, CHECKSUM_SIZE)) { // compare calculated checksum to retrieved checksum
    Serial.print(" (OK)"); // calculated checksum corresponds to transmitted checksum!
  } else {
    Serial.print(" (NOT OK)"); // checksums do not match
  }
  Serial.println("");
  Serial.println("--------");
  return tag;
}
long hexstr_to_value(char *str, unsigned int length) { // converts a hexadecimal value (encoded as ASCII string) to a numeric value
  char* copy = malloc((sizeof(char) * length) + 1);
  memcpy(copy, str, sizeof(char) * length);
  copy[length] = '\0';
  // the variable "copy" is a copy of the parameter "str". "copy" has an additional '\0' element to make sure that "str" is null-terminated.
  long value = strtol(copy, NULL, 16);  // strtol converts a null-terminated string to a long value
  free(copy); // clean up
  return value;
}

Ich vermisse Angaben darüber, wie du den RFID-Reader angeschlossen hast.
Ich kann nur vermuten an den Pins 10, 11, 12 und 13.
Wenn ja, ist der Pin 10 dein Problem.

Hat sich geklärt, habe ich übersehen.

Dein Problem liegt vermutlich an der doppelten Nutzung der SoftwareSerial.
Wenn der RFID per SoftwareSerial seine Anwesenheit meldet, wird wohl die Steuerung des MP3-Players versagen.

while (ssrfid.available() > 0) {
    ssrfid.read();
}

Kann es sein, dass dieses while blockierend wirkt, solange die Gurke im Napf liegt?

HotSystems:
Dein Problem liegt vermutlich an der doppelten Nutzung der SoftwareSerial.
Wenn der RFID per SoftwareSerial seine Anwesenheit meldet, wird wohl die Steuerung des MP3-Players versagen.

Danke erstmal HotSystems, dass du dich mit meinem Problem beschäftigst.
Die Steuerung des MP3-Players funktioniert weiter während die Gurke im Napf liegt. Ich kann per Serial Befehl vom PC aus z.B. das Lied das abgespielt wird wenn die Gurke im Napf liegt, überschreiben. Nach einigen Sekunden, wird dann dieses Lied wiederum vom RFID Reader überschrieben, was aber vom bisherigen Code so ist. Das Songs immer zu Ende gespielt werden müssen und danach erst der Song gewechselt wird, kommt heute dazu.
Das Problem, dass aber keine Funksignale mehr erkannt/ausgelesen (oder was auch immer genau das Problem ist) werden, während die Gurke im Napf liegt bleibt weiterhin bestehen.

Deltaflyer:

while (ssrfid.available() > 0) {

ssrfid.read();
}




Kann es sein, dass dieses **while** blockierend wirkt, solange die Gurke im Napf liegt?

Danke auch an dich DeltaFlyer, dass du dir mein Problem angesehen hast.
Die While schleife verlangsamt das Programm etwas, ich habe sie eingebaut um den RFID Buffer zu leeren und hoffe sie macht an dieser Stelle Sinn, habe sie aber auch schon an anderen Orten ausprobiert. Jedoch ändert sich an der funkblockade nichts, auch wenn ich diese Schleife ausklammer, habe es erfolglos probiert.

Dann wird es ein Problem mit dem Interrupt sein.

Der Funkempfänger arbeitet am PinD2 (IRQ0) und der wird vermutlich durch die serielle blockiert, die auch per IRQ arbeiten.

HotSystems:
Dann wird es ein Problem mit dem Interrupt sein.

Der Funkempfänger arbeitet am PinD2 (IRQ0) und der wird vermutlich durch die serielle blockiert, die auch per IRQ arbeiten.

Und was kann ich dagegen tun?

Software Serial kann nicht gleichzeitig Senden und Empfangen. Versuche mal AltSoftSerial. Das arbeitet mit einem Timer und ist daher zuverlässiger:
https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html

Ansonsten einen Arduino mit mehreren Hardware Schnittstellen verwenden

Serenifly:
Software Serial kann nicht gleichzeitig Senden und Empfangen. Versuche mal AltSoftSerial. Das arbeitet mit einem Timer und ist daher zuverlässiger:
AltSoftSerial Library, for an extra serial port

Ansonsten einen Arduino mit mehreren Hardware Schnittstellen verwenden

Das war die Lösung!
Ich habe meinen Arduino Nano gegen einen Arduino Mega getauscht. Nun habe ich die Anschlüsse des RDM6300 (RFID Modul) von Pin 5, 8 auf 18, 19 (Serieal1) gelegt. Nun musste ich nur noch den Aufruf von "ssrfid" auf Serial1 wechseln, so das auf einem anderen Seriellen Port parallel zum Funk gearbeitet werden konnte und schwupps, alles funktionierte. Vielen Dank für eure nützliche Hilfe!