Zwei serielle Schnittstellen mit Nano: welche Libraries?

Hallo,

Tx/Rx liegen Idle immer auf High. Klemme die Led+R zwischen Signal und 5V. Das Signal mit der Led nicht zu stark belasten.

Was macht deine Debouncer Funktion?
Muss man die Software Seriellen Pins wirklich selbst mittels pinmode konfigurieren? Ich glaube eher nicht.
Sind alle GNDs verbunden?
Schon mit 9600 Baud probiert?
Nicht kompilierbarer Code ist auch Mist. Erscheint denn immer auf Tastendruck "Send ..."?
Wenn nicht ein Grund mehr die Debouncer Funktion zu untersuchen oder gleich richtig entprellen.

(deleted)

Doc_Arduino:
Hallo,

Tx/Rx liegen Idle immer auf High. Klemme die Led+R zwischen Signal und 5V. Das Signal mit der Led nicht zu stark belasten.

Ja, danke.Ich habe inzwischen mit einem Logikanalysator gesehen, dass die Bits mit fallender Flanke gesendet werden - das Ding sendet auch. Das Problem war primär vor der Tastatur und zweitens im Empfänger-Nano.

Doc_Arduino:
Was macht deine Debouncer Funktion?

Ziemlich elegant Tasten entprellen. Ist ein Fund aus dem Netz und funktioniert prima; ich verwende den standardmäßig schon lange.

Doc_Arduino:
Muss man die Software Seriellen Pins wirklich selbst mittels pinmode konfigurieren? Ich glaube eher nicht.

Nein, das war die Verzweiflung…

Doc_Arduino:
Sind alle GNDs verbunden?

Ja.

Doc_Arduino:
Schon mit 9600 Baud probiert?

Geht leider nicht, der MODBUS ist vorgegeben und läuft eben auf 19200.

Doc_Arduino:
Nicht kompilierbarer Code ist auch Mist. Erscheint denn immer auf Tastendruck “Send …”?
Wenn nicht ein Grund mehr die Debouncer Funktion zu untersuchen oder gleich richtig entprellen.

Der Code ist nicht allzu lang, deswegen hier mal beide. Das erste ist der Simulator, das zweite der Slave. Heißen leider beide main.cpp.

main.cpp (5.77 KB)

main.cpp (8.01 KB)

Hallo,

also die Debouncer Funktion ist doch irgendwie sinnfrei oder nicht?
Sie wird ständig außerhalb der Wartezeit aufgerufen und schiebt nur Bits zur Seite. Der Effekt soll scheinbar ein Monoflop sein, sodass nur auf erneuten Tastendruck hin eine Aktion ausgelöst wird. Funktionieren tut das hier nur, weil die Wartezeit 5s lang ist. Nimmt man übliche 30ms kommt es vor das auch beim loslassen eine Aktion ausgelöst wird. Wundert einem nicht wirklich, da mit dem ständigen Bit schieben nur Rechenzeit teuer verschwendet wird. Es findet keine echter Vergleich des Tasterzustandes vorher/nachher statt. Wer weiß wofür das einmal gedacht war.

Hänge Dich nicht an dem Debouncer auf - hier ist eine ausführliche Erklärung, falls es Dich doch nicht loslässt: Debouncer .
Rechenzeit ist bei diesem Simulator völlig egal, der soll ja nur die Schnittstelle testen und wird danach wieder in die Tonne gekloppt. Die 5s sind willkürlich von mir eingebaut, um meine Zitterfinger am schnellen Doppelklick zu hindern.

