www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik [PIC] Problem mit Interrupt


Autor: Andreas Riegebauer (blackpuma)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen!

Ich habe hier ein Problem auf einem PIC mit dem Interrupt on Change am 
PortB. Ein Drehimpulsgeber ist wie am Bild angeschlossen.

Wenn ich am Drehimpulsgeber drehe funktioniert mein Programm. Wenn ich 
aber auf den Drehimpulsgeber drücke dann Schaltet er zwischen 10 und 100 
Hz um. Nur das er zusätzlich noch die frequenz (frequ) erhöht. Ich finde 
aber nicht heraus warum.
#pragma interruptlow high_isr
void high_isr( void )
{
  char hdt[] = "100";
  char zen[] = " 10";

  // Am Drehimpulsgeber wurde gedreht.
  if( INTCONbits.RBIF && PORTBbits.RB5 )    // Interrupt on Change ist aufgetreten
  {
    if( PORTBbits.RB4 == PORTBbits.RB3 )
    {
      frequ += add_frequ;
    }
    else
    {
      frequ -= add_frequ;
    }
    set_new_frequ();
  }
  // Der Drehimpulsgeber wurde gedrückt
  else if( INTCONbits.RBIF && !PORTBbits.RB5 )    // Interrupt on Change ist aufgetreten
  {
    if( stat == 0x00 )
      stat = 0x01;
    else
      stat = 0x00;
    
    if( add_frequ == 10 )
    {
      add_frequ = 100;
      SetDDRamAddr( 0x4C );
      while( BusyXLCD() );
      putsXLCD( hdt );
      while( BusyXLCD() );    
    }
    else if( add_frequ == 100 )
    {
      add_frequ = 10;  
      SetDDRamAddr( 0x4C );
      while( BusyXLCD() );
      putsXLCD( zen );
      while( BusyXLCD() );    
    }

    while( !PORTBbits.RB5 ); // Warten bis der Impulsgeber wieder los gelassen wird.
  }

  INTCONbits.RBIF = 0;  // Interruptflag löschen
  return;
}

Ich hoffe ihr seht da was. Wenn ich mehr vom Code braucht sagt es mir.

BG
Andreas

Autor: Peter Diener (pdiener) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
while( !PORTBbits.RB5 ); // Warten bis der Impulsgeber wieder los gelassen wird.
Das hat zwar mit dem eigentlichen Problem nichts zu tun, aber es ist 
generell keine so gute Idee, im Interrupt auf Benutzereingaben zu 
warten...
 // Am Drehimpulsgeber wurde gedreht.
  if( INTCONbits.RBIF && PORTBbits.RB5 )    // Interrupt on Change ist aufgetreten
Das verstehe ich auch nicht ganz. RB5 ist doch der Taster. Was hat das 
mit dem Drehen zu tun?


Grüße,

Peter

Autor: morph1 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
er lässt es nur zu, dass die frequenz verändert wird wenn der taster 
nicht gedrückt ist :)

aber für die leserlichkeit:

#define TASTER PORTBbits.RB5

dann musst du nur mehr TASTER schreiben, geht klarerweise auch für 
anderes :)

Autor: Peter Diener (pdiener) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, ich denke es soll so sein:
 // Am Drehimpulsgeber wurde gedreht.
  if( INTCONbits.RBIF && PORTBbits.RB4 )    // Interrupt on Change ist aufgetreten

Autor: Peter Diener (pdiener) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Fehler passiert beim Loslassen vom Taster. Das erzeugt auch einen 
Pinchange-Interrupt.
if( INTCONbits.RBIF && PORTBbits.RB5 )
ist dann einmal erfüllt und
if( PORTBbits.RB4 == PORTBbits.RB3 )
ist auch erfüllt, die Frequenz wird also um einen Schritt erhöht beim 
Loslassen des Tasters.

Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Diener schrieb:
> Der Fehler passiert beim Loslassen vom Taster. Das erzeugt auch einen
> Pinchange-Interrupt.
> if( INTCONbits.RBIF && PORTBbits.RB5 )
> ist dann einmal erfüllt und
> if( PORTBbits.RB4 == PORTBbits.RB3 )
> ist auch erfüllt, die Frequenz wird also um einen Schritt erhöht beim
> Loslassen des Tasters.

