- 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 Robotik Visionär Avatar von 021aet04
    Registriert seit
    17.01.2005
    Ort
    Niklasdorf
    Alter
    37
    Beiträge
    5.093
    Das ist die Variante die ich gemeint habe. Ich würde aber eine Bytevariable nehmen und einzelne Bits einem Eingang zuordnen. Bei dir ist es "Resourcenverschwendung" weil du für jeden Eingang eine Bytevariable verwendest.

    Also z.B. eine Hilfsvariable "char hilfsvariable" => Bit 0 = Freigabe PA4, Bit 1 = Freigabe PA5
    Der Code sieht dann so aus
    Code:
    if ((PINA & (1<<PA4)) && (hilfsvariable & (1<<0))){...}
    Das gleiche gilt auch für PA5. Die Schleife wird nur ausgeführt wenn PA4 == 1 und hilfsvariable == 1.

    MfG Hannes

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.06.2019
    Beiträge
    148
    Verstehe, das Prinzip ist ok, aber zu viel Speicherplatz verschwendet wenn zB. 10 Eingänge ins Spiel kommen. Hier ist mir (als Anfänger) die transparenz und einfacherere Lesbarkeit wichtig!
    Ich hatte nur bedenken wegen der Übersicht bei mehreren volatile-Variablen. Sehe hier aber keinen Ausweg.

    - - - Aktualisiert - - -

    Ist es eigentlich normal, dass bei Timer-ISR mehrere volatile-Variable eingesetzt werden?
    Folgend schon wieder eine, nur um einen Intervall-Zähler zu erhalten;
    Code:
    volatile uint8_t EingIntervall=0;									
    																			
    ISR(TIM1_COMPA_vect)
    {
    	OverflowZaehler++;
    	EingIntervall++;
    
    	if(OverflowZaehler >= 60000)		// 1ms*60 000 = 1Min
    	{
    		OverflowZaehlerReset();
    	}
    
    	if (EingIntervall==10)			// alle 10[ms] werden die Eingangskontakte abgefragt
    	{
    		RegA_KontaktAbfrage();  // Eingänge auf Veränderung analysiert
    		EingIntervall=0;
    	}
    }
    __________________________________________________ _
    | Sprache: C | Teensy 3.2 | Arduino 2.x | Status: EwigerAnfaenger |

  3. #3
    Erfahrener Benutzer Robotik Visionär Avatar von 021aet04
    Registriert seit
    17.01.2005
    Ort
    Niklasdorf
    Alter
    37
    Beiträge
    5.093
    Meiner Meinung nach ist es nicht besser lesbar. Wie man die Hilfsvariable nennt ist egal, mann kann sie z.B. auch "FreigabeEingaenge" oder sonst wie nennen.
    Ob man 1 Variable benötigt, oder 3 wird egal sein. Wenn man aber mehrere hat und so arbeitet bekommt man irgendwann ein Speicherproblem (z.B. wenn man Eingänge eines ganzen Ports steuern will). Deswegen sollte man sorgsam mit den Resourcen umgehen.

    Man kann auch mit #define arbeiten.
    z.B.
    Code:
    #define  PA4_ein  hilfsvariable |= (1<<0)
    #define  PA4_aus hilfsvariable &= ~(1<<0)
    #define  PA4_freigabe  hilfsvariable & (1<<0)
    Wenn du es nutzen willst schreibst du:

    Code:
    PA4_ein; // PA4 freigeben
    PA4_aus; // PA4 sperren
    
    if ((PINA & (1<<PA4)) && PA4_freigabe) {...}  // Abfrage auf PA4 und Freigabe PA4

    Bei der ISR kann man es so machen wie du und mehrere Variablen nehmen, oder du konfigurierst die ISR so das du alle 10ms einen Interrupt bekommst (geht nicht immer).
    Wenn man z.B. alle 10ms einen Int haben will muss man den Timer so anpassen das du, wenn du den Timer von 0-Max laufen lässt, über die 10ms kommst (Prescaler anpassen). Anschließend musst du einen "Startwert" für den Timer ausrechnen. Den musst du in der ISR jedes mal neu übergeben. Also wenn du z.B. bei einem 8bit Timer jede ISR den Wert 250 in das TCNT Register schreibst zählt er von 250 bis 255 und löst dann wieder einen Int aus.

    MfG Hannes

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.06.2019
    Beiträge
    148
    Zitat Zitat von 021aet04 Beitrag anzeigen
    Bei der ISR kann man es so machen wie du und mehrere Variablen nehmen, oder du konfigurierst die ISR so das du alle 10ms einen Interrupt bekommst (geht nicht immer).
    Dieser Timer ist als Generaltaktgeber (1ms) für das gesamte Prog konfiguriert.
    Da hängen später auch Zeitstufen/Countdownzähler etc drann.

    Die Idee mit #define finde ich gut!
    Auch die LED-Steuerungen, LEDgn_ein() etc. könnte ich direkt mit #define bestimmen.
    Wo siehst du die Grenze zw. Funktion() und #define ?

    Code:
    #define LEDgn_ein PORTB |= (1<<PB0)
    #define LEDgn_aus PORTB &= ~(1<<PB0)
    
    // statt
    
    void LEDgn_ein(void)	 // LED einschalten
    {
    	PORTB |= (1<<PB0);
    }
    
    void LEDgn_aus(void)	// LED ausschalten
    {
    	PORTB &= ~(1<<PB0);
    }
    Geändert von frabe (15.08.2019 um 14:01 Uhr)
    __________________________________________________ _
    | Sprache: C | Teensy 3.2 | Arduino 2.x | Status: EwigerAnfaenger |

  5. #5
    Erfahrener Benutzer Robotik Visionär Avatar von 021aet04
    Registriert seit
    17.01.2005
    Ort
    Niklasdorf
    Alter
    37
    Beiträge
    5.093
    Wenn du eine 1ms ISR benötigst geht es nicht anders als du es machst.

    Es hat jeder seinen eigenen Programmierstil. Wichtig ist nur das es lesbar bleibt. Du musst denken das du z.B. in einem Jahr das Programm anschaust und du bzw jemand anderes ohne "Studium" deinen Code ohne Probleme lesen können musst. Deswegen solltest du Variablen, Defines, Funktionen,... so benennen das es logisch ist und du nicht erst suchen muss was das gerade macht.

    Defines kannst du immer nehmen wenn du nur eine "Aktion" hast, wie z.B. einen Ausgang setzen. Wenn du mehrere Dinge machen musst und diese öfters ausführst, solltest du Funktionen verwenden.

    Wichtig wird es aber wenn du eigene Bibliotheken erstellst. Dann hast du eine Headerdatei (*.h) und eine dazugehörende Codedatei (*.c). In die Headerdatei kommen die ganzen Defines und Funktionsprototypen und in die Codedatei kommen die eigentlichen Funktionen.

    MfG Hannes

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.06.2019
    Beiträge
    148
    Hallo Leute.
    Habe an meinem Code weiter gearbeitet, hänge aber gerade an Tasten-/Kontaktentprellung fest.

    Bis auf folgende Anweisung mit "i"-Schleife, funktioniert alle einwandfrei - dank Eurer anregungen!
    "i" in RegA_Abfrage() sollte die 10ms-Schleifen hoch zählen. Sind 30ms (Entprellzeit) keine Veränderung vorgekommen, werden die veränderten Eingänge ausgewertet und verarbeitet.

    Irgendwo scheint sich hier ein Logikfehler zu verstecken, da RegA_Auswertung() nicht mehr angesprochen wird.

    Code:
    ISR(TIM1_COMPA_vect)
    {
    	OverflowZaehler++;
    	EingIntervall++;
    	
    	if(OverflowZaehler >= 60000)				// 1ms*60 000 = 1Min // uint16_t 0…65.535
    	{
    		OverflowZaehlerReset();
    	}
    	if (EingIntervall==10)					// alle 10[ms] werden die Eingangskontakte abgefragt
    	{
    		RegA_Abfrage();					// Eingänge auf Veränderung analysiert
    		EingIntervall=0;
    	}
    }
    
    void RegA_Abfrage(void)
    {	
    	uint8_t RegA_neu;
    	uint8_t RegA_dif;
    	uint8_t i;
    
    	RegA_neu = PINA;						// PINA-Regist. wird ausgelesen
    	if(((RegA_dif = RegA_akt ^ RegA_neu) !=0) && i>=3) // Änderungen gegenüber Vor-Interrupt=1 UND >=30ms
    	{
    		RegA_Auswertung(RegA_dif, RegA_neu);		// Pins einzeld auswerten
    		i=0;
    	}
    	i++;
    	RegA_akt = RegA_neu;						// akt. PINA in Vor-Interrupt speichern, für den nächsten ISR
    }
    
    void RegA_Auswertung (uint8_t RegA_dif, uint8_t RegA_neu)  // Pins einzeld auswerten
    {
    	uint8_t RegA_high;
    	uint8_t RegA_low;
    	uint8_t Zuweisung=0;
    	
    	RegA_high = RegA_dif & RegA_neu;		// Pins von 0 auf 1 = 1
    	RegA_low = RegA_dif & ~RegA_neu;	// Pins von 1 auf 0 = 1
    
    	if(((RegA_high & (1<<PINA4)) != 0) && (PA4frei==1))	Zuweisung=41;		// PA4 wurde high
    	if(((RegA_low & (1<<PINA4)) != 0) && (PA4frei==1))	Zuweisung=40;		// PA4 wurde low		
    	if(((RegA_high & (1<<PINA5)) != 0) && (PA5frei==1))	Zuweisung=51;		// PA5 wurde high
    	if(((RegA_low & (1<<PINA5)) != 0) && (PA5frei==1))	Zuweisung=50;		// PA5 wurde low
    
    	switch(Zuweisung)
    	{
    		case 41:	LEDrt_ein;	Zuweisung=0;	break;	// PA4 high
    		case 40:	LEDrt_aus;	Zuweisung=0;	break;	// PA4 low
    		case 51:	SUM_ein;	Zuweisung=0;	break;	// PA5 high
    		case 50:	SUM_aus;	Zuweisung=0;	break;	// PA5 low
    	}
    }
    Bemerkung:
    - OverflowZaehler ist static und wird mit 1ms, über Timer-Interrupt getaktet/hoch gezählt.
    - PA4frei, PA5frei static-Var., kommen aus dem main und schalten die jeweiligen Pin ein/aus.
    - RegA_akt, RegA_neu, EingIntervall sind static-Var.

    - - - Aktualisiert - - -

    Fehler gefunden!
    "i" muss eine static-Variable sein!
    Klappt jetzt prime - was haltet ihr von der Struktur?
    Geändert von frabe (20.08.2019 um 14:28 Uhr)
    __________________________________________________ _
    | Sprache: C | Teensy 3.2 | Arduino 2.x | Status: EwigerAnfaenger |

  7. #7
    Erfahrener Benutzer Robotik Visionär Avatar von 021aet04
    Registriert seit
    17.01.2005
    Ort
    Niklasdorf
    Alter
    37
    Beiträge
    5.093
    Ich finde den Code relativ unübersichtlich.

    Ich würde es nicht auf so viele Funktionen aufteilen. Ich würde Funktionen nur verwenden, wenn du es öfter als 1x benötigst oder wenn man diese Funktion auch in anderen Projekten genau so verwenden kann (dann würde ich es aber in eine eigenen Bibliothek geben). Das Problem wenn du es auf so viele Funktionen aufteilst ist, das du immer suchen musst.

    Ich würde alle Funktionen direkt in der ISR machen. Was mir auch auffällt ist, das du in der Auswertung zuerst eine Zahl einer Variable zuweißt und anschließend diese Variable abfrägst. Ich würde z.B. "Ledxx_ein", Ledxx_aus,... direkt in die "If"-Abfrage schreiben.

    Edit:
    Wenn ich deinen Code richtig verstanden habe (Pinabfrage und Weiterverarbeitung) sollte dieser Teil das gleiche machen.

    Man sollte, wenn es geht, auf >, >=, < oder <= Abfragen und nicht auf == wie du es bei dem 10ms Takt gemacht hast. Der Grund ist das du theoretisch den Wert auf z.B. 11 stellen kannst und dann wird weitergezählt bis der Zähler überläuft und zählt dann wieder bis 10. Wenn du eine Bytevariable hast zählt er 255ms zu lange.

    Ich habe bei dem 10ms Takt "5" genommen, weil bei diesem Programm ca. alle 2ms ein INT ausgelöst wird, bei dir muss "10" stehen.
    Mit der Variable "Eingang_Freigabe" kannst du bestimmen welche Eingänge abgefragt werden. Du kannst so darauf zugreifen wie ich es im main gemacht habe (nach dem "sei();").
    In der "10ms-Abfrage" wird geprüft ob der Eingang freigegeben ist und ob der Eingang vom vorhergehendem Eingang geändert hat (wird ebenfalls mit der Eingangsfreigabe verknüpft).
    Wenn das alles zutrifft wird der "Prellzeitzähler" um 1 erhöht, weicht er ab wird sofort der Zähler auf 0 gesetzt und der Durchlauf wird erneut gestartet. Sollte der Zähler den Maximalwert erreichen (Eingang ist konstant) werden die Aktionen ausgeführt. Bei meinem Beispiel steuert PB0 den Ausgang PB4 und PB2 den Ausgang PB5.

    Solltest du das Programm nicht ganz verstehen, einfach melden.

    Code:
    #define F_CPU 8000000UL
    
    
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    
    volatile unsigned char Prellzeit=0, Eingang_alt=0, Eingang_Freigabe=0, Takt_10ms=0;
    
    #define Ledgn_ein PORTB |=  (1<<PB4)
    #define Ledgn_aus PORTB &= ~(1<<PB4)
    #define Ledrt_ein PORTB |=  (1<<PB5)
    #define Ledrt_aus PORTB &= ~(1<<PB5)
    
    
    ISR (TIMER0_OVF_vect)
    {
         if (Takt_10ms >= 5)
         {
              if ((PINB & Eingang_Freigabe) & (Eingang_alt & Eingang_Freigabe))
              {
                   Prellzeit++;
              
                   if (Prellzeit >= 3)
                   {
                        if (Eingang_alt & (1<<PB0)) Ledgn_ein;
                        else                        Ledgn_aus;
                        
                        if (Eingang_alt & (1<<PB2)) Ledrt_ein;
                        else                        Ledrt_aus;
                        
                        
                   }               
              }    
              else
              {
                   Prellzeit = 0;
              }          
         
              Eingang_alt = PINB;    
              Takt_10ms = 0;  
         }         
         
         Takt_10ms++; 
    }     
    
    
    int main(void)
    {
         TCCR0B |= (1<<CS00) | (1<<CS01);
         TIMSK |= (1<<TOIE0);
         
         sei();
         
         Eingang_Freigabe = (1<<PB0) | (1<<PB2);
    
        while (1) 
        {
             
        }
    }
    MfG Hannes
    Geändert von 021aet04 (20.08.2019 um 20:43 Uhr)

Ä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