Ich habe das Problem geknackt - puuuuuh! Es liegt an den Leseschleifen mit “while(MODBUS.available()…”. Die terminieren immer wieder, bevor das ganze Datenpaket durch ist, wodurch es auf der Empfängerseite verworfen wird.

Die Lösung ist diese Konstruktion:

while(MODBUS.available() && outPacketLen<OUTPACKETSIZE)
{
  while(MODBUS.available() && outPacketLen<OUTPACKETSIZE)
  {
    outPacket[outPacketLen++] = MODBUS.read();
  }
  delay(1);
}

Der “delay(1)” sorgt scheinbar dafür, dass wieder komplette Zeichen bereitstehen und die Schleife weiter laufen kann.

Hallo,

naja, will ja nichts sagen, aber die Debouncer Funktionsweise im Original ist anders wie bei dir. Dann muss mich auch nichts wundern warum das bei dir so seltsam nicht stabil funktioniert. Genauso versuchst du jetzt ein grundlegendes Problem mit delay lösen zu wollen mit 2 gleichen while. Kommt dir das nicht auch seltsam vor?

Doc_Arduino:
Hallo,

naja, will ja nichts sagen, aber die Debouncer Funktionsweise im Original ist anders wie bei dir. Dann muss mich auch nichts wundern warum das bei dir so seltsam nicht stabil funktioniert. Genauso versuchst du jetzt ein grundlegendes Problem mit delay lösen zu wollen mit 2 gleichen while. Kommt dir das nicht auch seltsam vor?

Ahem...

  • Debouncer: Wo ist der anders als im Original? Ich meine, semantisch, nicht syntaktisch? Und der Button ist doch gar nicht das Problem gewesen, sondern die serielle Übertragung ???
    Und deren Problem lag, wie ich oben schrob, auf der Empfängerseite, die nix mit dem Button zu tun hat.
  • while-Schachtelung: Auch das hat Vorbilder im Netz. Ich vermeide delay() wegen der Nebenwirkungen auch weitgehend, aber bei 1ms sind die gering genug, denke ich. Wenn ich eine Konstruktion mit millis() nähme, wäre das sicher nebenwirkungsfreier, aber aufwendiger zu schreiben.
    Und die Erklärung, warum das so funktioniert und anders nicht, weil nicht schnell genug weitere Zeichen ankommen, finde ich auch einleuchtend - Du nicht? Ich weiß nämlich nicht a priori, wie lang ein eintreffender MODBUS-Request ist, da gibt es alles von 5 bis 100 Byte und mehr. Ich muss strenggenommen sogar noch eine while(MODBUS.available()...)-Schleife dahinter hängen, um überlange Requests "wegzulesen".
    Dass mein Client nur auf eine spezielle Requestart wartet, schert den Rest der Busteilnehmer nicht, also muss ich die verkraften.

Hallo,

ich schaue mir soweit mir möglich immer alles an.

Wenn man die Verzögerung gleich setzt, was ist denn der Unterschied im Ablauf?
Die Frage kann ich nicht näher präzisieren, sonst gebe ich die Antwort vor.

zwischen Original

void loop(void)
{
   button_press_and_action();
   delay(5000);
}

und deinem

void loop() 
{
  if(millis()>waitUntil && Debouncer(digitalRead(3)))
  {
    // irgendeine Aktion ...
    waitUntil = millis() + 5000;
  }
}

Zudem deine millis Anwendung Probleme macht beim Bereichsüberlauf.

Wegen deinem seriellen Problem. Stichwort Terminierung. Erkennung wann die Übertragung komplett ist.

Doc_Arduino:
Hallo,

ich schaue mir soweit mir möglich immer alles an.

Klasse, und da bin ich auch durchaus dankbar für! :slight_smile:

Doc_Arduino:
Wenn man die Verzögerung gleich setzt, was ist denn der Unterschied im Ablauf?
Die Frage kann ich nicht näher präzisieren, sonst gebe ich die Antwort vor.

Im Falle mit millis() verhindere ich nur, dass nochmal der Button während der 5s gedrückt werden kann, alles andere (Warten auf Antwort usw.) läuft ja weiter. Mit delay() steht der Prozessor quasi, es passiert nix anderes - meintest Du das?

Doc_Arduino:
Zudem deine millis Anwendung Probleme macht beim Bereichsüberlauf.

Wenn ich mehr als 53 Tage ohne Neustart an dem Ding sitze und teste, habe ich ein ganz anderes Problem :smiley:
In für längere Zeit geschriebenen Sketchen benutze ich millis()-Timer mit Überlauferkennung.

Doc_Arduino:
Wegen deinem seriellen Problem. Stichwort Terminierung. Erkennung wann die Übertragung komplett ist.

Da musst Du die MODBUS-Erfinder ausgraben und nochmal postum ohrfeigen... Die Standardfunktionen sind noch unproblematisch, da weiß man die Länge und in den Responses steht sie relativ weit vorne drin. Das Problem sind die User Function Codes, denn da ist außer den ersten 2 Byte (SlaveID und Function Code) nichts mehr vorgegeben, und da gibt es leider Wildwuchs.
Ich helfe mir jetzt, indem ich das SlaveID-Byte, das als erstes kommt, gleich in der Leseschleife abfrage und nur noch in den Eimer lese, wenn das Paket nicht für mich ist. Das schützt halbwegs vor den User Function Code-Paketen.

Hallo,

meinte ich leider nicht. Der Autor schreibt dass man seine Debouncer Funktion nicht zu oft aufrufen soll. Also nicht ungebremst laufen lassen darf. Deswegen bremst er das vereinfacht für die Demo mit 1ms delay. Ungebremst tritt mein beschriebener Effekt auf, dass völlig sinnlos ständig Bits geschoben werden, was zu Fehlfunktion führt.

Du hast allerdings die Aufrufbremse außer Kraft gesetzt. Wenn deine Wartezeit vorbei ist, wird bei dir die Debouncer Funktion ständig aufgerufen, also ständig Bits geschoben. Genau dann funktioniert es nicht mehr richtig. Weil es reiner Zufall ist wo sich das zu schiebende Bit befindet zum Zeitpunkt des erneuten Taster drückens.

Warum wird sie ständig aufgerufen. Weil die erste Bedingung der UND Verknüpfung erfüllt ist und auf die zweite Bedingung gewartet wird.

Damit ist der gute Code des nicht retriggbaren Monoflops futscht. Deswegen dein “Zitter” Problem, was nicht von dir kommt, sondern vom ständigen Aufruf. :slight_smile:

Umgebaut wie folgt, die update Funktion ist wie gezeigt nur für den einen Taster gedacht:

const byte pinTaster = 2;

void setup(void)
{
  pinMode(pinTaster, INPUT);
  Serial.begin(115200);
  Serial.println("\nStart");
}

void loop(void) {

  if (updateTaster (pinTaster, 3) )
  {
    Serial.print(F("Taster wurde "));
    button_press_action();
    Serial.println(F(" mal gedrückt"));
  }
}


/////////////////////////////////////////////////////////////////

void button_press_action(void)
{
  static unsigned long count = 0;
  Serial.print(++count);
}


bool updateTaster (const byte pin, unsigned int interval)
{
  bool state = false;
  static unsigned long lastMillis = 0;
  unsigned long ms = millis();

  if (ms - lastMillis >= interval)
  {
    lastMillis = ms;

    static uint16_t btndbc = 0;
    btndbc = (btndbc << 1) | (!digitalRead(pin)) | 0xe000;
    if (btndbc == 0xf000) {   // High for 1 bits low for 12 (each bit is 1 loop thru this code).
      state = true;
    }
  }
  return state;
}

Intervall 3 ergibt mit 12 mal Bit schubsen gebräuchliche Entprellzeiten von 36ms bis seine Auswertung gültig wird. Ich nutzte gewöhnlich 30-40ms. Kannst mal einen Testsketch schreiben um deine Fingerschnelligkeit festzustellen. Also wie lange du beim drücken auf dem Taster bleibst bzw. wie schnell du den Finger überhaupt wieder runterbekommst. Ich war erstaunt wie langsam mein Finger zucken ist. :slight_smile:

Ah, ich verstehe. Danke, merke ich mir für das nächste Mal.