Arduino zu langsam beim Lichtschranken Impuls zählen

Liebes Forum,

ich habe folgendes Problem welches ich einfach nicht gelöst bekomme:

Ich steuere mit dem Arduino (NANO, V3, CH340, IDE 1.8.0) einen DC Motor (ca. 200 rpm ). Eine Lichtschranke zählt die Umdrehungen und gibt den Wert auf einem LCD ( Hier LCD mit Keypad Board) weiter. Ein Schalter startet den Motor über ein Relais. Die Lichtschranke zählt bis ein bestimmter Wert an Umdrehungen erreicht ist und dreht dann über das Schalten eines zweiten Relais rückwärts für einen Wert an Umdrehungen und stoppt dann den Motor. Die Werte für die Umdrehungen können über Tasten verändert werden.

Das Problem ist, dass der Arduino zu viele Umdrehungen zählt und den Motor entsprechend zu früh stoppt. Auf dem LCD sieht man, dass sozusagen Zahlen übersprungen werden - 21, 22, 23, 25, 26 ... Ich habe mein Sketch auf Verzögerungen geprüft finde aber nichts, ich vermute es hängt mit dem debouncen zusammen.

Irgendwie komme ich nicht weiter, vielleicht finden ja hier einer den Fehler.

Vielen Dank im Vorraus