Das Interruptflag wird aber erst am Ende der Interruptroutine wieder 
gelöscht. Kann dann überhaupt noch ein Interrupt ausgelöst werden?

Ich habe jetzt mal versucht beim Einstieg in die Routine den Interrupt 
on Change auszuschalten und erst am ende der Routine wieder 
einzuschalten. Problem bleibt aber bestehen. :-(

Autor: Peter Diener (pdiener) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Kann dann überhaupt noch ein Interrupt ausgelöst werden?

Ja,  normalerweise wird ein PinchangeInterrupt bei beiden Flanken 
ausgelöst.

Es ist schon klar, dass er nicht nochmal kommt durch Drücken während der 
Interrupt noch läuft. Aber durch Loslassen triggert er nochmal.

Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Diener schrieb:
>>Kann dann überhaupt noch ein Interrupt ausgelöst werden?
>
> Ja,  normalerweise wird ein PinchangeInterrupt bei beiden Flanken
> ausgelöst.
>
> Es ist schon klar, dass er nicht nochmal kommt durch Drücken während der
> Interrupt noch läuft. Aber durch Loslassen triggert er nochmal.

Aber wenn ich beim Einstieg in die Routine den Interrupt on Change 
ausschalte und ich dann die Taste los lasse kann er nicht nochmal einen 
Auslösen oder? Ist ja deaktiviert! Und bei Sprut habe ich noch gelesen 
das GIE beim einstieg in die Interruptroutine auf 0 gesetzt wird. Also 
sind die Interrupts während eines Interrupts überhaupt aus.

Autor: Peter Diener (pdiener) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde es mal so versuchen:
// Am Drehimpulsgeber wurde gedreht.
if( INTCONbits.RBIF && ((!PORTBbits.RB4) || (!PORTBbits.RB3)) )    // Interrupt on Change ist aufgetreten

Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kein Erfolg.

Autor: Stefan Kunz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Interrupt wird nochmal ausgelößt, da die Interrupt um einiges 
schneller ausgeführt wird als der Mensch ihn wieder loslassen kann.

Autor: Stefan Kunz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wenn du wirklich darauf warten willst, dass die Taste losgelassen wird 
in der Interruptroutine dann solltest du

 while( !PORTBbits.RB5 ); // Warten bis der Impulsgeber wieder los 
gelassen wird.

in

 while( PORTBbits.RB5 ); // Warten bis der Impulsgeber wieder los 
gelassen wird.

ändern, da dein Taster den Pin sicher gegen GND zieht und wenn er 
losgelassen wurde gegen VCC.

Davon ab ist dies aber eine DEFENETIV schlechte lösung. Verfolge lieber 
die Anzahl der Interrupts und ihre Gründe, so das du den Interrupt 
unterscheiden kannst.

Autor: Peter Diener (pdiener) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein,
while( !PORTBbits.RB5 );
ist schon richtig um auf das Loslassen zu warten.

Der Punkt ist ein ganz anderer. Der Taster prellt.
Und das eventuell so schnell, dass er einen Interrupt auslöst und in 
diesem dann an verschiedenen Stellen verschiedene Werte liefert.

Das Konzept ist wie gesagt eh nicht gut mit dem Warten im Interrupt.

Ich würde einen Timerinterrupt aufsetzen, dort regelmäßig alle Kontakte 
prüfen und entprellen und dann damit weiterarbeiten.

Autor: Peter Diener (pdiener) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier gibt es ein paar gute Anregungen:
http://www.mikrocontroller.net/articles/Drehgeber

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.