Probleme mit Serial.available

Hallo an alle,
wie aus dem Titel zu erkennen ist habe ich Probleme mit dem Serial.available.

/*
 * See documentation at https://nRF24.github.io/RF24
 * See License information at root directory of this library
 * Author: Brendan Doherty (2bndy5)
 */

/**
 * A simple example of sending data from 1 nRF24L01 transceiver to another.
 *
 * This example was written to be used on 2 devices acting as "nodes".
 * Use the Serial Monitor to change each node's behavior.
 */
#include <SPI.h>
#include "printf.h"
#include "RF24.h"

#define ACK 9
#define Send 12
#define Read 13

int Steuerzeichen = 0;

// instantiate an object for the nRF24L01 transceiver
RF24 radio(9, 10);  // using pin 7 for the CE pin, and pin 8 for the CSN pin

// Let these addresses be used for the pair
uint8_t address[][6] = { "1Node", "2Node" };
// It is very helpful to think of an address as a path instead of as
// an identifying device destination

// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber = 1;  // 0 uses address[0] to transmit, 1 uses address[1] to transmit

// Used to control whether this node is sending or receiving
bool role = true;  // true = TX role, false = RX role

// For this example, we'll be using a payload containing
// a single float number that will be incremented
// on every successful transmission
float payload = NULL;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    // some boards need to wait to ensure access to serial over USB
  }

  // initialize the transceiver on the SPI bus
  if (!radio.begin()) {
    //    Serial.println(F("radio hardware is not responding!!"));
    while (1) {}  // hold in infinite loop
  }

  // print example's introductory prompt
  //  Serial.println(F("RF24/examples/GettingStarted"));

  // To set the radioNumber via the Serial monitor on startup
  //  Serial.println(F("Which radio is this? Enter '0' or '1'. Defaults to '0'"));
  //  Serial.print(F("radioNumber = "));
  //  Serial.println((int)radioNumber);

  // role variable is hardcoded to RX behavior, inform the user of this
  //  Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));

  // Set the PA Level low to try preventing power supply related problems
  // because these examples are likely run with nodes in close proximity to
  // each other.
  radio.setPALevel(RF24_PA_LOW);  // RF24_PA_MAX is default.

  // save on transmission time by setting the radio to only transmit the
  // number of bytes we need to transmit a float
  radio.setPayloadSize(sizeof(payload));  // float datatype occupies 4 bytes

  // set the TX address of the RX node into the TX pipe
  radio.openWritingPipe(address[radioNumber]);  // always uses pipe 0

  // set the RX address of the TX node into a RX pipe
  radio.openReadingPipe(1, address[!radioNumber]);  // using pipe 1

  // additional setup specific to the node's role
  if (role) {
    radio.stopListening();  // put radio in TX mode
  } else {
    radio.startListening();  // put radio in RX mode
  }

  // For debugging info
  // printf_begin();             // needed only once for printing details
  // radio.printDetails();       // (smaller) function that prints raw register values
  // radio.printPrettyDetails(); // (larger) function that prints human readable data

}  // setup

void loop() {
  if (Serial.available() > 0) {  // If anything comes in Serial (USB),
    Steuerzeichen = Serial.parseInt();
  }
  if (Steuerzeichen == Send) {
    radio.stopListening();
    Steuerzeichen = 0;
    Serial.println(ACK);

    while (Serial.available() == 0) {
      payload = Serial.parseInt();
      Serial.println(payload);
    }
    // This device is a TX node
    /*      unsigned long start_timer = micros();                // start the timer
      bool report = radio.write(&payload, sizeof(float));  // transmit & save the report
      unsigned long end_timer = micros();                  // end the timer
      
      if (report) {
        Serial.print(F("Transmission successful! "));  // payload was delivered
        Serial.print(F("Time to transmit = "));
        Serial.print(end_timer - start_timer);  // print the timer result
        Serial.print(F(" us. Sent: "));
        Serial.println(payload);  // print payload sent
        payload += 0.01;          // increment float payload
      } else {
        Serial.println(F("Transmission failed or timed out"));  // payload was not delivered
      }
*/
    // to make this example readable in the serial monitor
    Serial.println("loop");
    delay(100);  // slow transmissions down by 1 second
  }
}

und zwar in der void loop(), lese ich als erstes ein Zeichen ein (Steuerzeichen) und wenn dieses Steuerzeichen einen bestimmten Wert hat dann soll das Program auf ein weiteres Zeichen warten (das soll im späteren Verlauf dann per NRF24L01 versendet werden). Das Lesen des Steuerzeichens funktioniert auch problemlos. Die Abfrage in der while loop bleibt dann jedoch stur auf 0 obwohl aber Eingaben eingelesen werden. Das bedeutet das Program betritt die while loop und bleibt dann endlos darin gefangen da sich der Wert von Serial.available nicht mehr ändert obwohl die Variable payload sich ändert wenn was eingegeben wird. (ich hoffe das war verständlich). Wieso erkennt das Serial.available in der while loop abfrage nicht das ein Zeichen gelesen wurde?
Übersehe ich hier was und stelle mich nur doof an?
Vielen Dank schon mal im Vorraus,

LG Hansbeder

Vermutlich: Ja!

Vieles verstehe ich nicht!
z.B. payload = Serial.parseInt();
Warum parst man ein Int und stopft das Ergebnis in ein float?

Mein Rat:
Definiere ein Protokoll.
Wo klar wird, wo Daten beginnen, und enden.
Lese die Zeichen in einen Buffer.
Wenn Buffer gefüllt, dann parsen und weiter verarbeiten.

Hallo,

du hast mit