Code: (entschuldigt meine schlecht Programmierung bin Neuling

*WICHTIG
 * LCDKeypad shield is quite common and popular. It includes 16x2 HD44780 compatible LCD and 5 push buttons. Pins 4, 5, 6, 7, 8, 9 are used to interface with the LCD. Backlight on/off function is controlled via pin 10. Analog pin 0 is used to read the buttons.
LCD und tastn so anschließen.



  LCDKeypad Arduino library
  https://github.com/dzindra/LCDKeypad
  
  Copyright 2014 Jindřich Doležy (jindrich@dolezy.cz)
  based on the code by fj604 from http://forum.arduino.cc/index.php?topic=38061.0


  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include <LiquidCrystal.h>
#include <LCDKeypad.h>

LCDKeypad lcd;

const int zahlerPin = 2;
const int schalter1 = 3;
const int LEDpin = 13;

int relay1 = 11; 
int relay2 = 12; 

int zahlerState = 0;
int zahler = 0;
int zahlerStateHIGH = 0;
int ziel = 52;//Zaeler Wert der erreicht werden soll Vorwarts
//boolean relayState = false;
int relay1State = 0;
int backrpm = 3;//Zaeler Wert der erreicht werden soll Rueckwaerts
int menu = 0;
int ziel2 = ziel;//Zaeler Wert brrechnet




void setup() {
  lcd.begin(16,2);
  lcd.clear();
  
  lcd.print("");// TEXT
  lcd.setCursor(0,1);
  lcd.print(""); // TEXT
  
  delay(1000);
  lcd.clear();
  lcd.print("");//TEXT

  pinMode(zahlerPin, INPUT);
//   Serial.begin(9600);
// initialize digital pin LED_BUILTIN as an output.
  pinMode(relay1, OUTPUT);
pinMode(relay2, OUTPUT);
pinMode(schalter1, INPUT);
pinMode(LEDpin, OUTPUT);

}

static int counter = 0;

void loop() {
  // use buttonBlocking in menus or other cases
  // when you need repeated and debounced key presses
  // key direction will be returned once only for each blocking period (default 500ms)
  
  switch (lcd.buttonBlocking()) {
    case KEYPAD_LEFT:
      counter -= 10;
      menu = !menu;
      break;
    case KEYPAD_RIGHT:
      counter += 10;
lcd.setCursor(0,1);
 lcd.print("   ");
     zahler=0;
      break;
    case KEYPAD_DOWN:
      counter += 1;
       if(menu==1){
      ziel--;
      }else{
        backrpm--;
      }
      break;
    case KEYPAD_UP:
      counter -= 1;
      if(menu==1){
      ziel++;
      }else{
        backrpm++;
      }
      break;
    case KEYPAD_SELECT:
      counter = 0;
     relay1State = !relay1State;
      break;
  }

 // lcd.setCursor(9,0);  
 // lcd.print(counter);
 // lcd.print("   ");


zahlerState = digitalRead(zahlerPin);
 if (zahlerState == HIGH)
 {    
   zahlerStateHIGH = 1;
 }
 if (zahlerState == LOW && zahlerStateHIGH == 1)
 {
   zahler++;
   zahlerStateHIGH = 0;
 }
// Serial.println(counter);

lcd.setCursor(0,1);

 lcd.print(zahler);
lcd.setCursor(5,1);
 lcd.print(ziel);
 lcd.setCursor(9,1);
 lcd.print(backrpm);

 if(zahler>=ziel)
 {
  digitalWrite(relay1, LOW);   // turn the relay1 on (HIGH is the voltage level)
  lcd.setCursor(12,1);
 lcd.print("AUS");
 relay1State = 0;
 
 }
 else
{
  //digitalWrite(relay1, LOW);    // turn the LED off by making the voltage LOW
 lcd.setCursor(12,1);
 lcd.print("EIN");
// do Thing C
}
if (relay1State==HIGH){
  digitalWrite(relay1, HIGH);   // turn the relay1 on (HIGH is the voltage level)
}
else{
  digitalWrite(relay1, LOW);    // turn the LED off by making the voltage LOW
}
 lcd.setCursor(8,0);
 lcd.print(relay1State);

//--------------------Relay 2 Schalten---------------
ziel2=ziel + backrpm;
lcd.setCursor(0,0);
lcd.print(ziel2);

if(zahler>=ziel && zahler<=ziel2){
digitalWrite(relay2, HIGH);   // relay 2 ein
lcd.setCursor(12,0);
lcd.print("EIN");
}
else{
  digitalWrite(relay2, LOW);   // relay 2 aus
 lcd.setCursor(12,0);
 lcd.print("AUS");
}
int buttonState = digitalRead(schalter1);
if(buttonState==HIGH){
 digitalWrite(LEDpin, HIGH); 
 digitalWrite(relay2, HIGH);   // relay 2 ein
}
else{
digitalWrite(LEDpin, LOW);
//digitalWrite(relay2, LOW);   // relay 2 aus
}

  
}

ich vermute es hängt mit dem debouncen zusammen.

Vermute ich auch.
Wenn du die Tasten blockierend abfragst, dann darfst du dich nicht wundern, wenn dein Code während der Blockade blockiert. Und so keine Inputs mit bekommt.

Tipp:

entschuldigt meine schlecht Programmierung bin Neuling

Bitte erniedrige dich nicht selber.
Das wirkt nur ablenkend auf uns und hilft keinem.
Und noch schlimmer: Je öfter du das sagst/denkst, desto fester glaubst du daran.

Gibt es eine Möglichkeit das LCD-Keypad mit Tasten und Menü und den Lichtschrankenzähler zusammen zu verwenden? oder muss ich auf die Verwendung der über A0 angeschlossenen Taster verzichten ?

vielen Dank

Highpressuresteam:
Gibt es eine Möglichkeit das LCD-Keypad mit Tasten und Menü und den Lichtschrankenzähler zusammen zu verwenden?

In der Biliotheksdoku lese ich:

"lcdKeypad.buttonBlocking(block_delay,repeat_delay)

Read filtered button states. After detecting button press for the first time and returning appropriate code this function returns KEYPAD_BLOCKED until block_delay milliseconds has passed. If the button is held after this time its code is returned once and then function returns KEYPAD_BLOCKED again for repeat_delay milliseconds. Great for use in menus or similar situations where you need only one button press code."

Standardwerte sind buttonBlocking(500, 300); die Du testweise verringern könntest. Wenn es dann besser wird, bist Du auf der richtigen Spur.

Ich finde, da sollte man nicht sofort eine Grundsatzfrage draus machen.

Obwohl/Denn:

Vorschlag.... (ja, ich weiß, kaltes Wasser usw...)
Die A0 Abfrage kann man im Hintergrund automatisch abhandeln, so dass es nicht blockiert, so wie es analogRead() tut.
Die Pulse kann man zählen, ohne dass es den Programmfluss blockiert.
A. per Hardware Timer (Input Capturing)
B. per Interrupt

Aber vielleicht reichts ja schon aus, wenn du die nicht blockierende Abfragefunktion, aus deiner Keypad Lib nutzen würdest.

wie und wo ist denn was für eine Lichtschranke angeschlossen?

ElEspanol:
wie und wo ist denn was für eine Lichtschranke angeschlossen?

Ich habe ein 4Pin China Modul mit LM393 verbaut so eins:

Diese ist über D2 am Arduino und gibt bereits High und LOW aus. Aus diesem generiere ich mein zählen.

agmue:
In der Biliotheksdoku lese ich:

"lcdKeypad.buttonBlocking(block_delay,repeat_delay)

Read filtered button states. After detecting button press for the first time and returning appropriate code this function returns KEYPAD_BLOCKED until block_delay milliseconds has passed. If the button is held after this time its code is returned once and then function returns KEYPAD_BLOCKED again for repeat_delay milliseconds. Great for use in menus or similar situations where you need only one button press code."

Standardwerte sind buttonBlocking(500, 300); die Du testweise verringern könntest. Wenn es dann besser wird, bist Du auf der richtigen Spur.

Das finde ich eine gute Idee, blöde frage - aber wie bringe ich das in mein sketch ? Habs im void Setup und davor probiert, bekomme dann jedoch Fehlermeldungen.
Wo finde ich den die Doku zur Libary ?
wusste bisher nicht das es die Funktion buttonBlocking(500, 300); für diese Lib gibt.

Danke schon mal

wusste bisher nicht das es die Funktion buttonBlocking(500, 300); für diese Lib gibt.

Dann ist dir sicherlich noch viel mehr entgangen.
Viel!

Die Lib findest du auf deinem Rechner.
Der einzige der dich hindern kann, da rein zu sehen, bist du selber.

Hallo,

irgendwas stimmt hier nicht, deshalb habe ich eine Bemerkung abzugeben.
Blockierung und "zählt zu viel" passt laut meiner Meinung nicht zusammen. Er müsste wenn dann zu wenig zählen.

Die Lib habe ich mir angeschaut, da ist kein delay(x) drin, arbeitet mit millis. Eine echte Blockierung schließe ich damit aus.
Ich wüßte jetzt zwar nicht wie eine Lichtschranke prellen kann, vermute den Fehler aber nicht direkt im Code.
Ein Schaltplan der der Wahrheit entspricht wäre nicht verkehrt.

Testweise kann auch nur gezählt werden ohne den "Tastenkram" im Code.

Highpressuresteam:
Wo finde ich den die Doku zur Libary ?

Ich habe hier gelesen:

https://github.com/dzindra/LCDKeypad/blob/master/LCDKeypad/LCDKeypad.h

wobei sich die Dateien auch auf Deinem Rechner im Verzeichnis der Bibliothek befinden.

In LCDKeypad.h finde ich:

uint8_t buttonBlocking(uint16_t block_delay = 500, uint16_t repeat_delay = 300);

Wenn Du wie im Sketch

switch (lcd.buttonBlocking())

verwendest, werden die Standardwerte 500 und 300 verwendet. Mit

switch (lcd.buttonBlocking(30, 100))

kannst Du eigene Werte probieren.

Hallo Leute,

ich wollte eigentlich schreiben, dass das Problem ganz simpel war und der Code richtig, aber irgendwie läufts jetzt wieder nicht.

Ich hatte das ganze System runter gebrochen, und nur auf die Lichtschranke reduziert, dabei musste ich feststellen, dass meine Lichtschranke teilweise doppelt zählt - keine Erklärung warum ...
Gegooglt nach FC-03 Lichtschranke, ich habe so eine ( https://www.amazon.com/LM393-Measuring-Comparator-Sensor-Module/dp/B00GYV11U2) auf Project#11 Infrared speed sensor module (applied on DIY anemometer) - myscratchbooks

hat jemand vom gleichen doppel zähl Probelm geschreiben, -> einfachste Lösung von 5 V auf 3,3 V als Vcc geht.
Gemacht und alles hat funktioniert.

Jetzt habe ich die Geschwindigkeit reduziert (vormals 172 U/min) jetzt zählt der Sensor wieder zuviele Schritte.
switch (lcd.buttonBlocking(30, 100)) hatte ich reduziert.

bin wirklich am verzweifeln, das immer irgendwas nicht funktioniert... und das vorallem mit solchen primitiven Sensoren... geht ja wirklich fast nur um Ein Aus Wenn dann ....

hoffe ihr könnt mir helfen ...
schon mal danke

Hier mal eine Foto vom Aufbau:

und der Code zum testen der Lichtschranke.

ist es vielleicht besser eine Lochscheibe anstelle eines Arms zu verwenden ?

Vielen Dank :slight_smile:

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
const int zahlerPin = 2;
const int schalter1 = 3;
int zahlerState = 0;
static int zahler = 0;
int zahlerStateHIGH = 0;
int ziel = 10;
int relay1 = 11; 
int relay2 = 12;

void setup() {
  // put your setup code here, to run once:
lcd.begin(16, 2);
lcd.print("hello, world!");

pinMode(zahlerPin, INPUT);
pinMode(schalter1, INPUT);
pinMode(relay1, OUTPUT);
pinMode(relay2, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:

//--------------------------Zahler  ---------------------

zahlerState = digitalRead(zahlerPin);
 if (zahlerState == HIGH)
 {    
   zahlerStateHIGH = 1;
 }
 if (zahlerState == LOW && zahlerStateHIGH == 1)
 {
   zahler++;
   zahlerStateHIGH = 0;
 }


lcd.setCursor(0,0);
 lcd.print(zahler);
lcd.print(zahlerState);
lcd.print(zahlerStateHIGH);
//--------------------------Sachalter  ---------------------

if(digitalRead(schalter1)==LOW){
 
 digitalWrite(relay1, HIGH);   // relay 2 ein
 zahler=0;
}

//--------------------------Stopper  ---------------------
 if(zahler>=ziel)
 {
  digitalWrite(relay1, LOW);   // turn the relay1 on (HIGH is the voltage level)
  lcd.setCursor(12,1);
 lcd.print("AUS");

 
 }

}

Ich habe mal Füße unter einen UNO geschraubt, der dann nach ein paar Tagen den Geist aufgab. Nach Entfernen der Füße funktioniert er wieder.

"Dicke" Schraube presst Platine Richtung Aluminium, Display ruht auf Kunststoff. Das könnten Quellen für unerwartete Ereignisse sein.

Hallo,

ich habe den Code mal mit meinem Taster probiert. Eigentlich müßte der Zähler auf Grund des prellens mehrfach zählen pro Tastendruck. Macht er aber nicht. Ich habe keinen Schimmer warum sich das prellen im Zähler nicht wiederspiegelt. Habe mehrere Taster probiert.

Für Highpressure ist der Code aber genau richtig, Zählsperre solange Lichtschranke unterbrochen ist. Der Code paßt in meinen Augen für sein Anliegen. Dann dachte ich es gibt bei ihm vielleicht ungewollte Reflektionen vom Licht wegen dem glänzenden Teflon, daher mein Test mit dem Taster.

Gibt es von der Lichtschrankenplatine einen Schaltplan?

Was macht denn der Zähler wenn du mit einem anderen Gegenstand, EC-Karte o.ä. mehrfach durch die Lichtsschranke gehst? Springt der Zähler dann auch?

Pin    bool    bool    count
0	1	1	16
0	1	1	16
1	1	0	17
1	0	0	17
1	0	0	17
0	1	1	17
0	1	1	17
1	1	0	18
1	0	0	18




const int zahlerPin = 2;
byte zahlerState = LOW;
bool zahlerStateLOW = false;
int zahler = 0;

void setup() {
  Serial.begin(250000);
  pinMode(zahlerPin, INPUT_PULLUP);

}

void loop() {

  zahlerState = digitalRead(zahlerPin);             

  Serial.print(zahlerState); Serial.print('\t');

  if (zahlerState == LOW) {
    zahlerStateLOW = true;                        
  }

  Serial.print(zahlerStateLOW); Serial.print('\t');

  if (zahlerState == HIGH && zahlerStateLOW == true) {
    zahler++;
    zahlerStateLOW = false;
  }

  Serial.print(zahlerStateLOW); Serial.print('\t');
  Serial.println(zahler);

}

Hallo Leute, agmue & Doc_Arduino,

vielen Dank für eure Tests und eure Vorschläge!

Den Arm habe ich jetzt gegen eine Lochscheibe mit zwei Schlitzen getauscht. Die Lochschreibe bzw. der Arm waren auch PLA aus dem 3D Drucker, und nicht aus Teflon - schön wärs :slight_smile: .

Ich habe mit dem unten stehen Sketch mir mal die Analog Werte der Lichtschranke anzeigen lassen bzs. gepottet. Foto im Anhang. Überzeit habe ich den Analogwert und einen Schwellwert anzeigen lassen um Zählungen zu simulieren. Und siehe da, es werden manchmal wirklich Werte verschluckt.
Leider habe ich keinen Schaltplan dieser China Lichtschranke mit Ihrem LM393. Auch weiß ich nicht bei welchem Schwellwert sie schaltet. Daher ist es für mich wahrscheinlich sinnvoller direkt den Analogwert auszuwerten anstelle des I O Siganals der FC-03 Lichtschranke.

Ich habe ausprobiert, was der Sensor zurück gibt wenn ich wie Doc_Arduino vorgeschlagen ich einen anderen Gegenstand durch die Lichtschranke ziehe. Habe einen Roten Kunststoffbrieföffner verwendet... konstantes Signal ohne Aussetzer.
In Kombination mit dem Vorschlag das es von Reflektionen kommen könnte. Übringes war dies auch schon meine Überlegung nur dachte ich, es könnte von Teilen der Status LEDs kommen - habe diese daher abgeklebt.
Ich habe die Lochschreibe einfach nur so durch die Lichtschranke gefahren (bzw. die Lichtschranke bewegt)... komischerweise kam es an stellen, wo es kein loch gab zu Ausschlägen. Da meine Lochscheibe aus dem 3D Drucker stammt könnte es sein, das Licht durch das Plasik kommt .... wenn auch nur minimal ... wenn man sie gegen das Fenster hält sieht sieht man es ...

Ich schreibe euch mehr wenn dieser Fehler behoben ist, ich werde es mit einem schwarzen Material ohne Hohlräume versuchen.

Schon mal vielen Dank

/*
  AnalogReadSerial
  Reads an analog input on pin 0, prints the result to the serial monitor.
  Graphical representation is available using serial plotter (Tools > Serial Plotter menu)
  Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

  This example code is in the public domain.
*/
int signal1=0;
// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A1);

if (sensorValue<100){
signal1=1000;
}
else{
  signal1=0;}


  
  // print out the value you read:
  Serial.print(sensorValue);
Serial.print("  ");  
Serial.println(signal1);


  
  delay(1);        // delay in between reads for stability
}

Hallo,

wenn der analoge Wert gegen 0 geht, erzeugt er ein HIGH Signal. Soweit klar.
Kurz nach einer blauen Schaltspitze nach unten gibt es manchmal kurz danach zusätzliche die weit nach unten gehen, die werden wohl in manchen Fällen weiter runter gehen und das falsche Signal erzeugen.

Der LM393 ist eigentlich ein Komparator. Das heißt der schaltet unmittelbar sofort um ohne Verzögerung. Wenn der Schwellwert ungünstig vorgegeben ist, kann es zu solchen Effekten führen wie bei dir. Es kann aber auch sein das die daraus einen Schmitt-Trigger gebaut haben. Ohne Schaltplan schlecht zu sagen.

Du kannst folgende Maßnahmen wie schon erkannt umsetzen, auch die von agmue natürlich :slight_smile:
a) "Flag" schwärzen, mattschwarz, Testweise mit Folienstift bemalen etc.
b) Lichtschranke etwas wie in ein Gehäuse packen, also Umgebungslicht besser abschotten
c) saubere Masseverbindungen
d verdrillte Kabel
e) analog einlesen und ohne/mit Hysterese im Code zählen, probieren

Hallo Leute,

Ich habe entsprechende Änderungen vorgenommen, Lochscheibe in Schwarz und Vollmaterial. Desweiteren habe ich die Lichtschranke versucht durch einen Hall-Sensor auszutauschen um die ganze Steulicht und Schwelllwert Probelmatik zu umgehen. Der Hall Sensor ist wieder ein China Modul mit LM393 und einem Poti Ausgangssignal ist I O.
Im Anhang findet Ihr ensprechende Fotos. Die Zählerscheibe vom Hall Sensor hat einen Magneten die Lochscheibe 2 Spalte.
Jetzt habe ich gans ganze wieder mit der Ardino IDE Plotten lassen. Soweit ganz gut, Da wo die Lichtschranke Aussetzer hat liefert der Hall-Sensor ein konstantes Signal. Die Lichtschranken aussetzer kann ich immer noch nicht erklären. Habe Sie auch extra wieder mit 5 V betrieben und kontrolliert, ob nicht meine Spannung zu niedrig ist und teilweise während des Messens einbricht.

Ich wollte die Drehzahl erhöhen, von vorher 172 u /min mit Hilfe einer Übersetzung auf das Doppelte.
Nun stellt sich heraus, dass zwar der Hall-Sensor an der Platine entsprechend häufig auf blinkt - als Kennzeichnung für eine Umdrehung / Magnetfeld erkennung- aber der Arduino nicht schnell genug zählt.

Also eigentlich wieder das Probelm vom Anfang. Ich habe im Anhang zwei Diagramme mit 25 rpm und eins mit 80 rpm zudem eins mit 430 rpm.

Die Signale kommen nicht hinterher....ich habe das ganze mal bei verschieden Baud Raten ausprobiert, bei 19200 Baud geht es noch nicht , aber bei 115200 Baud scheinen die Signale regelmäßig von beiden Sensoren zu kommen.

Entsprechend habe ich mir in meinem Zählprogramm mit 115200 Baud die Zählerwerte anzeigen lassen ( Diagramm Zählerwert). Blau ist der Zählerwert der hochl äuft, Gelb und rot die Zielwerte die erreicht werden sollen. Jetzt merkt man, dass bei konstanter Drehzahl die Abstände zwischen den Zählerwert Erhöhungen variieren, Entsprechend stimmen die gezählten Umdrehungen auch nicht, der Zähler zählt viel zu langsam, Anstelle von ca. 430 rpm werden nur ca. 270 rpm gezählt.

Ich weiß wirklich nicht wo ich ansetzen soll um das Problem endlich zu beheben, ich will doch nur Umdrehungen zählen und Relays schalten... das kann doch eigentlich nicht so schwer sein... verzweifel

Hallo,

Foto vergessen?

