[PIC] Problem mit Interrupt

OP #1661003
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.
1
#pragma interruptlow high_isr
2
void high_isr( void )
3
{
4
  char hdt[] = "100";
5
  char zen[] = " 10";
6

7
  // Am Drehimpulsgeber wurde gedreht.
8
  if( INTCONbits.RBIF && PORTBbits.RB5 )    // Interrupt on Change ist aufgetreten
9
  {
10
    if( PORTBbits.RB4 == PORTBbits.RB3 )
11
    {
12
      frequ += add_frequ;
13
    }
14
    else
15
    {
16
      frequ -= add_frequ;
17
    }
18
    set_new_frequ();
19
  }
20
  // Der Drehimpulsgeber wurde gedrückt
21
  else if( INTCONbits.RBIF && !PORTBbits.RB5 )    // Interrupt on Change ist aufgetreten
22
  {
23
    if( stat == 0x00 )
24
      stat = 0x01;
25
    else
26
      stat = 0x00;
27
    
28
    if( add_frequ == 10 )
29
    {
30
      add_frequ = 100;
31
      SetDDRamAddr( 0x4C );
32
      while( BusyXLCD() );
33
      putsXLCD( hdt );
34
      while( BusyXLCD() );    
35
    }
36
    else if( add_frequ == 100 )
37
    {
38
      add_frequ = 10;  
39
      SetDDRamAddr( 0x4C );
40
      while( BusyXLCD() );
41
      putsXLCD( zen );
42
      while( BusyXLCD() );    
43
    }
44

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

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

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

BG
Andreas
Angehängte Dateien:
Persönliche Seite #1661036
Lesenswert?

1
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...
1
 // Am Drehimpulsgeber wurde gedreht.
2
  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
Gast #1661040
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 :)
OP #1661089
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. :-(
OP #1661107
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.
Gast #1661133
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.
Persönliche Seite #1661145
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren