Interrupts kommen teilweise nicht an.

Hallo Zusammen Selber weiter suchen bringt wohl nichts! (UNO) Ein optischer Drehgeber soll einen Sensor so steuern, dass er nur Messungen sendet wenn der Drehgeber Schritte macht. Die Schritte werden an einer LED angezeigt - der Serial Monitor zeigt sich unbeeindruckt von irgendwelchen Interrupts und haspelt unentwegt (Einstellung CHANGE). Eigentlich genügte ein RISING Interrupt, der kommt aber nicht auf der LED an. Danke für eure Hilfe.

Mein Sketch sieht so aus:

#define FIRST_PIN 5     // schwarz, Sensor auf pinNr=5, gelb auf GND
const byte LED = 13;    
const byte BUTTON = 2;  // weiss/orange, Drehgeber auf pinNr=2
int firstValue;
int zaehler;

// Interrupt Service Routine (ISR)
void pinChange ()
{
  if (digitalRead (BUTTON) == HIGH) 
    digitalWrite (LED, HIGH);       
  else                              
    digitalWrite (LED, LOW);        
}  

void setup ()
{ Serial.begin (9600);
  pinMode (LED, OUTPUT);  // so we can update the LED
  digitalWrite (BUTTON, HIGH);  // internal pull-up resistor
  attachInterrupt (0, pinChange, CHANGE);  // attach interrupt handler
}  

void loop ()
{ 
  firstValue = analogRead(FIRST_PIN);  
  zaehler=zaehler+1;
  Serial.print("Zaehler= ");
  Serial.print(zaehler);
  Serial.print(", ");
  Serial.print(firstValue); 
  Serial.println(',');    
}

Naja, der Sketch passt auch nicht zu dem was du dir wünscht.

Die serielle Ausgabe läuft durchgehend und erhöht der Wert von zaehler. Das sollte idR so schnell gehen, dass die 9600 Baud wohl eher nicht ausreichen. Des weiteren gibt es nicht die Möglichkeit mit dem Greycode zu arbeiten?? Kenne deinen optischen Drehencoder nicht.

Der Zähler läuft natürlich die ganze Zeit und viel schneller als man es verfolgen kann. Weil du es so programmiert hast.

Wenn du die Schritte damit zählen willst, musst du die Zählvariable als volatile deklarieren (ganz wichtig), sie in der ISR inkrementieren und ab und zu (vielleicht alle 100-300ms) in loop() ausgeben. Dazu millis() verwenden, nicht delay(). Was nicht geht ist ist Serial.print() in der ISR. Genauso bringt es nichts so schnell auf Serial zu schreiben. So schnell kann das gar nicht gesendet werden.

Danke für die schnellen Antworten und Hinweise.

@ sschultewolter: Der Encoder ist ein GIO40A-22 und wird nicht mehr gebaut. Greycode habe ich nachgeschlagen - hat er nicht - nur zwei versetzte Rechteckspannungen.

@serenifly: Serial Monitor und LED-Ausgaben sind nur für die "Fortschrittskontrolle" gedacht, die kommen wieder raus.

Die anderen Hinweise: da muss ich mich erst reinknieen.

Solche Encoder muss man auch nicht per Interrupt bearbeiten. Es sei vielleicht der Encoder dreht sich ganz, ganz schnell. Es reicht alle paar ms zu pollen: http://www.mikrocontroller.net/articles/Drehgeber

Der Code da lässt sich auch auf den Arduino anpassen. Timer0 kannst du allerdings nicht verwenden, da darauf millis() und delay() läuft. Außerdem ist da für 8 MHz. millis() oder vielleicht micros() für das Timing tut es aber erst mal auch. Der Code da fragt alle 1ms den Zustand ab.

Und wenn man einen wirklich schnellen Encoder per ISR behandelt blockiert er ständig das Programm...

Ansonsten, wenn du hier mal nach "rotarary encoder", "Drehgeber" oder "Inrekrementalgeber" suchst, findest du auch fertigen Code für den Arduino.

wenn man einen wirklich schnellen Encoder per ISR behandelt blockiert er ständig das Programm

;) Na, das ist aber der Sinn einer ISR, dass sie das eigentliche Programm unterbricht und schnell ein bisschen was macht, sogar während loop bequem in delay() oder sonstwo hängen sollte/könnte !

Ist halt abzuwägen, was bequemer ist: - Sorgfältig die ISR mit der Übernahme der volatile-Variablen nach loop zu synchronisieren - Oder gleich alles in loop zu machen, und da eben keine Bequemlichkeits-Delays, pulseIn(), und ähnliches benutzen zu können.