Pages: [1]   Go Down
Author Topic: Bei steigender Flanke in nächste Funktion springen  (Read 4046 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 1
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo zusammen,

Ich habe folgendes vor:
Immer wenn ein wechsel von LOW nach HIGH (steigende Flanke) erfolgt, soll die nächste Funktion aufgerufen werden. Befindet man sich in der letzten Funktion, so soll bei steigender Flanke wieder an den Anfang gesprungen werden.

Nun bin ich soweit, das er bei HIGH an Pin 13 led_1 abarbeitet und bei LOW led_2. Ich möchte dies noch erweitern bis led_10, jedoch weis ich nicht wie das oben beschriebene zu Programmieren ist.

Code:
const int inputPin = 2;
const int outputPin = 13;


void setup() {               
  pinMode(outputPin, OUTPUT);
  pinMode(inputPin, INPUT); 
}

void loop(){
if (digitalRead (inputPin) == HIGH) {led_1();}
if (digitalRead (inputPin) == LOW) {led_2();}
}

void led_1()
{
  digitalWrite(outputPin, HIGH);   // set the LED on
  delay(1000);              // wait for a second
  digitalWrite(outputPin, LOW);    // set the LED off
  delay(1000);              // wait for a second
}
 

void led_2()
{
  digitalWrite(outputPin, HIGH);   // set the LED on
  delay(100);              // wait for a second
  digitalWrite(outputPin, LOW);    // set the LED off
  delay(100);
}

Hoffe ihr könnt mir helfen  smiley

Viele Grüße
Michael
Logged

Weinsberg, Germany
Offline Offline
God Member
*****
Karma: 3
Posts: 773
A Coder's Tale
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Du liest den inputPin aus und merkst Dir den Zustand in einer Variablen.
Vor dem merken vergleichst Du den aktuellen Zustand mit dem Wert in der Variablen, wenn der inputPin HIGH ist und der Wert in der Variblen LOW, dann hast Du eine steigende Flanke, dann zählst Du eine Zählervariable um eins hoch. Und der Zählerwert ist die Nummer der Funktion, die Du anspringen sollst. smiley-wink
Logged

Germany
Offline Offline
Edison Member
*
Karma: 46
Posts: 2309
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ganz richtig, wie es Joghurt sagt. Und wenn deine Zählervariable 10 übersteigt, setzt du sie einfach auf 1 zurück.
Logged

Mein Arduino-Blog: http://www.sth77.de/ - letzte Einträge: Teensy 3.0 - Teensyduino unter Window 7 - Teensyduino unter Windows 8

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Irgendwie passt Dein Sketch aber nicht ganz zu dem, was Du machen willst. Du schreibst, das bei einer steigenden Flanke "reagiert" werden soll, in Deinem Sketch reagierst Du aber nur auf HIGH oder LOW Deines inputPin. Du musst Dir, wie bereits geschrieben aber den alten Zustand merken und dann mit dem aktuellen vergleichen, um einen Flankenwechsel zu erkennen. Interupts würden auch gehen, sind aber etwas komplizierter und unübersichtlicher. Für den Anfang reicht sicher erstmal:
Code:
const int inputPin = 2;
const int outputPin = 13;

int count = 1;
int state = LOW;
int laststate = LOW;


void setup() {               
  pinMode(outputPin, OUTPUT);
  pinMode(inputPin, INPUT); 
}

void loop(){
 state = digitalRead (inputPin);
 
 //Flankenwechsel erkennen
 if(laststate == LOW && state == HIGH) {
    //abhängig vom counter passende funktion aufrufen
    switch(count) {
     case 1:     led_1();
                 break;
     case 2:     led_2();
                 break;
     case 3:     led_3();
                 break;
     //hier weitere "case" fälle ergänzen
    }   
    //zähler erhöhen
    count++;
    //zähler zurücksetzen
    if(count == 10) count = 1;
 }
 
 //letzten zustand merken
 laststate = state;
}

void led_1()
{
  digitalWrite(outputPin, HIGH);   // set the LED on
  delay(1000);              // wait for a second
  digitalWrite(outputPin, LOW);    // set the LED off
  delay(1000);              // wait for a second
}
 

void led_2()
{
  digitalWrite(outputPin, HIGH);   // set the LED on
  delay(100);              // wait for a second
  digitalWrite(outputPin, LOW);    // set the LED off
  delay(100);
}

void led_3()
{
  digitalWrite(outputPin, HIGH);   // set the LED on
  delay(100);              // wait for a second
  digitalWrite(outputPin, LOW);    // set the LED off
  delay(100);
}
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Danke für eure Antworten.
Ja, mein Sketch passte nicht zu dem was ich vor habe...da ich nicht weiter kam.
(Hab erst vor kurzem damit angefangen smiley-wink)

@mkl0815:
Im Prinzip funktioniert der Sketch den du gepostet hast, jedoch wird jede Funktion bei Tastendruck immer nur einmal abgearbeitet. Hab oben vergessen zu erwähnen, dass er so lange in der vorherigen Funktion bleiben soll bis die Flanke kommt. Also blinken mit 1000ms, Flanke, Blinken mit 100ms, Flanke, etc...

« Last Edit: March 06, 2012, 02:49:40 pm by Adalwolf » Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 38
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

wenn man die Sache mit dem nur-einmal-abarbeiten korrigiert, hat dein Sketch ein Problem: Das Programm hängt ständig in langen delay() fest und wird deshalb sicher viele Tastenklicks verpassen.

Das Zauberwort zur Lösung dieses Problems heißt Interrupt. Zum Glück hast du deinen Taster an Pin 2 angeschlossen (einer der beiden interruptfähigen Pins des Uno), so dass es ungefähr so funktionieren müsste:

Code:
volatile int state=1;  //Variablen, die von Iterruptroutinen angefasst werden, sollten "volatile" deklariert werden
volatile unsigned long lastTime=0;  //Zeitpunkt der letzten steigenden Flanke, nötig zum Entprellen

void setup(){
...
  attachInterrupt(0, keyPressed, RISING); // 0 ist der Interrupt für Pin 2, bei jeder steigenden Flanke wird keyPressed() aufgerufen
}

void keyPressed(){                   //state hochzählen, falls mindestens 50ms seit der letzten Flanke vergangen sind
  unsigned long now = millis();
  if (now - lastTime > 50){        //entprellen
    state++;
    if (state > 3){state=1;}
  }
  lastTime=now;
}

void loop(){
  switch (state){  //die passende Ausgaberoutine aufrufen
    ....
  }
}


Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So funktioniert es erstmal, danke flohzirkus!

Eins ist mir noch aufgefallen, manchmal reagiert er nicht auf den Tastendruck (Das könnte aber auch daran liegen das ich momentan ein Kabel benutze welches den Schalter/Taster simuliert, ohne Widerstand).

Oder ist doch im Programm ein Fehler? (Habs nochmal angehängt)

Code:
const int inputPin = 2;
const int outputPin = 13;

volatile int state=1;                   // Variablen, die von Interruptroutinen angefasst werden, sollten "volatile" deklariert werden
volatile unsigned long lastTime=0;      // Zeitpunkt der letzten steigenden Flanke, nötig zum Entprellen


void setup() {               
  pinMode(outputPin, OUTPUT);
  pinMode(inputPin, INPUT); 

attachInterrupt(0, keyPressed, RISING);       // 0 ist der Interrupt für Pin 2, bei jeder steigenden Flanke wird keyPressed() aufgerufen
}

void keyPressed(){                   // state hochzählen, falls mindestens 50ms seit der letzten Flanke vergangen sind
  unsigned long now = millis();
  if (now - lastTime > 50){          // entprellen
    state++;
    if (state > 2){state=0;}
  }
  lastTime=now;
}


void loop(){
    switch(state) {
     case 0:     
          digitalWrite(outputPin, HIGH); 
          delay(1000);                     
          digitalWrite(outputPin, LOW); 
          delay(1000);
          break;
     case 1:     
          digitalWrite(outputPin, HIGH); 
          delay(500);                   
          digitalWrite(outputPin, LOW);
          delay(500);
          break;
     case 2:     
          digitalWrite(outputPin, HIGH);
          delay(100);                 
          digitalWrite(outputPin, LOW);
          delay(100);
          break;
     //hier weitere "case" fälle ergänzen
    }   
 }
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Was mir spontan auffällt ist zum einen, das "state" bei 1 anfängt zu zählen, der switch() - case Block aber bei 0. Der erste Fall "case 0:" wird also nie erreicht.
Außerdem fehlt das "Zurücksetzen" der state Variable. state wird immer weiter erhöht und irgendwann greift keiner der "case" fälle mehr. Du kannst das recht einfach in den "default:" Zweig des "switch - case" Block packen. (siehe auch http://arduino.cc/en/Reference/SwitchCase)
Code:
...
     case 2:     
          digitalWrite(outputPin, HIGH);
          delay(100);                 
          digitalWrite(outputPin, LOW);
          delay(100);
          break;
     //hier weitere "case" fälle ergänzen
     ...
     default:
          state = 0;
          break;
}
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich habs mal geändert, hatte aber irgendwie keine Auswirkungen.
Nachdem ich jedoch eine Pulldown-Widerstand von 10k in die Schaltung eingefügt habe, funktioniert es nun smiley

Durch eine Erweiterung funktioniert nun auch vor- und zurück schalten:

Code:
const int inputPin_0 = 2;
const int inputPin_1 = 3;
const int outputPin = 13;

volatile int state=1;                   // Variablen, die von Interruptroutinen angefasst werden, sollten "volatile" deklariert werden
volatile unsigned long lastTime=0;      // Zeitpunkt der letzten steigenden Flanke, nötig zum Entprellen


void setup() {               
  pinMode(outputPin, OUTPUT);
  pinMode(inputPin_0, INPUT);
  pinMode(inputPin_1, INPUT);   

attachInterrupt(0, keyPressed_0, RISING);       // 0 ist der Interrupt für Pin 2, bei jeder steigenden Flanke wird keyPressed_0() aufgerufen
attachInterrupt(1, keyPressed_1, RISING);       // 1 ist der Interrupt für Pin 2, bei jeder steigenden Flanke wird keyPressed_1() aufgerufen
}

void keyPressed_0(){                   // state hochzählen, falls mindestens 50ms seit der letzten Flanke vergangen sind
  unsigned long now = millis();
  if (now - lastTime > 100){           // entprellen
    state++;
    if (state > 4){state=1;}
  }
  lastTime=now;
}

void keyPressed_1(){                   // state hochzählen, falls mindestens 50ms seit der letzten Flanke vergangen sind
  unsigned long now = millis();
  if (now - lastTime > 100){           // entprellen
    state--;
    if (state < 1){state=4;}
  }
  lastTime=now;
}

void loop(){
    switch(state) {
     case 1:     led_1();
                 break;
     case 2:     led_2();
                 break;
     case 3:     led_3();
                 break;
     case 4:     led_4();
                 break;
     //hier weitere "case" fälle ergänzen
     default:
          state = 1;
          break;
    }   
 }


void led_1()
{
  digitalWrite(outputPin, HIGH);
  delay(1000);
  digitalWrite(outputPin, LOW);
  delay(1000);
}


void led_2()
{
  digitalWrite(outputPin, HIGH);
  delay(500);
  digitalWrite(outputPin, LOW);
  delay(500);
}


void led_3()
{
  digitalWrite(outputPin, HIGH);
  delay(100);
  digitalWrite(outputPin, LOW);
  delay(100);
}


void led_4()
{
  digitalWrite(outputPin, HIGH);
  delay(50);
  digitalWrite(outputPin, LOW);
  delay(50);
  digitalWrite(outputPin, HIGH);
  delay(500);
  digitalWrite(outputPin, LOW);
  delay(500);
}

Nun habe ich aber ein weiteres Problem, die Schaltung soll in ein RC-Modell mit Servo-Ausgängen. Dachte mir ich könnte die 5V des Servo-Ausgang schalten, jedoch ändert sich dann nur die Pulsbreite des PWM-Signals (Hätte mal vorher darüber nachdenken sollen smiley-wink)
Wie kann ich das PWM-Signal auswerten?
Folgendes soll passieren:
Ich habe einen 3-Stufen-Schalter (Bei Mittelstellung keine Aktion ausführen, Impulslänge zwischen 1,3 und 1,7ms).
Beim Impulslängen kleiner 1,3ms wird zurückgeschaltet (Schalterstellung unten), bei Impulslängen größer 1,7ms wird weitergeschaltet (Schalterstellung oben).

Werden hierfür beide Interrupt-Eingänge benötigt, oder kann das auch anderst realisiert werden?
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 38
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wenn ich dich richtig verstehe, hast du jetzt einen *Schalter*, der in seinem Zustand bleibt - und keinen Taster, bei dem sich der Arduino merken muss, ob und wie oft er schon gedrückt wurde?

Dann sind Interrupt-Kopfstände und Flankensuche überflüssig, und dein loop() sieht etwa so aus:

Code:
void loop(){
  liesSchalterstellung();
  berechneServoWinkel();
  setzeServoWinkel();
}

Zum Kontrollieren von Servos gibt es eine Library, die die ganze Pulsweiten-Ansteuerung im Hintergrund Timer-gesteuert erledigt, schau' da mal rein.

Schönen Sonntag noch!

Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hab mich wohl etwas falsch ausgedrückt, momentan ist es ein 3-Stufen-Schalter der aber eigentlich ein (Ein)-Aus-(Ein)-Taster sein soll. Also Ein-Oben state++, Ein-Unten state--.
Dieser Schalter ist in einem Sender für ein RC-Modell verbaut, am Empfänger kommen aber nur Impulse für Servos raus. Diesen Impuls müsste man nun irgendwie am Arduino einlesen.
Bei Schaltermittelstellung ergeben sich Impulslängen von ca. 1.5ms, jedoch wären hier eine Überwachung von +/-0.2ms von Vorteil.

Hoffe nun ist es eher zu verstehen smiley-wink

Die Servo-Libary ist aber nur zum ansteuern von Servos, oder hab ich da was falsch verstanden?

Dir auch einen schönen Sonntag.
« Last Edit: March 11, 2012, 08:19:51 am by Adalwolf » Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 38
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Also hoffe ich, dass ich dich jetzt richtig verstehe: Der Arduino soll Impulse von einem RC-Empfänger auswerten, die eigentlich für einen Servo gedacht sind und damit z. B. verschiedene LED-Blinkprogramme ablaufen lassen. Es ist aber nur ein Servo, der gesteuert wurde, also auch nur eine Leitung als Eingang zum Arduino. Richtig so?

Das bedeutet: du musst die Länge jedes Eingangsimpulses messen und prüfen, ob sie von der Mittelstellung abweicht.
Wenn sie das macht und beim letztenmal noch nicht gemacht hat, dann ändere den Status.

Dazu könnte man z.B. eine Interruptroutine bei jedem Zustandwechsel aufrufen lassen. Bei steigender Flanke merkt man sich die Startzeit und bei fallender berechnet man die Impulslänge und daraus dann die Schalterstellung. Die muss dann in der Interruptroutine mit der letzten Schalterstellung verglichen werden. Abhängig von Ergebnis wird eine Statusvariable gesetzt, die innerhalb von loop() abgefragt wird, um zu entscheiden, was denn nun getan werden muss.


Logged

Germany
Offline Offline
Edison Member
*
Karma: 46
Posts: 2309
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Warum denn einen Interrupt verwenden? Das wäre doch mit Kanonen auf Spatzen geschossen. Ich würde das einfach über die pulseIn-Funktion erfassen.
Logged

Mein Arduino-Blog: http://www.sth77.de/ - letzte Einträge: Teensy 3.0 - Teensyduino unter Window 7 - Teensyduino unter Windows 8

Offline Offline
Newbie
*
Karma: 1
Posts: 38
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Warum denn einen Interrupt verwenden?

Weil adawolfs Hauptprogramm längere Zeit in irgendwelchen delays hängt und deshalb immer wieder Impulse verpassen würde - also nicht jeden Tastendruck zählen würde.
Logged

Pages: [1]   Go Up
Jump to: