-         
Seite 2 von 3 ErsteErste 123 LetzteLetzte
Ergebnis 11 bis 20 von 28

Thema: Teensy 3.2 +++ Interrupt, Übergabeparameter

  1. #11
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.834
    Anzeige

    Praxistest und DIY Projekte
    Zitat Zitat von Rabenauge Beitrag anzeigen
    -Interrupts deaktivieren
    -tun, was zu tun ist
    -Interrupts aktivieren
    Vorsicht, das geht in die Hose.

    Von vorne mal angefangen. Das Deaktivieren des Interrupts am Anfang ist nicht das erste, was im Interrupthandler passiert. Da laufen noch ein Dutzend oder mehr Assemblerbefehle vorher ab, wie Status und Register retten. Wenn dort der Interrupt nicht automatisch gesperrt wäre, würde der Interrupt sofort wieder zuschlagen, da das Interruptflag noch nicht gelöscht ist. Der Interrupt muß also noch vor dem ersten Assemblerbefehl gesperrt werde, und das geht nur, wenn es automatisch passiert. Und so ist es auch. Beim Eintritt in den Interrupthandler ist mindestens dieser interrupt gesperrt. Den Interrupt im Handler zu deaktivieren ist zwar nicht unbedingt schädlich aber überflüssig und käme auch viel zu spät.

    Das Aktivieren ist aber schlecht. Zwischen dem letzten C-Befehl und dem Ende der Funktion wird das, was am Anfang des Handlers gesichert wurde, wiederhergestellt. Das sind nochmal ein Dutzend oder mehr Befehle. Die laufen jetzt mit offenen Interrupts und das ist gefährlich. Erst ganz am Ende, wenn der Prozessor den Interruptkontext verlassen hat, dürfen die Interrupte wieder zugelassen werden. Daher endet ein Interrupthandler auch nicht mit einem Return (from Subroutine) sondern einem Return from Interrupt. Das heißt häufig RETI. Der stellt den Interrupstatus wieder so ein, wie er vor dem Interrupt war.

    MfG Klebwax
    Geändert von Klebwax (23.11.2019 um 19:42 Uhr)
    Strom fließt auch durch krumme Drähte !

  2. #12
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.06.2019
    Beiträge
    123
    Kann sein, aber wie macht man´s besser?

    Zwischen
    attachInterrupt(Taster01Pin, ISR_Taster1, RISING);
    und
    Code:
    ISR_Taster1() {
      noInterrupts(); // alle Interrupts ausschalten
      Variable = Entprellung();  // volatile, ~30ms
      interrupts();  // alle Interrupts wieder einschalten
    }
    ist nicht mehr viel Platz.
    __________________________________________________ _
    | Sprache: C | Teensy 3.2 | Status: EwigerAnfaenger |

  3. #13
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    09.10.2014
    Beiträge
    5.049
    erst mal evt das hier wieder streichen (ich kann es nicht beurteilen, was nun stimmt, Klebwax vs. Rabenauge):
    noInterrupts(); // alle Interrupts ausschalten
    interrupts(); // alle Interrupts wieder einschalten


    ich vermute, 30ms warten ist auch etwas lang für eine ISR, und wenn das so ist: dann eine Statemachine programmieren:
    erst state1=0,
    beim 1.Tastendruck per Interrupt: state1=1 und timestamp1=millis()
    dann millis()-timestamp1 in loop() kontrollieren und sobald 30ms erreicht ist: Tastendruck verarbeiten und state1 wieder auf 0.

    Ich mache das bisher ganz ohne Interrupts in einer C++ Klasse, auch zum Erkennen und Unterscheiden von kurzem Click, langem Press und Doppelklick.
    Aber ich weiß ntl nicht, ob dich meine Lösung interessiert, sonst zeige ich sie dir gerne...
    ·±≠≡≈³αγελΔΣΩ∞ Schachroboter:www.youtube.com/watch?v=Cv-yzuebC7E Rasenmäher-Robot:www.youtube.com/watch?v=z7mqnaU_9A8

  4. #14
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.06.2019
    Beiträge
    123
    Zitat Zitat von HaWe Beitrag anzeigen
    Ich mache das bisher ganz ohne Interrupts in einer C++ Klasse, auch zum Erkennen und Unterscheiden von kurzem Click, langem Press und Doppelklick.
    Aber ich weiß ntl nicht, ob dich meine Lösung interessiert, sonst zeige ich sie dir gerne...
    Natürlich interessiert mich das - kann ja durch andere (erfahrene) Gedanken nicht blöder werden
    Ich finde die ISR-Auslösungen schon super - mit einer state-Mashine kombiniert - und dann als universelle Standart-Funktion mit der ich mich nie wieder beschäftigen muss... !
    Zitat Zitat von HaWe Beitrag anzeigen
    ich vermute, 30ms warten ist auch etwas lang für eine ISR, und wenn das so ist: dann eine Statemachine programmieren:
    Daher war mein Ursprungsgedanke, dass der Interrupt ein Sprungziel in die loop()-Funktion defeniert - mehr nicht.
    Dort wird dann erneut die Tastenabfrage/Entprellung und alles folgende vor genommen.
    Geht das überhaupt?
    __________________________________________________ _
    | Sprache: C | Teensy 3.2 | Status: EwigerAnfaenger |

  5. #15
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    09.10.2014
    Beiträge
    5.049
    ok, hier ist die Klasse:

    Code:
    // Button Press Object
    // (C) 2018 by dsyleixa
    
    // This example code is in the public domain for private use.
    // Use for professional or business purpose only by personal written permission 
    // by the author.
    
    // history
    // 0.0.8 new level 31 & debounce premature 2nd click
    // 0.0.7 PCF + MCP pin-read (outline) 
    // 0.0.6 adjustable long press
    // 0.0.5 adjustable dbl click speed, block press limit
    // 0.0.4 constant long press intervall
    // 0.0.3 long press= 6*short press
    
    // ButtonClass.h
    // ver 0.0.8
    
    
    #ifndef __BTNCLASS__
    #define __BTNCLASS__ 
    
    #include <Arduino.h>
    
    #define PCF_INPUT          8574
    #define PCF_INPUT_PULLUP  -8574
    #define MCP_INPUT         23017
    #define MCP_INPUT_PULLUP -23017
    #define ANALOG_HIGH         900
    #define ANALOG_LOW          100
    #define ANALOG_50            50
    #define ANALOG_100          100
    #define ANALOG_200          200
    #define ANALOG_300          300
    #define ANALOG_400          400
    #define ANALOG_500          500
    #define ANALOG_600          600
    #define ANALOG_700          700
    #define ANALOG_800          800
    #define ANALOG_900          900
    #define ANALOG_1000        1000
    
    
    
    class tButton {
      
       //---------------------------------------------------------- 
       protected:   
        
        int16_t  pin;
        int32_t  mode;
        uint32_t aktMillis, aktMillis2;
        int8_t   level, 
                 dnstate, dnstate2, upstate, 
                 btnstate, oldbtnstate;
        uint32_t MINPRESSms, DBLCLICKms, LONGPRESSms, BLOCKPRESSms, DEBOUNCEms;
    
    
        //------------------------------------- 
        int8_t dtimer() {
          if (millis()-aktMillis >= LONGPRESSms) { // long press 400ms
              return 3;
          }
          else
          if (millis()-aktMillis >= MINPRESSms) {   
              return -1;
          }
          else
          return 0;
        }
    
        
        //-------------------------------------
        int8_t dtimer2() {
          if (millis()-aktMillis2 >= BLOCKPRESSms) { // block press limit
              return 2;
          }
          if (millis()-aktMillis2 >= DBLCLICKms) { // double click limit
              return 1;
          }
          //else
          return 0;
        }
    
    
        //-------------------------------------
        int8_t readButton(int16_t _pin, int32_t _mode) {
          if(_mode==INPUT) return digitalRead(_pin);
          else
          if(_mode==INPUT_PULLUP) return !digitalRead(_pin);
          else
          if(_mode==ANALOG_HIGH) return analogRead(_pin)>900;
          else
          if(_mode==ANALOG_LOW)  return analogRead(_pin)<100;
          else
          if(_mode==ANALOG_50)  return inRange(analogRead(_pin),50);
          else
          if(_mode==ANALOG_100) return inRange(analogRead(_pin),100);
          else
          if(_mode==ANALOG_200) return inRange(analogRead(_pin),200);
          else
          if(_mode==ANALOG_400) return inRange(analogRead(_pin),400);
          else
          if(_mode==ANALOG_800) return inRange(analogRead(_pin),800);
    
    
          
          /*
          else
          if(_mode==PCF_INPUT) return !pcfRead(_pin);
          else
          if(_mode==PCF_INPUT_PULLUP) return !pcfRead(_pin);
          else
          if(_mode==MCP_INPUT) return !mcpRead(_pin);
          else
          if(_mode==MCP_INPUT_PULLUP) return !mcpRead(_pin);
          */
    
        } 
    
    
      //----------------------------------------------------------
      public:       
    
        tButton () : 
          pin(0xFF), aktMillis(0), aktMillis2(0), 
          MINPRESSms(40),     // min duration for either button press
          DBLCLICKms(150),    // max priod between double click actions
          LONGPRESSms(300),   // min duration for long press 
          BLOCKPRESSms(200),  // min wait duration after completed actions
          DEBOUNCEms(20),     // debounce time after btn press (idle, ignore) 
          mode(INPUT_PULLUP),
          level(0), dnstate(0), dnstate2(0), upstate(0), 
          oldbtnstate(0), btnstate(0)  
          { }
       
        ~tButton ()  { }
    
        //-------------------------------------
        void init(int16_t _pin, int32_t _mode, uint32_t _minpressms=40) {      
          pin  = _pin;    
          mode = _mode;  
          MINPRESSms = _minpressms;
          
          if(mode==INPUT || mode==INPUT_PULLUP)         // Button at dig GPIO
          {  
             pinMode(pin, mode);
          }
          else 
          if(mode==PCF_INPUT || mode==PCF_INPUT_PULLUP) // Button at PCF8574
          { 
             // dummy     
          }
          else 
          if(mode==MCP_INPUT || mode==MCP_INPUT_PULLUP) // Button at MCP23017
          { 
             // dummy     
          }
    
        }
    
    
        //-------------------------------------
        bool inRange(int val, int ref, int range=10 ) {
          return( (val>ref-range)&&(val<ref+range) );
        }
    
    
        //-------------------------------------
        void setclickdurations( uint32_t _minpressms,
                                uint32_t _dblclickms,
                                uint32_t _longpressms,
                                uint32_t _blockpressms ) 
        {            
          MINPRESSms =   _minpressms;
          DBLCLICKms =   _dblclickms; 
          LONGPRESSms =  _longpressms;
          BLOCKPRESSms = _blockpressms;
        }
    
    
        //-------------------------------------
        int8_t click() { // returns 1(single), 2(double), 3(long), or 0(no press)
    
          btnstate=readButton(pin, mode); 
    
          if(level==0) {     
             dnstate=0;       
             if(!oldbtnstate && btnstate) { //  1st new btn down:
               aktMillis=millis();          //  restart btn down timer 
               level=1;           
               return 0;
             }  
          }
    
          if(level==1) {                           // either btn stroke happened        
             //Serial.println("level1");    Serial.println(dnstate);
    
             if(millis()-aktMillis <= DEBOUNCEms) { // debounce
                 return 0;
             }
    
             dnstate= dtimer();             // -1=short, 3=long pess 
             
             if(!btnstate){                 // 1st btn up                          
               if(dnstate){                 // -1=short, 3=long pess
    
                 aktMillis2=millis();             
                 if(dnstate==3) {           // long press: finished !!    
                    btnstate=0;
                    oldbtnstate=0;
                    dnstate=0;
                    aktMillis=millis();
                    aktMillis2=millis();
                    upstate=0;
                    level=4;            // extra wait after long press
                    return 3;
                }
                else level=2;               // short press: next level
               }  
             }  
          }
    
          if(level==2) {                           // short press happened         
             //Serial.println("level2");  Serial.println(dnstate);
    
             upstate=dtimer2();             // check btn up pause 
    
             btnstate=readButton(pin, mode);          
             
             //Serial.print("upstate="); Serial.println(upstate);     
                 
             if(btnstate) {           // second btn click during pause: double click! 
                dnstate2=1;
                //Serial.print(" dnstate2="); Serial.println(dnstate2); 
             }
             
             
             if(upstate==0 && dnstate2)   { // if double click: next level
                level=3;
             }
             else         
             if(upstate>=1) {                           // dbl click time passed:             
                //Serial.println(millis()-aktMillis2);   // single press finished !!
                dnstate=0; 
                dnstate2=0;
                //Serial.println(dnstate);
                btnstate=0;
                oldbtnstate=0;
                level=4;
                aktMillis=millis();   
                aktMillis2=millis(); 
                upstate=0;
                level=4;                  // extra wait after single press
                return 1;  
              }
          }
    
          if(level==3) {                       // double click
             if (btnstate) {     
                btnstate=readButton(pin, mode); 
                if (btnstate) level=31;    // non-blocking while still pressed 
                return 0;                                 
             }
             if (!btnstate) {              
                //Serial.println("level3");   
                dnstate=0;                   // double click finished !!
                dnstate2=0;
                upstate=0;
                //Serial.println(dnstate);
                oldbtnstate=0;              
                aktMillis=millis();  
                aktMillis2=millis(); 
                level=4;                // extra wait after double click
                return 2;    
             }         
          }
    
          if(level==4) {                // BlockPress  wait routine
             upstate=dtimer2();
             aktMillis=millis();  
             if(upstate>=2) {
                 level=0;
                 dnstate=0;     
                 upstate=0;
                 aktMillis=millis();   
                 aktMillis2=millis();
                 //Serial.println("level4 extra wait finished");
             }
          }
    
    
          if(level==31) {    // double click, still pressed
             btnstate=readButton(pin, mode);
             if (!btnstate) {            
                level=3;
                return 0; 
             } 
             oldbtnstate=btnstate;
             return 0; 
          } 
    
          oldbtnstate=btnstate;
          return 0;                
        };    
    
        //------------------------------------- 
        int8_t state() { // returns 1(single), 2(double), 3(long), or 0(no press)
             return  click();   // alias       
        }
    
    };
    
    #endif

    hier ist ein example:

    Code:
    // Button Press Lib Testcode
    // (C) 2018 by dsyleixa
    
    // This example code is in the public domain for private use.
    // Use for professional or business purpose only by personal written permission 
    // by the author.
    
    
    
    
    #include <ButtonClass.h>
    
    
    tButton btn1;
    tButton btn2;
    
    
    void setup() {
      Serial.begin(115200);
      delay(2000);
      pinMode(13, OUTPUT); // debug
      
      Serial.println("Serial started\n");
      btn1.init(4, INPUT_PULLUP);  // <<< adjust
      btn2.init(5, INPUT_PULLUP);  // <<< adjust
    }
    
    //------------------------------------------------------------------------
    
    void loop() {
      int8_t  btn;
    
      btn=btn1.click();
      if(btn) {
        Serial.print("btn1.click()=");
        Serial.println(btn);
      }
      btn=btn2.click();
      if(btn) {
        Serial.print("btn2.click()=");
        Serial.println(btn);
      }
      // delay(10);  // debug
    }


    den Teil für Analog-, MCP23017- und PCF8574-Buttonpads kannst du streichen, dazu kommen wir später

    - - - Aktualisiert - - -

    ach ja,
    und hier eine Beschreibung:

    Code:
    # Arduino
    
    
    ButtonClass tButton
    
    Instances: e.g.
    
    
    tButton mybtn;
    
    
    
    // and perhaps more:
    
    
    tButton mybtn1;
    
    
    tButton mybtn2;
    
    
    // etc
    
    
    Init:
    
    mybtn.init(pin_number,  INPUT/INPUT_PULLUP)
    - or -
    mybtn.init(pin_number,  INPUT/INPUT_PULLUP,  min_press_ms)
    (for INPUT_PULLUP mode, the press action is inverted automatically)
    (min_press_ms default: 60ms)
    
    
    
    to retrieve/refresh button click  states: 
    call repeatedly
    
    
    mybtn.click() 
    alias:  mybtn.state() 
    
    
    it returns a int8_t value 0, 1, 2, or 3:
    
    
    0: not pressed
    
    1: 1 short click (default minimum duration = 60ms)
    
    2: double click = 2 quick short clicks (default: within <= 150ms)
    
    3: a long press (minimum duration= 300ms)
    Geändert von HaWe (23.11.2019 um 10:28 Uhr) Grund: c+p Fehler
    ·±≠≡≈³αγελΔΣΩ∞ Schachroboter:www.youtube.com/watch?v=Cv-yzuebC7E Rasenmäher-Robot:www.youtube.com/watch?v=z7mqnaU_9A8

  6. #16
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.06.2019
    Beiträge
    123
    WOUW!

    Eigentlich wollte nur ich eine einfache Tasten/Kontakt-Entprellung von 20-30ms (ohne dalay) nach einer ISR-Auslösung programmieren.
    Deine Lösung scheint mir sehr viel umfangreicher und somit aufwendiger. Auch aufgrund der 6 Status-Abfragen. DIE EierLegendeWollMilchSau
    __________________________________________________ _
    | Sprache: C | Teensy 3.2 | Status: EwigerAnfaenger |

  7. #17
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    09.10.2014
    Beiträge
    5.049
    ja, ich sagte ja: anders - und nicht unbedingt das, was DU suchtest.
    ·±≠≡≈³αγελΔΣΩ∞ Schachroboter:www.youtube.com/watch?v=Cv-yzuebC7E Rasenmäher-Robot:www.youtube.com/watch?v=z7mqnaU_9A8

  8. #18
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.09.2011
    Ort
    Hessen
    Beiträge
    696
    Wenn es nur um ein einfaches Beispiel zur Tastenentprellung geht, ist das beim Teensy schon dabei, wenn man die mitgelieferten Libraries mit installiert hat.

    Die Bounce2 Library
    https://github.com/thomasfredericks/Bounce2
    macht so was, auf drei verschiedene Arten. Bounce2 und Vorgänger Bounce sind in Teensyduino enthalten, den Quelltext kann man sich ansehen, der ist nicht groß und arbeitet ohne Interrupts.

    30 ms in einer ISR sind für einen so schnellen Controller viel zu lang, das Sperren der Interrupts bringt natürlich alles durcheinander (USB, Serial, millis) usw.

  9. #19
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.834
    Zitat Zitat von Mxt Beitrag anzeigen
    Die Bounce2 Library
    https://github.com/thomasfredericks/Bounce2
    macht so was, auf drei verschiedene Arten. Bounce2 und Vorgänger Bounce sind in Teensyduino enthalten, den Quelltext kann man sich ansehen, der ist nicht groß und arbeitet ohne Interrupts.

    30 ms in einer ISR sind für einen so schnellen Controller viel zu lang, das Sperren der Interrupts bringt natürlich alles durcheinander (USB, Serial, millis) usw.
    Die von dir gezeigte Library und der Code von HaWe haben ein gemeinsames Problem: sie erwarten, daß loop() nicht länger als einige Millisekunden läuft. Dauert da eine Berechnung mal etwas länger, können kurze und lange Tastendrücke nicht mehr unterschieden werden oder gehen ganz verloren. Für ne Demo mag das passen, in einer nutzbaren Anwendung ist das aber unbrauchbar.

    Code:
    void loop() {
       debouncer.update(); // Update the Bounce instance
       if ( debouncer.fell() ) {  // Call code if button transitions from HIGH to LOW
         ledState = !ledState; // Toggle LED state
         digitalWrite(LED_PIN,ledState); // Apply new LED state
       }
    }
    In jedem loop() Durchlauf wird hier debouncer.update() aufgerufen, ist der Abstand großer als die Zeit, die die Taste gedrückt wird, wird sie nicht erkannt.

    Normalerweise erledigt man das in einem Timerinterrupt, der so im einstelligen Millisekundenbereich kommt. Da können alle Tasten bzw. Eingänge entprellt werden und auch Drehencoder ausgewertet werden. In diesem wird dann z.B. der gezeigte oder ein ähnlicher Code abgearbeitet. Die Ergebnisse können dann aus loop() abgefragt werden, wenn der Code dort bereit ist, sie zu verarbeiten.

    So ein Interrupt existiert beim Arduino, der kümmert sich da um die Millis (und lastet die CPU dabei sicher nicht aus). Leider habe ich bisher noch nichts gesehen, wie man eigenen Code in den vorhandenen Interrupt einbinden kann. Das einzige, was ich mal gesehen habe, war einen zweiten Timerinterrupt aufzusetzen, der dann parallel zum Millis-Interrupt läuft. Das ist natürlich suboptimal und für mich eine der großen Schwächen des Arduino.

    Inka hat für seine Stepper am Anfang die AccelStepper Library eingesetzt. da heiß es in der Doku:

    Poll the motor and step it if a step is due, implementing accelerations and decelerations to acheive the target position. You must call this as frequently as possible, but at least once per minimum step time interval, preferably in your main loop.
    Der Code in loop() muß hier kürzer als die Zeit für eine Schritt sein. Da ist bei Mikroschritten eigentlich gar nichts mehr in loop() möglich. Auch der Aufruf der Stepper-Lib gehört in einen (den) Timerinterrupt.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  10. #20
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.09.2011
    Ort
    Hessen
    Beiträge
    696
    Zitat Zitat von Klebwax Beitrag anzeigen
    Die von dir gezeigte Library und der Code von HaWe haben ein gemeinsames Problem:
    Das ist im Prinzip richtig, aber zumindest im Falle meiner Antwort didaktisch so gewollt. Ich denke der Fragesteller sollte erstmal dazu gebracht werden, seinen Code so hinzukriegen, dass er nicht blockierend wartet. Das geht am besten in der Loop.

    Dieser Thread ist ja offensichtlich in einem gewissen Bezug zu dem hier
    https://www.roboternetz.de/community...ttimer-via-RTC
    Ich bin mir nicht sicher, ob der Fragesteller schon so weit ist, mit der IntervalTimer Library zu arbeiten. Er würde sicher auch wieder versuchen, die Timer ISR für 30 ms zu blockiern.

    Auf das ganze "Arduino ist ungeeignet" und "habe ich nicht gesehen" gehe ich gar nicht weiter ein. In der Frage geht es um einen Teensy 3.2. Die Doku für die Interval Library ist hier
    https://www.pjrc.com/teensy/td_timin...rvalTimer.html

    Ja, es gäbe Alternativen z.B. mit den FTM, PDB oder LPTMR Timern. Nein, den Systick, der millis zählt, würde ich eher nicht erweitern.

Seite 2 von 3 ErsteErste 123 LetzteLetzte

Ähnliche Themen

  1. Teensy 3.2 +++ Interrupttimer via RTC ?
    Von frabe im Forum Arduino -Plattform
    Antworten: 1
    Letzter Beitrag: 22.10.2019, 14:56
  2. Teensy 3.2 +++ I/O-Werte, Analog-In
    Von frabe im Forum Arduino -Plattform
    Antworten: 26
    Letzter Beitrag: 18.10.2019, 08:57
  3. Der Teensy 4.0 ist fertig
    Von Mxt im Forum Arduino -Plattform
    Antworten: 44
    Letzter Beitrag: 12.08.2019, 09:24
  4. Platinenlayout Problem mit Platinenlayout - Adapterplatine für den Teensy 3.1
    Von robonooby im Forum Konstruktion/CAD/Sketchup und Platinenlayout Eagle & Fritzing u.a.
    Antworten: 9
    Letzter Beitrag: 29.06.2014, 15:09
  5. Tabelle als Übergabeparameter von Subroutine?
    Von screwdriver im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 8
    Letzter Beitrag: 09.01.2009, 15:45

Stichworte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •