- 12V Akku mit 280 Ah bauen         
Ergebnis 1 bis 10 von 59

Thema: Interrupt-Abfrage >>> Routine vereinfachen

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    07.04.2015
    Beiträge
    903
    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?

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.06.2019
    Beiträge
    148
    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 | Arduino 2.x | Status: EwigerAnfaenger |

  3. #3
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    07.04.2015
    Beiträge
    903
    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 16:43 Uhr)

  4. #4
    Erfahrener Benutzer Robotik Visionär Avatar von 021aet04
    Registriert seit
    17.01.2005
    Ort
    Niklasdorf
    Alter
    37
    Beiträge
    5.091
    Wenn du mechanische Schaltkontakte nutzt (die Prellen) ist es besser wenn du einen Timer zum Auslesen verwendest.

    Ich hätte noch eine Verbesserung des Codes. Du prüfst mit einer If auf "0" und mit einer If auf "1". Bei einer If-Abfrage gibt es aber auch noch "else", das wird immer angesprungen wenn das If-Ergebnis nicht "1" ist.
    Ein Beispiel als Pseudocode:
    Code:
    if (PB3 == 1)
    {
       Led = 1
    }
    
    if (PB3 != 1)
    {
       Led = 0
    }
    ist das gleiche wie:
    Code:
    if (PB3 == 1)
    {
       Led = 1
    }
    else
    {
       Led = 0
    }
    das ist auch das gleiche:
    Code:
    if (PB3)
    {
       Led = 1
    }
    else
    {
       Led = 0
    }
    Das if wird immer ausgeführt wenn das Ergebnis wahr ist und das ist immer der Fall wenn es nicht 0 ist. Wenn du auf "0" abfragen willst musst du aber "if (Variable == 0)" schreiben. Bei der while Schleife ist es das gleiche, deswegen sind auch "while(1)" Schleifen endlos.

    MfG Hannes

  5. #5
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.06.2019
    Beiträge
    148
    Zitat Zitat von Holomino Beitrag anzeigen
    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.
    Interessanter Aspekt, da ich davon ausging, dass erst nach dem Verlassen der ISR der nächste Interrupt durchgelassen wird. Das "speichern" des Flag innerhalb eines ISR ist mir neu und macht einiges unübersichtlicher...
    Daher wollte ich auch innerhalb des ISR die Tastenentpreller (später teils Tasten, Türkontakte, Bewegungsmelder, etc) einsetzen. Nach deiner Beschreibung, aber vollkommen unsinnig.

    Zitat Zitat von Holomino Beitrag anzeigen
    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.
    Hier habe ich immer noch "Bauchgrummeln", da auch ohne minuten-/stundenlange Kontaktbetätigung, im ms-Interval ISR-Routiniert wird - unnötige Energie und Rechenleistung!?

    Wie sieht es mit einem Kompromiss als Königsweg aus?
    Bsp:
    PortChange-Interrupt löst den Timer-Interrupt aus, der diesen wiederum ablöst und eine Tastenentpreller einleitet. Erst danach DARF der "global interrupt enabled" des PortChange wieder gesetzt werden.
    __________________________________________________ _
    | Sprache: C | Teensy 3.2 | Arduino 2.x | Status: EwigerAnfaenger |

  6. #6
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    07.04.2015
    Beiträge
    903
    Zitat Zitat von frabe Beitrag anzeigen
    Hier habe ich immer noch "Bauchgrummeln", da auch ohne minuten-/stundenlange Kontaktbetätigung, im ms-Interval ISR-Routiniert wird - unnötige Energie und Rechenleistung!?
    Löse Dich von dieser Vorstellung. Ohne Sleep-Modi (die eigentlich nur im Batteriebetrieb interessant sind) läuft der Controller in der main-Loop immer in der Runde. Da spart man nix. Die Verluste von Netzteil und Regler bewegen sich üblicherweise weit oberhalb der vom Controller aufgenommenen Leistung.

    Der von mir gepostete ISR-Rahmen dürfte incl. Stack-Push/-Pop nicht mehr als 10..20µs bei 8MHz dauern. Im Zyklus von 1..8ms aufgerufen (so schnell muss man erst mal tippen können) und bezogen auf die Gesamtleistung des Controllers reden wir also über 0,125 .. 2% Rechenlast für die Timerroutine.

  7. #7
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.06.2019
    Beiträge
    148
    Hallo - nochmal.

    Die Methoden die ihr mir mit dem Timer-ISR aufgezeigt habt ist toll und funktioniert. Soweit kann ich auch als Anfänger jede Code-Zeile nachvollziehen.
    Hier ist es so, das alle Kontakte des Register A kontinuierlich abgefragt werden. Sobald eine Veränderung statt findet, wird dieser Kontakt auf Prellung überprüft.
    Zum Entprellen wird einfach eine Variable hoch gezählt. Sollte 30ms keine Veränderung statt finden, ist dieser Kontakt entprellt!
    Danach kommt der Befehl "tu was".

    Aber ... eigentlich brauche ich eine Kontaktabfrage aus dem main() heraus.
    Innerhalb des Prg-ablauf gibt es verschiedene Bereiche. Mal ist es wichtig Kontakt PA4 dauernd zu überwachen, wärend dessen mir Eingang PA5 vollkommen egal ist.
    Erst wenn ich PA4 benötige, würde ich auf Veränderung und Entprellung abfragen.


    Oder ich sehe vor lauter Bäumen den Wald nicht mehr...
    __________________________________________________ _
    | Sprache: C | Teensy 3.2 | Arduino 2.x | Status: EwigerAnfaenger |

  8. #8
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    07.04.2015
    Beiträge
    903
    Ich denke mal, es ist kein Problem, den Code so zu erweitern, dass Du auch aus der main() auf die Tasten reagieren kannst. Tatsächlich hatte ich die Änderungen hier schon reingeschrieben, dann allerdings wieder gelöscht - ganz einfach weil es jetzt gänzlich unterschiedliche Konzepte für unterschiedliche Anwendungen gibt (nix für Ungut, aber bei "ich bräuchte" von nem Youngster lohnt es sich manchmal zu hinterfragen, ob er es denn wirklich braucht).

    Eine tastengesteuertes Displaymenü z.B. würde ich mit Funktionspointern zu erschlagen suchen. Andere logische Zusammenhänge eher mit einer einfachen StateMachine. Ob das dann allerdings immer in der main() liegt oder ebenfalls in der Timer-ISR, hängt alleine davon ab, wie lange der Ablauf der Aktionen ist. Eigentlich präferiere ich die Timer-ISR, weil sie sich ideal für mehrere "asynchone" Aufgaben eignet (Das ist zwar nicht wirklich asynchron, aber mit Prescalern kann man fabelhaft passende Abfragezyklen bauen und so die Rechenleistung optimal aufteilen). Die main() hebe ich mir dann gerne für niederpriorisierte Aufgaben auf.

    Wir müssten jetzt also erst einmal darüber sprechen, was genau Du vor hast.

Ähnliche Themen

  1. [ERLEDIGT] Interrupt Routine
    Von Saturas077 im Forum Assembler-Programmierung
    Antworten: 8
    Letzter Beitrag: 23.04.2014, 12: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, 12:54
  3. Interrupt Routine
    Von luvat im Forum Schaltungen und Boards der Projektseite Mikrocontroller-Elektronik.de
    Antworten: 4
    Letzter Beitrag: 16.03.2008, 20:54
  4. Interrupt in ISR-Routine freigeben
    Von dj5am im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 5
    Letzter Beitrag: 10.08.2007, 08:44
  5. uart interrupt routine
    Von Computerkora im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 4
    Letzter Beitrag: 25.11.2006, 13:45

Berechtigungen

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

12V Akku bauen