while (Serial.available() == 0) {

eine temporäre Endlosschleife bzw. eine Warteschleife. available() liefert ja 0 zurück wenn kein Zeichen im Empfangsbuffer steht. Das Programm kann auf nichts reagieren solange kein Zeichen ankommt, ist damit blockiert und das immer wieder aufs Neue.

Wie combie schreibt. Protokoll festlegen, Startkennung abfragen, wenn true, Zeichen in Buffer einlesen solange bis Endkennung erkannt wird. Buffer abschließen und verarbeiten. Im Normalfall genügt eine Endkennung ein LF. Also einlesen bis ein LF kommt oder was auch immer du als Endkennung festgelegt hast.

Hi Doc_Arduino,
die temporäre Endlosschleife war gewollt. Das Program soll darauf warten, dass ein Zeichen eingegeben wird (liest sogar Zeichen ein nur Serial.available() bleibt bei 0 und die Schleife wird nicht durchbrochen) das mit dem Protokoll muss ich mir morgen noch einmal ansehen. Mich verwundert nur das Verhalten von dem Serial.available(), da das ja eig. anzeigt wie viele byte im Buffer vorhanden sind (soweit ich das verstanden habe) und wenn er Zeichen in der Schleife liest, dann müssen ja dementsprechend Zeichen im Buffer gewesen sein nur zeigt das das Serial.available eben nicht an.

Vielen Dank schoneinmal

Vielen Dank, das mit dem Protokoll muss ich mir nochmal in Ruhe ansehen.

Hallo,

du musst dein Programm nicht pausieren lassen. Die Serielle kannste nebenbei abfragen in jeden loop Durchlauf. Stelle dir vor du hast einen Blinker programmiert. Die Led soll immer mit dem über Serial eingegeben Intervall blinken. Die Led würde nie blinken, weil das Programm immer auf Eingabe warten würde. Die Led kann aber blinken und sobald nebenbei ein neue Intervallvorgabe eintrudelt wird der Blinktakt beiläufig geändert. Kein delay, keine Warteschleifen. Die loop sollte immer durchlaufen werden können. Dann fühlt sich das an als wenn alles jederzeit reagiert und agiert.

Darauf habe ich aktuell keine Antwort. Kann viele Ursachen haben. Ich habe parseInt o.ä. bis heute noch nie benötigt. Immer nur available() und read() und eben einen Einlesebuffer.

Edit:
Liegt vermutlich an parseInt, macht bestimmt etwas anderes als du denkst?

  1. Keine Sorge... Serial.available() funktioniert perfekt!
  2. Keine Sorge... Serial.available() braucht man für sowas nicht.

Ein recht primitives Beispiel aus meiner Wühlkiste:


String buffer;

void setup() 
{
  buffer.reserve(20);
  Serial.begin(9600);
  Serial.println("Start");
}

void bearbeiteZahl(int zahl)
{
  Serial.print("Aufruf mit Zahl: "); Serial.println(zahl);

  while(zahl > 1) 
  {
    if(1 & zahl) // ungerade?
    {
      zahl *= 3;
      zahl -= 1;
    }else
    {
      zahl /= 2;
    }
    Serial.print("Berechnete Zahl: "); Serial.println(zahl);
  }
}

void serialEvent()
{
  char zeichen = Serial.read();
  int zahl = 0;
  switch(zeichen)
  {
    case '\r': /* fall through */
    case '\n':
          zahl = buffer.toInt();
          buffer = "";
          if(zahl) bearbeiteZahl(zahl);
          break;
          
    case '0' ... '9':           
          buffer += zeichen;
          break;
  }
}

void loop() 
{
}

Weil mit Serial.parseInt() der Puffer geleert wird, und damit bei der nächsten Abfrage der while-Bedingung wieder nichts im Puffer steht. Deine While-Abfrage funktioniert von der Logik so nicht (mal abgesehen davon, dass sie nicht nötig ist - wie ja schon mehrfach geschrieben wurde).

Hallo,

combie, String Buffer ohne feste Größe ist aber jetzt nicht dein ernst oder?

String hat nie eine feste Größe.
Bei mir sogar eine vorgegebene Minimalgröße.
Solange da ab und an mal ein Zeilenende kommt, sich der Sender an das Protokoll hält, geht alles gut.

Du darfst das gerne nach belieben aufpeppen.

Hallo,

nur String fragmentiert den Speicher eben wegen der ständigen Anpassung der Größe. Ich verwende immer ein char Array. Das Protokoll muss ja sowieso vorher bekannt bzw .festgelegt sein.

Hallo,
ich stimme Dir da eigentlich zu, char Arrays finde ich auch oft sinvoller. . Insbesondere beim UNO. Allerdings wenn, wie hier von der Seriellen immer das gleiche Protokoll mit der selben Länge kommt, gibt ja eigetntlich nichts was angepasst werden muss.
Zudem sind z.B beim ESP viele Funktionen mit Strings (objekte) vorhanden, und dann kann man die auch so übernehmen.
Heinz

Drum findest du in meinem Code auch ein

Das sollte deutlich reichen um die Fragmentierung zu unterbinden, solange nur ints gesendet werden.
(aber das sagte ich doch im vorherigen Post schon)

Also nein, keine Fragmentierung.

Kann man tun....
Aber eine Notwendigkeit gibts da nicht unmittelbar.

Hallo,

okay, hab verstanden, Mindestgröße 20 Zeichen, solange das reicht gibts keine gefürchtete Fragmentierung. Ehrlich gesagt hatte ich das reserve() glatt weg übersehen.
Danke Euch. Man lernt nie aus.
Weitermachen ... :wink:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.