Was ist falsch?

Hallo,
warum werden die Funktionen wake() und sleep() nicht aufgerufen, also der serielle Monitor zeigt nicht an "going to sleep"und " waking up". Dies soll durch das Schließen und Öffnen des Schalters geschehen

#include <avr/sleep.h>
int motorPin=9;
int Pin=8;

byte pwm=150;

void setup()
{
 Serial.begin(9600);
  digitalWrite(motorPin, OUTPUT);
  digitalWrite(Pin, OUTPUT);
  pinMode(3,INPUT_PULLUP);
  analogWrite(9, 250);
}
void wake ()       // Erwachen aus dem Schlaf nachdem Betätigen des Schalters
{
  sleep_disable();
  detachInterrupt(1);
  Serial.println("waking up");
  ADCSRA = _BV(ADEN);

}  

void loop()
{
  if(digitalRead(3)==HIGH)
  {
   analogWrite (9,250);
   }
  
 if (digitalRead(3)==LOW)
  {
   analogWrite(9,0);
  }
}

void sleep()              // Schlafen 
{
    Serial.println("going to sleep");
    delay(50);
    ADCSRA = 0;  
    set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
    sleep_enable();
    noInterrupts (); 
    attachInterrupt (1, wake, HIGH);
    MCUCR = bit (BODS) | bit (BODSE);
    MCUCR = bit (BODS); 
    interrupts ();
    sleep_cpu ();
}

Die beiden routinen werden weder im setup noch in der loop irgendwo aufgerufen.

Edit: und nicht digitalWrite und pinMode verwechseln :slight_smile:

Ja, pinMode habe ich korrigiert.
Wieso bleibt der Motor erst stehen, wenn ich in die sleep() anlogWrite (9, 0) einfüge. Muss nicht durch den set_sleep_mode (SLEEP_MODE_PWR_DOWN); alles deaktiviert werden?

#include <avr/sleep.h>
int motorPin=9;
int Pin=8;

byte pwm=150;

void setup()
{
 Serial.begin(9600);
  pinMode(motorPin, OUTPUT);
  pinMode(Pin, OUTPUT);
  pinMode(3,INPUT_PULLUP);

}
void wake ()       // Erwachen aus dem Schlaf nachdem Betätigen des Schalters
{
  sleep_disable();
  detachInterrupt(1);
  Serial.println("waking up");
  ADCSRA = _BV(ADEN);

}  

void loop()
{
  if(digitalRead(3)==HIGH)
  {
analogWrite (9,150);
  
  }
  
 if (digitalRead(3)==LOW)
  {
    sleep();
  }
}

void sleep()              // Schlafen 
{
    Serial.println("going to sleep");
    delay(50);
    ADCSRA = 0;  
    set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
    sleep_enable();
    noInterrupts (); 
    analogWrite(9,0);
    attachInterrupt (1, wake, HIGH);
    MCUCR = bit (BODS) | bit (BODSE);
    MCUCR = bit (BODS); 
    interrupts ();
    sleep_cpu ();
}

PWM läuft in Hardware über Timer. Es ist möglich, dass diese auch im Schlafmodus weiterlaufen (wodurch man vielleicht auch alle ms durch den millis() Timer kurz aufgeweckt wird). Die CPU ist von der Peripherie getrennt!

Schau dir mal das an:
http://www.nongnu.org/avr-libc/user-manual/group__avr__power.html

Da gibt es Makros um alle Subsysteme getrennt abzuschalten. Wenn du da denn entsprechende Timer des PWM Pins abschaltest sollte er auch stehen bleiben. Aber dann muss man ihn auch wieder aktiveren. PWM Pin läuft auf dem UNO auf Timer1 und auf dem Mega auf Timer2.

Es gibt auch power_all_disable(), was alles abschaltet. Das Interrupt System läuft dann hoffentlich noch. So genau kenne ich mich da nicht aus.

Der Timer scheint nicht zu laufen, wenn ich
Timer1.initialize(3000000); // Timer, Aufruf alle 10 Sekunden
Timer1.attachInterrupt(Messung);
einfüge, startet der Motor gar nicht.

[code]Kämpfe immer noch mit dem Schalter.  Würde  gerne einen Tipp abholen: 

