Forum: Mikrocontroller und Digitale Elektronik PIC12F629 GPIO3 Problem


von Matthias L. (mcl024)


Angehängte Dateien:

Lesenswert?

Hallo Zusammnen,

ich arbeite zur Zeit mit einem PIC12F629. Hier habe ich ein Takt Signal 
(grün) an GPIO3 hängen. Meine IO_Pins sind folgendermaßen initialisiert:
1
void port_init(void)
2
{
3
    TRISIO  =  0b00101000; // Register for define the I/O Pins as Input or Output
4
}

meine Interrupt Init sieht so aus:
1
void Interrupt_Init(void)
2
{
3
  GIE    = 1;  // Global Interrupt Enable
4
  GPIE  = 1;  // Port Change Interrupt Enable
5
  IOC3  = 1;  // GPIO3 Interrupt on Change Enable
6
  GPIF  = 0;  // Interrupt on Change Bit cleared
7
}

Daraus sieht man das ich den GPIO3 als Interrupt on Change konfiguriert 
habe. Nun möchte ich bei jeder negativen Flanken des Takt-Signals in der 
ISR etwas tun. Dazu habe ich meine ISR folgendermaßen aufgebaut.
1
static void interrupt  clk_ISR(void)
2
{
3
  if(!TAKTSIGNAL && GPIF)
4
        {
5
             TRIG = !TRIG
6
             //etwas tun
7
             GPIF = 0;
8
        }
9
}

Hier schaue ich ob das Takt-Signal nach einsetzen des Interrupt == 0 
ist. Somit stelle ich fest ob es sich um eine negative Flanke handelt. 
Dann toggle ich erstmal einen Trigger (gelb).

Bei den ersten 11 negativen Flanken geht das auch gut, doch dann (rot 
gekennzeichnet) gehe ich bereits bei einer positiven Flanke in die 
if-Anweisung.

Woran kann das liegen?
Liegt das vielleicht an dem speziellen GPIO3.
Hat jemand Erfahrung.

von Matthias L. (mcl024)


Lesenswert?

Die falsche Auswertung des Takt-Signals erfolgt nach längerer Analyse 
mit dem Oszi sehr unregelmäßig. Sobald ich die if-Anweisung wiederhole 
tritt der Fehler nicht mehr auf.
1
static void interrupt  clk_ISR(void)
2
{
3
  if(!TAKTSIGNAL && GPIF)
4
  {
5
      if(!TAKTSIGNAL && GPIF)
6
      {
7
          TRIG = !TRIG
8
          //etwas tun
9
           GPIF = 0;
10
       }
11
   }
12
}

Das kann doch nicht sein! Der Interrupt tritt ja erst bei einer Änderung 
des IO-Pins auf.

von Matthias L. (mcl024)


Lesenswert?

Hat noch keiner ne Idee oder ähnliche Erfahrungen gemacht?

von Eschi (Gast)


Lesenswert?

...naja, falls es am GPIO3 liegt könntest Du ja einen anderen Eingang 
probieren - falls möglich.
Wird der IRQ nicht auch von der pos. Fanke ausgelöst, aber das Flag dann 
nicht zurückgesetzt. Das Prg. also ständig zum im IRQ läuft? Probier mal 
das GPIF=0 aus der Klammer rauszunehmen. Das Setzen des Trig. Ausgangs 
erlärt es aber nicht.
Lt. Datasheet wird das GPIF auch durch ein erneutes Einlesen 
zurückgesetzt (kein Plan was Dein Programm sonst noch treibt).

Gruss Martin

von Martin S. (drunkenmunky)


Lesenswert?

Was ist denn überhaupt TRIG? Ist das ein Ausgang?

Auf Seite 23 des Datenblattes steht, dass du zum Rücksetzen des 
Interruptflag den GPIO lesen oder schreiben MUSST. Das ist leider keine 
ODER-Verknüpfung im Datenblatt, sondern eine UND. Wenn dein TRIG 
direkt(!) ein Ausgang ist, sollte das eigentlich reichen. Sonst füge 
doch noch ein
GPIO;
bevor du das Flag zurücksetzt.

Hast du den IOC auch nur bei diesem einen Pin eingeschalten und bei 
sonst keinem?

Ein Tipp: Schau dir mal den 12F1822 an. Bei dem musst du den Port nicht 
extra lesen oder schreiben zum zurücksetzen. Und man kann für jeden Pin 
einstellen ob ein Interrupt bei der steigenden oder fallenden Flanke 
oder bei beiden ausgelöst werden soll. Und jeder Pin hat auch sein 
eigenes Interruptflag. Kostet nur 3 Cent mehr ;-)

von Matthias L. (mcl024)


Lesenswert?

Hey

Danke für die Antworten.

Also TRIG ist eine Ausgang (GPIO1). Sollte es am zurücksetzen des GPIF 
liegen sollte der Fehlerfall dann nicht immer auftreten? Der Fehler 
tritt total unregelmäßig auf.

Es ist nur Interrupt on Change an Pin 3 aktiviert (siehe Interrupt_Init)

von Dani (Gast)


Lesenswert?

Dein Taktsignal sieht nicht wirklich regelmässig aus... Was ist denn das 
für eine Taktquelle? Kannst du mit Sicherheit ausschliessen dass die 
Taktquelle prellt?

Gruss Dani

von Matthias L. (mcl024)


Lesenswert?

ja das kann ich definitiv. Ich habe das Takt-Signal schon genau mit Oszi 
unter die Lupe genommen.
Das kann es nicht das Problem sein.

von Martin S. (drunkenmunky)


Lesenswert?

Hast du den IOC auch nur bei diesem einen Pin eingeschalten und bei
sonst keinem?

Sonst poste doch mal das ganze Programm, dann kann man auch besser 
helfen.

von Uwe N. (ulegan)


Lesenswert?

Das solltest du umschreiben:
1
static void interrupt  clk_ISR(void)
2
{
3
  if(GPIF)
4
    {
5
      if(!TAKTSIGNAL)
6
        {
7
             TRIG = !TRIG
8
             //etwas tun
9
        }
10
      GPIF = 0;
11
    }
12
}
sonst wird nach einer steigenden Flanke das Interruptflag nicht 
gelöscht. Dann springt der Prozessor immer wieder in die 
Interruptroutine, bis irgendwann mal der Eingang 0 wird.
Erklären tut das den Effekt leider noch nicht...
Eigentlich sollte es den Prozessor nur weitgehend lahmlegen, während der 
Eingang 1 ist. Das könntest du testen, indem du im Hauptprogramm nur 
einen Ausgang toggelst. Das sollte während 1 am Eingang wesentlich 
ausgebremst werden.
Hier sieht es ja so aus, als würde im Interrupt für eine steigende 
Flanke noch eine 0 vom Port gelesen, oder das Signal prellt doch. Und 
das so kurz, dass in der Interruptroutine für die steigende Flanke schon 
wieder eine 0 gelesen wird, die nachfolgende steigende Flanke aber noch 
keinen neuen Interrupt auslösen kann. Sonst hättest du einen kurzen 
Impuls an der steigenden Flanke.

von Michael L. (michaelx)


Lesenswert?

Matthias Laubnitz schrieb:
> ...
>
1
> ...
2
>   if(!TAKTSIGNAL && GPIF)
3
>   {
4
>       if(!TAKTSIGNAL && GPIF)
5
>       {
6
>           ...
7
>
>
> Das kann doch nicht sein! ...

Durch die doppelte Prüfung wird wohl ein kurzes Prellen des Taktes 
ausgeblendet. An sonsten gilt was Uwe geschrieben hat. Interessant wäre 
auch, welche Frequenz dein Einganlssignal (Takt) hat, und mit welcher 
Taktfrequenz der PIC selbst läuft.

von Matthias L. (mcl024)


Lesenswert?

@Martin S.
Es ist ein Interrupt on Change an Pin 3 aktiviert (siehe Interrupt_Init)

@Uwe Nagel
im Datenblatt auf Seite 23 steht:

The user, in the Interrupt Service Routine, can clear the
interrupt in the following manner:
a) Any read or write of GPIO. This will end the
mismatch condition.
b) Clear the flag bit GPIF.

nach dieser Ausage müßte es egal sein ob ich das GPIF Flag lösche, da 
ich es ja immer lese.

Ich habe jetzt bemerkt das es sich wohl tatsächlich um ein Timingproblem 
vom PIC handeln muss. Denn wenn ich die ISR so gestalte wie Uwe Nagel 
aber GPIF = 0 weg lasse:
1
static void interrupt  clk_ISR(void)
2
{
3
  if(GPIF)
4
    {
5
      if(!TAKTSIGNAL)
6
        {
7
             TRIG = !TRIG
8
             //etwas tun
9
        }
10
    }
11
}

tritt der Fehler nicht mehr auf, aber nur weil ich wieder durch die zwei 
if-Anweisungen ein Zeitvorteil erhalte. So meine Vermutung.

von Matthias L. (mcl024)


Lesenswert?

Sorry die Ausage das es egal ist ob ich das GPIF Null setze oder den 
IO-Pin lese, wie ich es im Datenblatt verstanden habe nehme ich zurück. 
Dann muss ich das wohl falsch verstanden haben.

Aber wie Uwe Nagel schon gesagt hat ändert das nichts am eigentlichen 
Problem.

von Matthias L. (mcl024)


Lesenswert?

Ich habe die ISR jetzt mal so geschrieben.
1
static void interrupt  clk_ISR(void)
2
{
3
  if(GPIF && !TAKTSIGNAL)
4
        {
5
             TRIG = !TRIG
6
             //etwas tun
7
             GPIF = 0;
8
        }
9
}

TAKTSIGNAL und GPIF getauscht. Es scheint zu funktionieren.

von Martin S. (drunkenmunky)


Lesenswert?

Matthias Laubnitz schrieb:
>
> The user, in the Interrupt Service Routine, can clear the
> interrupt in the following manner:
> a) Any read or write of GPIO. This will end the
> mismatch condition.
> b) Clear the flag bit GPIF.
>
> nach dieser Ausage müßte es egal sein ob ich das GPIF Flag lösche, da
> ich es ja immer lese.

Das ist, wie schon gesagt, eine UND-Verknüpfung von a) und b). Also du 
musst schon beides machen.

Sonst versuche es doch mal so:
1
static void interrupt  clk_ISR(void)
2
{
3
  if( (GPIF != 0) && (TAKTSIGNAL == 0) )
4
        {
5
             TRIG ^= 1;
6
             //etwas tun
7
             GPIF = 0;
8
        }
9
}

Ist denke ich sicherer her von der Abfrage.

Was für einen Compiler benutzt du überhaupt? Welche Version?

von Matthias L. (mcl024)


Lesenswert?

Jetzt habe ich es auch verstanden mit der UND-Verknüpfung.

So wie ich im Beitrag zuvor geschreiben habe funktioniert es. Es tritt 
kein Fehler mehr bei der Abfrage auf nur durch drehen der Abfragen.

Compiler: HI-TECH V9.8

allerding im Lite Mode

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.