- LiTime Speicher und Akkus         
Seite 2 von 6 ErsteErste 1234 ... LetzteLetzte
Ergebnis 11 bis 20 von 59

Thema: Interrupt-Abfrage >>> Routine vereinfachen

  1. #11
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.06.2019
    Beiträge
    130
    Anzeige

    Powerstation Test
    Ahhh - Missverständnis!

    Reset_Status() testet nur die "Reset"-Taste an PA2,
    PA3 heisst Start_Status(), usw.
    Alles eigenständige Funktionen, in dehnen entprellt und der letzte Zustand ausgegeben wird.

    Dann scheint mein Weg doch nicht so schlecht.

    Nur bei der Auswertung bin ich mir noch nicht sicher.
    Code:
    if(RegisterA & (1<<PINA2)) != 0)
    Die Zeile sollte die "alte, gespeicherte" Pinbelegung PA2 (RegisterA, vor dem Interrupt) mit dem "neuen, aktuellen" Zustand PA2 vergleichen um heraus zu finden, ob PA2 den Interrupt ausgelöst hat.
    1- Ist eine Veränderung zu erkennen, wird PA2 entprellt, danach Zustand 0/1 abfragen und weiter bearbeiten.
    2 -Wenn nicht, wird PA3 usw. abgefragt.

    - - - Aktualisiert - - -

    Müsste der alt/neu-Vergleich nicht eher folgend aussehen?
    Code:
    volatile uint8_t RegA_alt = PINA;
    
    ISR (PCINT0_vect)
    {
      uint8_t RegA_neu = PINA;
      uint8_t RegA_diff = RegA_alt ^ RegA_neu;  // hier sollte in jedem Reg.eintrag eine "1" stehen, wenn sich zum "alten" (Vor-Interrupt-Auslösung) eine Veränderung ergeben hat
      
      If((RegA_diff & (1<<PINA2)) != 1)
      {
        //wenn Ja, mach was
      {
    
      If((RegA_diff & (1<<PINA3)) != 1)
      {
        //wenn Ja, mach was
      }
    
      //usw. mit PA4, PA5
    __________________________________________________ _
    | Sprache: C | Teensy 3.2 | Status: EwigerAnfaenger |

  2. #12
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    11.12.2007
    Ort
    weit weg von nahe Bonn
    Alter
    39
    Beiträge
    3.416
    entweder machst du deine Variablen noch zusätzlich static oder legst sie global an, sonst wirst du nie einen unterschied sehen weil sie immer neu initialisiert werden

    ob das XOR da nicht lustige seiteneffekte auslöst würde ich gern prüfen, komme heute aber definitiv nicht mehr dazu mich da etwas tiefer reinzudenken oder zu antworten
    Es gibt 10 Sorten von Menschen: Die einen können binär zählen, die anderen
    nicht.

  3. #13
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.06.2019
    Beiträge
    130
    Seiteneffekte?

    Rein logisch müsste der XOR alle Unterschiede mit einer 1 markieren.
    Baue mir gerade ein Testprogramm auf.
    __________________________________________________ _
    | Sprache: C | Teensy 3.2 | Status: EwigerAnfaenger |

  4. #14
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    18.03.2018
    Beiträge
    2.643
    so kann man es auch beschreiben.
    Rein logisch müsste der XOR alle Unterschiede mit einer 1 markieren.

    0+0 = 0, 0+1 = 1, 1+0 = 1, 1+1 = 0

  5. #15
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    07.04.2015
    Beiträge
    865
    Geht das jetzt nur um Tastenabfragen an den Inputs?
    Dann würde ich NICHT den PortChange-Interrupt verwenden, sondern einen Timer im ms-Bereich. Der alleine bewerkstelligt schon die Entprellung.
    Der Code gestaltet sich vielleicht mithilfe einer Loop etwas schöner, wobei ich auch gleich das Allgemeingültige vom Anwendungsspezifischen trennen würde:
    Code:
    uint8_t prevPINA;
    
    void InitKeys()
    {
        prevPINA = PINA;
    }
    
    ISR (TIM0_OVF_vect)
    {
      uint8_t actPINA = PINA; //buffer actual state
      uint8_t chPINA = prevPINA ^ actPINA;   //get changes with XOR
      uint8_t setPINA = chPINA & actPINA;    // get new set pins
      uint8_t clPINA = chPINA & ~actPINA;    // get new cleared pins
    
      prevPINA = actPINA; //save actual PINA in prevPINA for next ISR call 
        
      for (uint8_t i = 0; i<8; i++)
      {
        if ((setPINA >>i) & 0x01)
          KeyDown(i);
     
        if ((clPINA >>i) & 0x01)
          KeyUp(i);
      }
    }
    InitKeys wird einmalig nach dem Controllerreset aufgerufen, die ISR wäre hier z.B. der TimerOverflow.

    Das Applikationsspezifische:
    Code:
    #define KEY_ENTER 0
    #define KEY_ESC 1
    #define KEY_UP 6
    #define KEY_DOWN 7
    
    void KeyDown(uint8_t key)
    {
      switch (key)
      {
        case KEY_ENTER:
            //TODO
            break;
    
        case KEY_ESC:
            //TODO
            break;
    
    
      }
    
    
    }
    
    
    void KeyUp(uint8_t key)
    {
        //Das gleiche in grün
    }
    Ob man nun alle Pins mit Tasten belegt hat oder nur einige, ist dem allgemeinen Teil egal. Das wird erst durch die cases in den Switches entschieden.

    (nicht kompiliert, daher ohne Gewähr! Aber mal so als Idee)

  6. #16
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    11.12.2007
    Ort
    weit weg von nahe Bonn
    Alter
    39
    Beiträge
    3.416
    Als ich die Antwort geschreiben hatte hate ich wohl ein Brett vor dem Kopf, ich dachte du XORst in die gleiche Variable zurück und konnte mir irgendwie keinen Reim drauf machen wie das funktionieren sollte ^^
    Es gibt 10 Sorten von Menschen: Die einen können binär zählen, die anderen
    nicht.

  7. #17
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.06.2019
    Beiträge
    130
    Dankefür eure Ausführungen!

    Zitat Zitat von Holomino Beitrag anzeigen
    Geht das jetzt nur um Tastenabfragen an den Inputs?
    Dann würde ich NICHT den PortChange-Interrupt verwenden, sondern einen Timer im ms-Bereich. Der alleine bewerkstelligt schon die Entprellung.
    Wo siehst du den Vorteil gegenüber einem PortChange-Interrupt ?
    Der Timer-I. würde alle ca.10ms aktiv werden, obwohl Sek, Min oder Std nichts passiert.

    Zitat Zitat von Holomino Beitrag anzeigen
    Code:
      uint8_t setPINA = chPINA & actPINA;    // get new set pins
      uint8_t clPINA = chPINA & ~actPINA;    // get new cleared pins
    
      prevPINA = actPINA; //save actual PINA in prevPINA for next ISR call
    ...warum dieser Aufwand?
    In deinem chPINA stehen doch alle Pin-Änderungen. Danach müssten die entsprechenden Bits PA2-PA5 auf 1 ausgewertet werden. Habe ich hier irgend etwas übersehen?
    Nach jeder chPINA-Auswertung kommt dann sofort eine erneute Aktualisierung+Speicherung in einer volatile-Variable.
    Code:
    prevPINA = PINA;
    __________________________________________________ _
    | Sprache: C | Teensy 3.2 | Status: EwigerAnfaenger |

  8. #18
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    07.04.2015
    Beiträge
    865
    Zitat Zitat von frabe Beitrag anzeigen
    Wo siehst du den Vorteil gegenüber einem PortChange-Interrupt ?
    Der Timer-I. würde alle ca.10ms aktiv werden, obwohl Sek, Min oder Std nichts passiert.
    Weil Tasten nun mal prellen.

    Zitat Zitat von frabe Beitrag anzeigen
    ...warum dieser Aufwand?
    In deinem chPINA stehen doch alle Pin-Änderungen. Danach müssten die entsprechenden Bits PA2-PA5 auf 1 ausgewertet werden. Habe ich hier irgend etwas übersehen?
    Weil man bei Tasten auf Drücken und Loslassen üblicherweise unterschiedlich reagiert. Das chPINA zeigt beides an. Auch auf PCs findest Du genau diese vom Betriebssystem bereitgestellten Funktionen KeyDown()/KeyUp(). Warum also das Rad neu erfinden?

  9. #19
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.06.2019
    Beiträge
    130
    Erst einmal vielen Dank für eure Mühe!

    Folgenden Code finde ich sehr einfach und übersichtlich.
    Bei "volatile uint8_t RegA_akt = PINA" hat der Compiler gemeckert, daher den Umweg über InitKeys().
    Tastenentprellung ist noch nicht drin.
    Code:
    volatile uint8_t RegA_akt;						// übergeordnete Variable			
    
    void InitKeys(void)
    {
    	RegA_akt = PINA;							// aktuelles Register A wird gespeichert
    }
    
    ISR (PCINT0_vect)								// Interrupt, aus Bank0, wird ausgelöst
    {
    	uint8_t Auswahl = 0;
    	uint8_t RegA_neu = PINA;
    	uint8_t RegA_diff = RegA_akt ^ RegA_neu;  // veränderte Bits werden mit 1 belegt
    
    	if((RegA_diff & (1<<PINA4)) != 0)					// PA4 wurde verändert
    	{
    		if((RegA_neu & (1<<PINA4)) == 0)	Auswahl=40;	// PA4 ist low	
    		if((RegA_neu & (1<<PINA4)) != 0)	Auswahl=41;	// PA4 ist high
    	}
    
    	if((RegA_diff & (1<<PINA5)) != 0)					// PA5 wurde verändert
    	{
    		if((RegA_neu & (1<<PINA5)) == 0)	Auswahl=50;	// PA5 ist low
    		if((RegA_neu & (1<<PINA5)) != 0)	Auswahl=51;	// PA5 ist high
    	}
    
    	switch(Auswahl)
    	{
    		case 40:	LEDaus();	Auswahl=0;	InitKeys();	break;	// PA4 low
    		case 41:	LEDein();	Auswahl=0;	InitKeys();	break;	// PA4 high
    		case 50:	SUMaus();	Auswahl=0;	InitKeys();	break;	// PA5 low
    		case 51:	SUMein();	Auswahl=0;	InitKeys();	break;	// PA4 high
    	}
    }
    @Holomino, deine Tastenentprellung habe ich noch nicht in Gänze verstanden.

    Wie kann man aus einem ISR, einen Wert zurück geben, außer eine erneute volatile-Variable zu verwenden?


    Euch ein angenehmes Wochenende
    __________________________________________________ _
    | Sprache: C | Teensy 3.2 | Status: EwigerAnfaenger |

  10. #20
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    07.04.2015
    Beiträge
    865
    Zitat Zitat von frabe Beitrag anzeigen
    @Holomino, deine Tastenentprellung habe ich noch nicht in Gänze verstanden.
    Gesetzt den Fall, Du schließt wirklich Taster an (DAS ist mir in Deiner Anwendung nicht ganz klar, Du schriebt, Du wolltest "erst einmal" Taster anschließen, ansonsten schriebst Du nur von "Kontakten"):

    Die ATTinys setzen das Status-Flag des Port-Change beim Eintritt in die entsprechende ISR zurück. Sollte der Eingang danach noch im µs-Bereich "flimmern",
    löst das schon während der laufenden ISR den nächsten Interrupt aus - nicht sofort, da beim Betreten einer ISR implizit das "global interrupt enabled"-Flag zurückgesetzt wird. Das gesetzte Statusflag wirkt aber sofort nach Verlassen der ISR (hier wird implizit auch wieder das "global interrupt enabled" gesetzt) und Dein Programm springt direkt wieder in die gleiche ISR. Das merkst Du z.B., wenn Du in Deiner ISR einen Zähler inkrementierst. Der springt dann mal zwei oder mehr Schritte pro Tastendruck, je nachdem, wie lange das Prellen dauert und wie schnell Dein ISR-Code abläuft.

    Wenn Du im ms-Bereich über einen Timer einfach nur den Port abfragst, hast Du dieses Problem nicht. Das Abtasten der Pin-Zustände im zeitlichen Raster wirkt wie ein digitaler Tiefpass, der das Prellen oberhalb der halben Abtastfrequenz (siehe Nyquist- oder Shannon-Theorem) herausfiltert.
    Geändert von Holomino (02.08.2019 um 17:43 Uhr)

Seite 2 von 6 ErsteErste 1234 ... LetzteLetzte

Ähnliche Themen

  1. [ERLEDIGT] Interrupt Routine
    Von Saturas077 im Forum Assembler-Programmierung
    Antworten: 8
    Letzter Beitrag: 23.04.2014, 13:46
  2. Codebeispiel für Lesen von RC5 Code mit Interrupt-Routine
    Von -tomas- im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 19
    Letzter Beitrag: 25.05.2011, 13:54
  3. Interrupt Routine
    Von luvat im Forum Schaltungen und Boards der Projektseite Mikrocontroller-Elektronik.de
    Antworten: 4
    Letzter Beitrag: 16.03.2008, 21:54
  4. Interrupt in ISR-Routine freigeben
    Von dj5am im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 5
    Letzter Beitrag: 10.08.2007, 09:44
  5. uart interrupt routine
    Von Computerkora im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 4
    Letzter Beitrag: 25.11.2006, 14:45

Berechtigungen

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

LiFePO4 Speicher Test