Ein Hallsensor ist immer besser wie eine Lichtschranke, wußte nicht das du das umbaust, hätte ich dir sonst auch empfohlen. Nur warum du immer gleich irgendwelche Chinamodule kaufst weiß ich nicht. Hallsensor und LM393 paßt nun wirklich nicht zusammen. Ein Wald- und Wiesen Hallsensor wie der TLE4905L arbeitet schon digital. Ein kleine Lochrasterplatine und fertig.

Hab dir dazu mal einen Schaltplan gemacht. Mehr wie die Standardbeschaltung braucht man nicht. Den Pullup habe ich mit einer 4mA low current LED ersetzt. Die leuchtet wenn ein Magnetfeld erkannt wurde. Optische Detektanzeige. C1 kannste auch 100nF groß machen. Die 4,7nF sind eher als Mindestgröße zu sehen zum abblocken. Er reagiert auf die Magnetseite mit Südpol zum Sensor zeigend. Damit haste ein ordentliches digitales Signal.

Die serielle Ausgabe blockiert meines Wissens nach nicht das Programm.

Zeige mal deinen aktuellen Code.

Hier die Anhang Dateien.
Fotos vom Versuchsaufbau und die Diagramme:

hoffentlich kann mir jemand helfen, und vielen Dank im Voraus.