DC-Motor mit Timer steuern

Hallo Zusammen,

Anfang Dezember wurde mir bei der Programmierung eines Zähler per Lichtschranke für eine Modelleisenbahn Brücke sehr weitergeholfen.
https://forum.arduino.cc/index.php?topic=651891.0

Diesen Code versuche ich gerade zu erweitern um damit einen DC-Motor anzusteuern.

Die Funktion soll so aussehen:
Öffnen der Brücke:
-Wenn Zähler 0, Taster Endlage (tend) gedrückt und Taster öffnen (toe) soll der Motor für eine gewisse Zeit in Geschwindigkeit 2 in Richtung 1 drehen, danach stehen bleiben.

Schließen der Brücke
-Wenn Taster Endlage (tend) nicht gedrückt ist und Taster Schließen betätigt wird soll der Motor eine Zeit in Geschwindigkeit 2 in Richtung 2 drehen und danach in Geschwindigkeit 1, bis Taster Endlage (tend) gedrückt wird.

Die Timerfunktion habe ich von nem Kumpel und angepasst, da vermute ich einen Fehler.

Mir wird der Fehler "Fehler beim Komplimieren für das Board Arduino/Genuino Mega or Mega 2560" angezeigt.
Ich, mit meinem Anfänger wissen, kann im Code den Fehler nicht finden.

Ich hoffe ihr könnt da was entdecken oder mir sagen auf welchem anderen/besseren Weg ich das programmieren kann.

In meinem ersten Versuch habe ich mit for schleifen und delays eine Rampe programmiert, aber während der Arduino in den Schleifen war hat er (logischer Weise) nicht die Endlage abgefragt. Also Versuche ich jetzt mit dem Timer zu arbeiten.

Schönen Abend noch
Nordlicht

 //Lichtschranke
const int photo1 = A0; //Das Wort „photo1" steht jetzt für den Analogenport „A0"
const int photo2 = A1; //Das Wort „photo2" steht jetzt für den Analogenport „A1"
bool LS1Belegt = false; // = true, wenn die Einfahrt Lichtschranke belegt ist
bool LS2Belegt = false; // = true, wenn die Ausfahrt Lichtschranke belegt ist

int photoWert1 = 0; //Variable für den Photodiodenwert 1 mit 0 als Startwert
int photoWert2 = 0; //Variable für den Photodiodenwert 2 mit 0 als Startwert

bool lastLS1 = false; // Variable zum Merken des Zustandes der Lichtschranke 1
bool lastLS2 = false; // Variable zum Merken des Zustandes der Lichtschranke 2

int counter = 0; //Zug- und Wagenzähler

const int LED1 = 7; //Das Wort „LED1" steht jetzt für den Digitalpin 7
const int LED2 = 6; //Das Wort „LED2" steht jetzt für den Digitalpin 6
const int LED3 = 5; //Das Wort „LED3" steht jetzt für den Digitalpin 5
const int LED4 = 4; //Das Wort „LED3" steht jetzt für den Digitalpin 4
const int LED5 = 8; //Das Wort „LED3" steht jetzt für den Digitalpin 3

const int toe = 22; //Taster zum Öffnen auf DiPin 22
const int tsch = 23;// Taster zum Schließen auf DiPin 23
const int tend = 24; // Taster für Endlagenabfrage auf DiPin 10

bool tsoe = false; //Variable für Status tasterÖffnen=0
bool tssch = false; // Variable für Status tasterSchließen=0
bool tsend = false;  // Variable für Status tasterendlage=0

//Motorsteuerung
int pwm_a = 3;  //PWM control for motor outputs 1 and 2 
int dir_a = 2;  //direction control for motor outputs 1 and 2 
int offnen=0;
int schlieszen=0; 
int ges0 = 0;         //Geschwindigkeit 0 U/min
int ges1 = 150;       // Geschwindigkeit 100% 37 U/min
int ges2 = 60;       // Geschwindigkeit 50%  20 U/min

//Stromversorgung Schiene
int relais =12;

// Zeit für Timer
int timer=0;
int starttimer=0;
int zeit= 10000; // 10sekunden



void setup()//Hier beginnt das Setup.
{
 Serial.begin(9600); //Die Kommunikation mit dem seriellen Port wird gestartet.
 while(!Serial);
 pinMode (LED1, OUTPUT); //Der Pin mit der LED1 ist jetzt ein Ausgang
 pinMode (LED2, OUTPUT); //Der Pin mit der LED2 ist jetzt ein Ausgang
 pinMode (LED3, OUTPUT); //Der Pin mit der LED3 ist jetzt ein Ausgang
 pinMode (LED4, OUTPUT); //Der Pin mit der LED4 ist jetzt ein Ausgang
 pinMode (LED5, OUTPUT); //Der Pin mit der LED5 ist jetzt ein Ausgang

 pinMode( toe, INPUT );
 pinMode( tsch, INPUT );
 

 //Die analogen Pin muss nicht definiert werden.

 //Motorsteuerung
 pinMode(toe, INPUT);
 pinMode(tsch, INPUT);

 //Motorsetups
 pinMode(pwm_a, OUTPUT);  //Set control pins to be outputs
 pinMode(dir_a, OUTPUT); 
 analogWrite(pwm_a, ges0);  //Startgeschwindigkeit

 // Relais
 pinMode(relais, OUTPUT);
 pinMode(tsend, OUTPUT );

 //TIMER KONFIGURATION
 TCCR0A=(1<<WGM01);    //Set the CTC mode   
 OCR0A=0xF9; //Value for ORC0A for 1ms

 TIMSK0|=(1<<OCIE0A);   //Set the interrupt request
 sei(); //Enable interrupt

 TCCR0B|=(1<<CS01);    //Set the prescale 1/64 clock
 TCCR0B|=(1<<CS00);
}

void loop()
//Lichtschranke mit Abfrage ob sich Zug auf der Brücke befindet
{ //Lichtschranke Auslesen
 LS1Belegt = ( analogRead(photo1) < 40 );//Die Spannung an dem Fotowiderstand auslesen und Belegtzustand in der Variable „LS1Belegt" abspeichern.
 LS2Belegt = ( analogRead(photo2) < 40 );//Die Spannung an dem Fotowiderstand auslesen und Belegtzustandunter der Variable „LS2Belegt" abspeichern.

//Zum kontrollieren der Sensorwerte bei Bedarf einblenden
 /*photoWert1=analogRead(photo1);     
 photoWert2=analogRead(photo2);
 Serial.print("Photo1: "); Serial.println (photoWert1);
 Serial.print("Photo2: "); Serial.println (photoWert2);*/

 // LED1 und LED2 entsprechend LS-Zustand schalten
 digitalWrite(LED1, LS1Belegt);
 digitalWrite(LED2, LS2Belegt);

 if (LS1Belegt && !lastLS1) // Lichtschranke 1 wurde unterbrochen ( Flanke )
 {
   counter ++;     // einen addieren
   Serial.print("Diff. " ); Serial.println(counter); Serial.print("LS1Belegt=" ); Serial.println(LS1Belegt); Serial.print("LS2Belegt=" ); Serial.println(LS2Belegt);
 }
 lastLS1 = LS1Belegt;   // aktuellen Zustand der LS merken

 if (LS2Belegt && !lastLS2) // Lichtschranke 2 wurde unterbrochen ( Flanke )
 {
   counter --;     // einen abziehen
   Serial.print("Diff. " ); Serial.println(counter); Serial.print("LS1Belegt=" ); Serial.println(LS1Belegt); Serial.print("LS2Belegt=" ); Serial.println(LS2Belegt);
 }
 lastLS2 = LS2Belegt;   // aktuellen Zustand der LS merken


 digitalWrite(LED3, (counter != 0) ); //LED3 leuchtet,wenn Counter nicht 0 (Fehlermeldung)

//Motorsteuerung auslesen
 tsoe = digitalRead(toe);
 tssch = digitalRead(tsch);
 tsend = digitalRead(tend);

 //Bedienung der Brücke nur wenn counter auf 0 steht

 if ( counter == 0 && tsend==HIGH && tsoe == HIGH) // Brücke öffnen
      {
       digitalWrite (offnen, HIGH);
      }

 if (tsend=LOW && tssch=HIGH) //Brücke schließen
     {
       digitalWrite (schlieszen,HIGH);
     }

 if(offnen == HIGH){
 digitalWrite(dir_a, LOW);
  if(tsend==HIGH){
   if(timer>=zeit){
       analogWrite(pwm_a,ges2);
       starttimer = LOW;
     }else{
       analogWrite(pwm_a,ges0);
       starttimer= HIGH;
     }
 }else{
   analogWrite(pwm_a,ges0);
   offnen=LOW;
 }
}

if(schlieszen == HIGH){
digitalWrite(dir_a, HIGH);
   if(tsend==LOW){
   if(timer>=zeit){
      analogWrite(pwm_a,ges2);
      starttimer = LOW;
     }else{
       analogWrite(pwm_a,ges1);
       starttimer= HIGH;
     }
 }else{
   analogWrite(pwm_a,ges0);
   schlieszen=LOW;
  }
} 
 
//Stromversorgung Schiene
 tsend=digitalRead(tend);
 if (tsend ==HIGH)
 {
   digitalWrite(relais, HIGH); //An dieser Stelle würde das Relais einsschalte
 }
 else
 {
 digitalWrite(relais,LOW);
 }

 delay (20); // zum entprellen;
}
//Timer
ISR(TIMER0_COMPA_vect){    //This is the interrupt request
 if((tsoe == HIGH)||(tssch == HIGH)){
   if(starttimer== HIGH){
      timer++;
   }
 }else{
   timer=0;
 }
}