Wenn ich das schreibe 

[if(digitalRead(3)==HIGH)
  
   {  
     analogWrite(3, 150);
     
   }]

startet der Motor und läuft.
Wenn ich aber das hinschreibe, dann gar nicht. Wie kann ich das den besser machen?

[if ( digitalRead(3)==HIGH )
{ if ( millis ()-prev_Miliis>1000) // Überprüfung, ob sich ein x Wert nach einer Sekunde ändert.
{
if (x==x_alt) // Wenn nicht, dann wurde vom Interrupt keine Drehung registriert, Zur Beginn ist x_alt=0
{
analogWrite ( 9,0); //Anweisung zum Stoppen des Motors, PWM Signal wird unterbunden
digitalWrite(A0, HIGH); // LED leuchtet auf, zu Fehleranzeige
//lcd.print ( " Error")
z=67;
// Damit das Programm keine weiteren Schritte unternimmt

}

x_alt=x; // der neue x Wert wird in den alten Wert überschrieben.
prev_Miliis=millis(); //Zeitupdate
if (z<65){
analogWrite(3,pwm++); Serial.println ("pwm:"); Serial.println(pwm); // Regelung
} if (z>70) {
analogWrite(3,pwm--); Serial.println ("pwm:"); Serial.println(pwm);
}

}
]
[/code]

Was soll denn falsch sein ?

if ( x == x_alt ) 
{  
   // Motor aus, usw. 
   // bleibt alles wie es ist, auch x, und ntürlich auch Motor aus.
}

Ok, das ist nicht im sketch, aber mittels einer Lichtschranke sollen x und x_alt verglichen werden. Habe eine ISR, die bei jeder Umdrehung des Motors ein x zählt.

Ok, habe so umgeschrieben. Jetzt ist aber so, dass x_alt aber immer 0 bleibt, x wird dann auch 0 und der  Motor tut auch gar nichts. Wie formuliere ich dass nach einer Sekunde x und x_alt verglichen werden sollen, aber dass x_alt aktualisiert wird immer?

[void loop (){

  
    
  if(digitalRead(3) == LOW)                // Wenn der Schalter auf LOW ist, dann Schlafmodusaktivieren
  {
    //delay(20);
    sleep();
  }
  
  
  if (digitalRead(3)==HIGH)
      {
    
  
   analogWrite(5,250);
  
}

if (millis ()-prev_Miliis>1000)
{  
   x=x_alt;

}
if (x=x_alt);
   { 
      analogWrite(5, 0);
   }

}

void count()           
{
  x++;                    // Zählung der Impulse bei steigender Flanke
  if (x==1) {                  // 
    previousMillis=millis();  // Zeitupdate
    x_alt=0;
  }
  if (millis()-previousMillis>1000){  //  Jedes mal nach Ablauf von einer Sekunde werden die Pulse 1 und 2 verglichen
    switch (x_Zustand){               // 
    case 1:                        // 
      x1=x;                       // Puls 1 wird aufgenommen
      x_Zustand=2;        // Zustandswechsel
      break;
    case 2:                
      x2=x;            // Puls 2 wird aufgenommen
      z=x2-x1;       // Die Differenz zwischen zweier Impulse wird ermittelt, damit gegebenenfalls eine Regelung vorgenommen wird
      x_Zustand=3;  // Zustandswechsel
      break;
    case 3:
      x1=x;         // Puls 1 wird nochmal aufgenommen
      z=x1-x2;     // Die Differenz zwischen zweier Impulse wird ermittelt, damit gegebenenfalls eine Regelung vorgenommen wird  
      x_Zustand=2; //  Da als nächstes wieser x2-x1 ermittelt wird, werden die möglichen Fälle damit  abgearbeitet
      break;
    }
    previousMillis=millis(); // Nach Bearbeitung der Fallunterscheidung wird die aktuelle Zeit überschrieben
  }
}
]

Habe jetzt so umgeschrieben. Problem: x_alt wird aktualisiert und bei x=x_alt bleibet der Motor nicht stehen. Vermute dies liegt
am

if (digitalRead(3)==HIGH)
{

analogWrite(5,250);
}

Wenn ich aber die Anweisung

analogWrite(5,250);

weglasse, dann startet der Motor gar nicht.

hängt denn dein MotorTreiber an Pin 5 oder 9 ?

(oder an beiden ?)

Meine Kristallkugel ist zwar gut poliert, aber deine Beschreibung

Wenn ich

analogWrite(5,250);

weglasse, läuft der Motor nicht

klingt nicht nach einem Fehler, sondern nach einem Hinweis, dass da ein Zusammenhang besteht :wink:

Ok, das ist nicht im sketch, aber mittels einer Lichtschranke sollen x und x_alt verglichen werden. Habe eine ISR, die bei jeder Umdrehung des Motors ein x zählt.

Versteh ich nicht.
Ich kann mir vorstellen, -sinnloserweise- einen Arduino schlafen zu lassen, wenn nichts los ist.
Würde ich aber -bei deinen Problemen- erstmal weglassen.
Ich kann mir vorstellen, einen Motor laufen zu lassen solange ein Taster gedrückt ist, auch mit PWM.
Ich kann mir vorstellen, mit einer Lichtschanke Motorumdrehungen zu zählen; wenn's denn als Übung so sein soll, auch in einer ISR.

Jetzt ist aber so, dass x_alt aber immer 0 bleibt, x wird dann auch 0

Das ist schön zu sehen in deinem Beispiel: x_alt wird nie auf was anderes als 0 gesetzt
  x=x_alt; setzt x auf 0

Wie formuliere ich dass nach einer Sekunde x und x_alt verglichen werden sollen, aber dass x_alt aktualisiert wird immer?

Was meinst du mit* immer* ?
Vergleichen geht mit

    if (x == x_alt)  // beachte die zwei Gleichheitszeichen !

Dein

if (x=x_alt)

ist leider formal richtig:
setzt x auf den Wert von x_alt und prüft den Wert. Wenn x und x_alt 0 ist, ist das false, sonst true.

Was ist falsch?

Die wesentlichen Sachen ( Variablendefinition, wo ist setup() und was macht es, was ist überhaupt wo und wie angeschlossen )
fehlen.

Ich rate mal, dass count() deine ISR ist.
Wann x_Zustand jemals den Wert 1 kriegt, seh ich nicht, und was das Ganze soll, ist mir auch nicht so klar.
Jede Sekunde willst du die Anzahl Impulse der letzten Sekunde in z aktualisieren, richtig ?
x soll die Anzahl der Impulse seit Motor - Start sein ?
Und x_alt kann man dafür nehmen, um z auszurechnen ?

volatile unsigend long x; // Impulse seit Start 
volatile unsigend long z; // Impulse je Sekunde
void count()           
{
  // Hilfsvariable für Sekundenwechsel
  // nur hier gebraucht, muss aber nach Ende der ISR erhalten bleiben
  static unsigned long previousMillis;
  static unsigned long x_alt;   

  x++;                    // Zählung der Impulse seit Start

  if (x==1) {                 // Start
    previousMillis=millis();  // 
    x_alt=0;
  }

  if (millis()-previousMillis>1000){  //  Jedes mal nach Ablauf von einer Sekunde 
    z = x - x_alt;           // Pulse je Sekunde
    x_alt = x;                       
    previousMillis=millis();  
  }
}

Ausserhalb der ISR musst du nur x auf 0 setzen, um einen Start zu signalisieren...
Wenn du es richtig machen willst, musst du zum Auswerten von x und z kurzzeitig noInterrupts(); setzen !

Habe es so umgeschrieben. Damit auch ein Schalter dran ist. Passiert aber nichts. 

[#include <TimerOne.h>
 #define PWM_pin   5
 #define Motor_pin 7
 
 
volatile unsigned long x = 0; // Impulse seit Start 
volatile unsigned long z=0; // Impulse je Sekunde
volatile unsigned long x_alt; // Impulse seit Sta
unsigned long previousMillis = 0; 

 
        
        
	byte pwm = 150;
     
        int Lichtschranke=2;
        int schalter=3;
	 
	void setup()
	{
	  Serial.begin(9600);
	 
	  pinMode(PWM_pin, OUTPUT);
	  pinMode(Motor_pin, OUTPUT);
          pinMode(Lichtschranke, INPUT); // Lichtschranken-Pin (Pin 2) wird als Input funktionalisiert
          pinMode(schalter,INPUT);
          
	 
	     
       
	  attachInterrupt(0, count, RISING);
         
	}
void loop (){
  
  if (digitalRead(3)==HIGH)
   {  x = 0;
      delay(1000);
       noInterrupts();
           if (z==!0)  {
                analogWrite(5,200);
                
  } else {   
    analogWrite(5,0);  
                
  }
  interrupts();
  
   }
}

void count()
	{
	 
  x++;                    // Zählung der Impulse seit Start

  if (x==1) {                 // Start
    previousMillis=millis();  // 
    x_alt=0;
  }

  if (millis()-previousMillis>1000){  //  Jedes mal nach Ablauf von einer Sekunde 
    z = x - x_alt;           // Pulse je Sekunde
    x_alt = x;                       
    previousMillis=millis();  
  }
}
         ]

Ich würde vor allem die ISR-routine ausmisten.
die ganzen millis-Abfragen haben da nichts zu suchen.
du machst da was doppelt: in der loop hat du nach dem Tastendruck ein delay(1000) und in der ISR auch nochmal eine Abfrage auf 1sek.
ich würde die ISR zusammenstreichen auf:

void count(){
  x++;}

und die ganzen millis -Vergleiche in der loop machen, dafür das delay raus.

Wenn ich den Code richtig interpretiere, dann soll ungefähr das passieren:
Bei Tastendruck 1 sek Drehzahlpulse messen.
wenn Drehzahl erkannt, Motor aus, sonst Motor an.

Mit dieser Aufgabe könnte der Code so aussehen:

#include <TimerOne.h>
const int PWM_pin =  5;
const int Motor_pin = 7;
const int Lichtschranke = 2;
const int schalter = 3;

volatile unsigned long x = 0; // Impulse seit Start 
unsigned long previousMillis = 0; 

void setup(){
  Serial.begin(9600);

  pinMode(PWM_pin, OUTPUT);
  pinMode(Motor_pin, OUTPUT);
  pinMode(Lichtschranke, INPUT); // Lichtschranken-Pin (Pin 2) wird als Input funktionalisiert
  pinMode(schalter,INPUT);

  attachInterrupt(0, count, RISING);
}

void loop (){
  if (digitalRead(3)==HIGH)  {    // Bei Tastendruck Messung starten
    x = 0;
    previousMillis=millis();
  }
  
  if (millis()-previousMillis>1000){  //  Nach Ablauf von einer Sekunde 
    noInterrupts();  
    if (x > 0)  analogWrite(PWM_pin,200);
    else        analogWrite(PWM_pin,0);          
    interrupts();
  }
}

void count(){
  x++;                    // Zählung der Impulse seit Start
}

Was mir allerdings nicht klar ist: wofür ist der Pin "Motor_pin"?

Ja, Motor_Pin braucht man nicht.

Also die Idee war, dass der Motor erstmal starten soll bei Tastendruck. Nachdem start soll jede Sekunde kontrolliert werden, ob x= x_old. Wenn ja heißt das, dass die Lichtschranke keine Umdrehungen registriert hat, deswegen Motorstop.
Also habe den Sketch, der im vorgerigen Beitrag steht, probiert und der Motor startet überhaupt nicht, schalter ein oder aus passiert nichts.

Nur wenn ich die Loop() so schreibe funktioniert es:

void loop(){
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {

analogWrite(pwmpin, 150);

}

if (buttonState == LOW) {

analogWrite(pwmpin,0);
}

}

Aber da ist keine Lichtschranke drin.

funktioniert denn die Lichtschranke?
Kriegst du ein Signal und einen Interrupt?

probier doch mal:

void count(){
  x++;
  serial.println(x);
}

und probiere was passiert, wenn du von Hand drehst.

User_ino:
Also die Idee war, dass der Motor erstmal starten soll bei Tastendruck. Nachdem start soll jede Sekunde kontrolliert werden, ob x= x_old. Wenn ja heißt das, dass die Lichtschranke keine Umdrehungen registriert hat, deswegen Motorstop.

Dann schreib dein Programm doch auch so einfach:

...dass der Motor erstmal starten soll bei Tastendruck.

  if (digitalRead(schalter)==HIGH)  {    // Bei Tastendruck Motor starten
    analogWrite(PWM_pin,200);
    previousMillis = millis();          // Startzeit setzen
    x = 0;                              // Pulszähler auf Null
  }

Aber ich habe das Gefühl, dass du noch keine Interrupts kriegst...

soll jede Sekunde kontrolliert werden, ob ... keine Umdrehungen registriert hat, deswegen Motorstop

  if (millis()-previousMillis>1000){  //  Nach Ablauf von einer Sekunde auf Drehzahl prüfen 
    if ( x == 0) analogWrite(PWM_pin,0);  // wenn keine Drehzahl, Motor Stop (Sinnvoll wäre vielleicht nicht auf Null zu testen, 
                                          //sondern auf einen Wert, der auch einen stark abgebremsten Motor erkennt
    previousMillis = millis();              // Startzeit neu setzen
    x = 0;                                    // Pulszähler auf Null
  }

User_ino_motor.ino (1.28 KB)

Die Lichtschranke funktioniert ganz sicher. 
   Wenn ich den Motor drehe und die Lichtschranke dran halte   kommt das:  1111121111
Wenn ich in void setup()  
die Anweisung  
  
analogWrite(5,200);


  
einfüge, dann startet der Motor auch, reagiert allerdings nicht auf den Knopf und bleibt nicht stehen. 
 Die Lichtschranke   zählt  allerdings wieder   1111121111

Wenn ich diesen Sketch probiere, dann zählt sie auch richtig und die Motorsteuerung funktioniert korrekt. 


[#include <TimerOne.h>
 #define PWM_pin   5

 volatile unsigned long x = 0;
 
        
        
	byte pwm = 150;
      
        int Lichtschranke=2;
	 
	void setup()
	{
	  Serial.begin(9600);
	 
	  pinMode(PWM_pin, OUTPUT);
	  
          pinMode(Lichtschranke, INPUT); // Lichtschranken-Pin (Pin 2) wird als Input funktionalisiert
          analogWrite(5,pwm);
          
	 
	     
       
	  attachInterrupt(0, count, RISING);
      
	}
void loop (){
  x = 0;
  delay(1000);
  noInterrupts();
  if (x > 0)  {
    analogWrite(5,150);
                  Serial.print("Drehzahl erkannt.  x = ");
                  Serial.println(x);
  } else {   
    analogWrite(5,0);  
                  Serial.println("  keine Drehzahl,  x =");
                  Serial.println(x);
  }
  interrupts();
}
void count()
	{
	  x++;
         
        
	}]

Wenn ich diesen Sketch probiere, dann zählt sie auch richtig und die Motorsteuerung funktioniert korrekt.

Das ist schön.
Was ist nicht verstehe, ist dein erster IF-Zweig:

  if (x > 0)  {
    analogWrite(5,150);
    ...

Wenn der Motor läuft, dann setzt du die PWM auf 150.
Das würde bedeuten, du kannst den Motor "anschieben". Ist das so gewollt?

reagiert allerdings nicht auf den Knopf

Dann prüfe doch mal deinen Knopf eingang!

void setup(){
  Serial.begin(9600);
  pinMode(3,INPUT);
}

void loop (){
  Serial.println(digitalRead(schalter));
  delay(100);
}

hast du an Pin3 einen Taster nach 5V und einen Pulldown?

Danke, für den angehängten Sketch.
Beim Start kommt die Meldung "Starte Motor" und zwar nur diese eine. x wird nicht gezählt, die Drehzahl wird nicht registriert.
Angeschlossen ist die Lichtschranke richtig, funktionsfähig ist die auch. Habe noch

if(digitalRead(schalter)==LOW)
{
analogWrite(PWM_pin, 0);
}

eingebaut und mir ist aufgefallen, dass der Motor nicht stehen bleibt, sondern ganz langsam rotiert, wenn ich den Schalter öffne.

Nein, der Motor startet von alleine, weil ich bei void setup() analogwrite (5, 150) geschrieben habe.

Der Knopf funktioniert. Beim öffnen kommt 00000, beim Schließen 111111. Er ist angeschlossen an GND und Pin 3. Mit INPUT_PULLUP kommt dann immer 111111