Warum hälst Du die Fehlermeldung geheim?

Gruß Tommy

Tommy56:
Warum hälst Du die Fehlermeldung geheim?

Gruß Tommy

Sorry... zur Übersichtlichkeit habe ich den Speicherpfad immer durch "Speicherpfad" ersetzt

Arduino: 1.8.10 (Windows 10), Board: "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

In file included from sketch\04_25012020_Steuerung_Kevin_2.ino.cpp:1:0:

C:\Speicherpfad\04_25012020_Steuerung_Kevin_2.ino: In function 'void loop()':

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:40:14: error: lvalue required as left operand of assignment

#define HIGH 0x1

             ^

C:\Speicherpfad\04_25012020_Steuerung_Kevin_2.ino:133:26: note: in expansion of macro 'HIGH'

exit status 1
Fehler beim Kompilieren für das Board Arduino/Genuino Mega or Mega 2560.

Das steht ja überhaupt nicht in dem von Dir veröffentlichten Sketch drin.

Gruß Tommy

Und Da, wo's steht:
Schuss ins Blaue ...
könnte daran liegen, daß HIGH bereits in Benutzung ist?

PS: IN LOOP??
Hätte Es noch nicht probiert, ob #define auch 'egal wo' stehen dürfen, möglich ist hier viel ...

Tommy56:
Das steht ja überhaupt nicht in dem von Dir veröffentlichten Sketch drin.

Gruß Tommy

Das ist die Fehlermeldung die mir unten angezeigt wird wenn die den rein kopierten Sketch hochladen will

postmaster-ino:
Und Da, wo's steht:
Schuss ins Blaue ...
könnte daran liegen, daß HIGH bereits in Benutzung ist?

PS: IN LOOP??
Hätte Es noch nicht probiert, ob #define auch 'egal wo' stehen dürfen, möglich ist hier viel ...

Hast du eine Vermutung welches High schon in Benutzung ist? Bin den Sketch nochmal durchgegangen und konnte nichts finden.

Welches Element meinst du gehört nicht in den Loop?

Gruß
Nordlicht

Nordlicht:
Das ist die Fehlermeldung die mir unten angezeigt wird wenn die den rein kopierten Sketch hochladen will

Dann schau Dir den hier veröffentlichten Sketch nochmal genau an und versuche die Zeile
zu finden.
Ich finde sie nicht, also kann dieser Sketch nicht diese Fehlermeldung erzeugt haben.
Doch er kann diese Fehlermeldung erzeugen. Sorry.
Meinst Du mit dieser Zeile eher etwas anderes? = ist Zuweisung, == ist Vergleich

// Dein Code:
 if (tsend=LOW && tssch=HIGH) //Brücke schließen
// Du meinst wohl eher
 if (tsend==LOW && tssch==HIGH) //Brücke schließen

Gruß Tommy

Der Compiler zeigt doch die falsche Stelle genau an. Du musst nur mal die Fehlermeldung weiter lesen. Irgendwie wurde ich nicht richtig kopiert. Bei mir steht da das:

[...] note: in expansion of macro 'HIGH'

  if (tsend=LOW && tssch=HIGH) //Brücke schließen
                         ^~~~

exit status 1
Fehler beim Kompilieren für das Board Arduino/Genuino Mega or Mega 2560.
if (tsend=LOW && tssch=HIGH)

= und == verwechselt

Der Fehler kann eventuell daher kommen dass && einen höheren Rang hat als = und er daher praktisch das machen möchte:

if ((tsend=LOW && tssch) = HIGH)

Damit hat man links keinen lvalue mehr, sondern einen rvalue und das geht natürlich schief. 100%ig sicher bin ich mir hier aber nicht

Aber die ist noch mehr falsch. Wieder mal die üblichen ISR Fehler:
1.) Variablen die innerhalb und außerhalb von ISRs verwendet werden müssen als volatile deklariert werden
2.) Multi-Byte Variablen die in ISRs geändert werden müssen außerhalb bei abgeschalteten Interrupts ausgelesen werden (siehe "timer")

Das sind Fehler die der Compiler nicht anmeckern kann. Aber das heißt nicht dass es immer richtig funktioniert

Es war der Fehler mit dem = statt == , danke für eure Hilfe.

Mir wird in der Fehlermeldung das nicht so Detailliert dargestellt sondern so:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:40:14: error: lvalue required as left operand of assignment

 #define HIGH 0x1

              ^

Was meins du mit ISR?

Gruß Nordlicht

ISR = Interrupt Service Routine

Versteht du überhaupt was du da machst:

ISR(TIMER0_COMPA_vect)

EDIT:
Oh, was mir gerade aufgefallen ist. Von Timer0 solltest du die Finger lassen. Darauf läuft in der Arduino Software schon ein Timer der von millis() und delay() verwendet wird. Das musst du auf Timer1 oder Timer2 ändern (auf dem Mega gibt es auch noch Timer 3 bis 5). Die funktionieren aber leicht anders als Timer0. Siehe Datenblatt

Außerdem noch beachten welche PWM Ausgänge von welchem Timer kontrolliert werden. Die 3 Pins funktionieren dann nicht mehr für PWM

Oder gleich millis() verwenden und dann konsequent nicht-blockierend programmieren

Das ist wieder einer der Fälle, wo vollkommen unnötig eine Interrupt eingesetzt wird. Die ISR mach im Prinzip auch nichts anderes als millis() - nur dass die Abfrage ob gezählt werden soll mit in der ISR ist.
Das geht auch ohne die ISR und 'klassisch' mit millis ( oder mit meinem MoToTimer der MobaTools :wink: ).
Dann hat man auch die angesprochenen Probleme mit volatile und atomarem Zugriff nicht ( volatile müssen übrigens nur Variablen sein, die in der ISR verändert und außerhalb gelesen werden, hier also 'timer' ).

P.S. gibt es eigentlich einen Endschalter für den Motor? Sonst habe ich Angst um die Brücke. Oder ist der Motor so schwach, dass er der Brücke nichts anhaben kann?

Hallo,

ich würde eine Schrittkette / Statemashine /endlicher Automat / verwenden 5 Zustände warten / offnen schnelll /warten /schliessen schnell / schliessen langsam . Anderung des Zustände abhängig von den Eingängen und mit millis().

Dazu gibts Beispiele im Netz

Heinz

Hallo,

@Serenifly: ich muss ganz klar sagen, nein den Timer verstehe ich nicht. Ich habe ihn nur genommen, da ich mit den for schleifen zwar die Funktion abfahren konnte, aber der Endlagenschalter erst nach dem Durchfahren der Beschleunigung abgefragt wurde. Ein Kumpel hat mir dann ein Sketch mit der Timer Funktion geschickt und meine ich soll mir das mal raus kopieren und dann klappt das … oder halt auch nicht ^^

@Microbahner und Rentner: Danke für den Vorschlag mit den Millis (). Werde ich mir mal angucken. Und den MoToTimer auch.

Beim raus drehen hat die Brücke (leider keinen Endlagenschalter, deswegen Zeitgesteuert. Bei der Weiterentwicklung wird da auf jedenfall auch ein Endlagenschalter rein kommen. Beim zufahren hat sie einen Endlagenschalter.

Gruß Nordlicht