Forum: Mikrocontroller und Digitale Elektronik Interrupts und der tägliche Wahnsinn


von Gero N. (geronimo76)


Lesenswert?

Ich mal wieder ;-)

Ich bastle nun schon seit geraumer Zeit mit meinem 18F4520 rum... Und 
wieder hab ich Probleme mit den Interrupts.

Kurze Beschreibung zum Ablauf.

Ein externes Signal (DCF77) lege ich an INT1 und INT2 an ... INT1 ist 
dabei Interrupt mäßig auf High-Edge gestellt, INT2 auf Low-Edge
Sinn und Zweck der geschichte ist, die Impulslänge zu messen.

Mysterium eins: wenn ich die Interrupts wechsle (es kam eine High Flanke 
-> Int1 aus -> INT2 an um auf Low-Flanke reagieren zu können) wurde 
jedesmal GIEL auf Low gesetzt... beide Interrupts sind Low-Prio...
Nach ewigen rumgesuche schalte ich nun bei jedem Flankenwechsel den GIEL 
manuel wieder ein ...

Mysterium zwei: Damit das sinn macht, werd nach erhalt der High-Flanke 
Timer0 gestartet. nach erhalt der Low-Flanke dieser gestoppt und gelesen 
... so ermittle ich Impulslänge ...
ABER: das Mistding ^^ springt einfach nicht in die ISR (Timer0 ist als 
High Prio definiert)

Damit ich meine Definitionen der Prio's, Flanken ect auch wärend des 
"BEtriebs" nachvollziehen/kontrollieren kann, lass ich mir mitlerweile 
sämtliche Interrupts / Prio's an diversen Ports ausgeben (zur Kontrolle)
alles Stimmt, aber T0 Interrupt springt einfach nicht zur entspr. Pos.

bissel Quelltext:
1
void MY_HIGH_HANDLER(void);
2
void MY_LOW_HANDLER(void);
3
4
/*=============== INTERRUPT DECLARATIONS ===============*/
5
#pragma code high_vector_section=0x8
6
void MY_HIGH_INT (void)
7
  {
8
  _asm GOTO MY_HIGH_HANDLER _endasm
9
  }
10
#pragma code low_vector_section=0x18
11
void MY_LOW_INT (void)
12
  {
13
  _asm GOTO MY_LOW_HANDLER _endasm
14
  }
15
#pragma code
16
17
#pragma interruptlow MY_LOW_HANDLER
18
void MY_LOW_HANDLER(void)
19
  {
20
        PORTAbits.RA2 = 1; //ICH BIN IM LOW ISR
21
if(INTCON3bits.INT1IF)
22
      {
23
      //Steigende Flanke erkannt
24
      INTERRUPT_Int1_Off();
25
      
26
      CLEAR_IntFlag_Int1();
27
      TMR0L        = 62;      // Startwert Counter
28
      t0_teiler       = 0;      // Interrupt-counter zurück setzen
29
      T0CONbits.TMR0ON   = 1;      // T0 clk ON
30
      INTCONbits.TMR0IF  = 0;      // clear T0 Interrupt Flag
31
      INTCONbits.TMR0IE  = 1;      // T0 Interrupt ON
32
      CLEAR_IntFlag_Int2();
33
      INTERRUPT_Int2_On();
34
      INTERRUPT_Low_On();
35
      show_interrupts();
36
      }
37
    //(INT2) Fallende Flanke 
38
    if(INTCON3bits.INT2IF)
39
      {
40
      INTERRUPT_Int2_Off();
41
      
42
      CLEAR_IntFlag_Int2();
43
      T0CONbits.TMR0ON   = 0;
44
      ms_messung = t0_teiler * 10;
45
      if(t0_teiler > 1200)
46
        {PORTAbits.RA4 = 1;}
47
      else
48
        {PORTAbits.RA4 = 0;}
49
      CLEAR_IntFlag_Int1();
50
      INTERRUPT_Int1_On();
51
      INTERRUPT_Low_On();
52
      show_interrupts();
53
      }
54
    PORTAbits.RA2 = 0;
55
    }
56
}
57
58
#pragma interrupt MY_HIGH_HANDLER
59
void MY_HIGH_HANDLER(void)
60
  {
61
  PORTAbits.RA3 = 1;
62
  
63
  /* ================ TIMER 0 ROUTINE =================== */
64
  if(INTCONbits.TMR0IF == 1)
65
    {
66
    
67
    INTERRUPT_Timer0_Off();
68
    CLEAR_IntFlag_Timer0();
69
    t0_teiler++;          // incrase Counter
70
    TMR0L        = 62;    // Counterstart setzen
71
    INTERRUPT_Timer0_On();
72
    
73
    }
74
  PORTAbits.RA3 = 0;
75
  }

Frage ist, wieso springt er nicht in die High Interrupt Routine (Anhand 
meines angeschlossenen LCD sehe ich auch, das er Zählt (TMR0L ändert 
sich ständig)

in der Initialisierung ist nat. T0 configuriert
1
/*Timer 0 Settup */
2
  T0CON          = 0b00000111;   // OFF | 8bit | 256PreScale
3
  INTCON2bits.TMR0IP    = 1;      // High Interrupt

von Falk B. (falk)


Lesenswert?

@  Gero Nimo (geronimo76)

>Ein externes Signal (DCF77) lege ich an INT1 und INT2 an ... INT1 ist
>dabei Interrupt mäßig auf High-Edge gestellt, INT2 auf Low-Edge
>Sinn und Zweck der geschichte ist, die Impulslänge zu messen.

Das ist ersten Pinverschwendung und zweitens ungünstig. Denn diese 
Schaltung reagiert auf kleinste Pulse, sprich Störungen.
Praktisch tastet man das Signal mittels Timer-Interrupt mit ca. 100Hz ab 
und misst damit die Pulsbreite.

MFG
Falk

von mh (Gast)


Lesenswert?

Interrupt für den Timer eingeschaltet?

von Peter D. (peda)


Lesenswert?

Gero Nimo schrieb:
> Ein externes Signal (DCF77) lege ich an INT1 und INT2 an ... INT1 ist
> dabei Interrupt mäßig auf High-Edge gestellt, INT2 auf Low-Edge
> Sinn und Zweck der geschichte ist, die Impulslänge zu messen.

Ja, man kann es auch höllisch kompliziert machen.

Oder man überlegt erstmal, was braucht man.
Eine supergenaue Messung ist nämlich völlig überflüssig.

Man muß ja nur 100ms von 200ms unterscheiden und für die Synchronisation 
die 1000ms von 2000ms.
Und dann geht alles popelinfach nur mit nem Timerinterrupt 10ms und 2 
Zählbytes (Puls, Periode) darin:
7 - 13: 0-Bit
17 - 23: 1-Bit
70 - 130: Sekundendauer
170 - 230: Sync-Sekunde

Und fertüsch.


Peter

von Joachim (Gast)


Lesenswert?

Interessante Aufgabenstellung. Ich hätte diesen Ansatz um Zeiten zu 
messen auch schon brauchen können.

>/*Timer 0 Settup */
>  T0CON          = 0b00000111;   // OFF | 8bit | 256PreScale
>  INTCON2bits.TMR0IP    = 1;      // High Interrupt

Okay soweit.

Aber:
GIEH für das Abarbeiten der ISR von T0 in der entsprechenden 
Flankenroutine gesetzt? Ich habe es in deinem Code nicht finden können.

Mir ist so ziemlich das gleiche auch mal passiert...

von Gero N. (geronimo76)


Lesenswert?

Interrupts sind an. lasse ich mir sogar per LED anzeigen um diese 
fehlerquelle ausschließen zu können


Es ist mir Klar, das ich mit den TimerInterrupt arbeiten muss.. nur wenn 
er bei Overflow nicht in die ISRT springt, bringt mir das nix ...

ich arbeite mit 20Mhz Quarz ... ergo ist bei einem 1:256 Verhältnis 
jeder TimerTakt 0,05 ms => 12,8 ms für jeden überlauf (0-255)

bei nem 8bit timer muss ich also den overflow interrupt nehmen um die 
anzahl der interrupts zu zählen (t0_teiler) ... also sind 8 überläufe 
rund eine sekunde ,,,, da aber der Interrupt nicht funktioniert (er 
apringt nicht in die ISR) kann ich auch nicht die durchläufe und somit 
nicht die ms ermitteln...

eine möglichkeit wäre, denTimer0 auf 16bit umzustellen .. muss ich mal 
probieren


Nachtrag .... T0 stand auf 16bit ,,, da kann es natürlich nicht zu 
Keinem überlauf kommen^^

Kennt jemand ein Tool, mit dem ich mir den To einstellungen berechnen 
lassen kann .. so wie hier: 
http://www.best-microcontroller-projects.com/pic-timer-0.html

ich brauchs aber für 16bit variante / 256prescale

von Joachim (Gast)


Lesenswert?

Ach du liebe Zeit, du nimmst 'n 8-bit Timer?

Ok,
'n Tool? Nee, hab ich nicht. Hab nur das da, damit geht das aber ganz 
gut. Geht mit 32kHz genauso wie mit 25MHz. Habe beides auf meinem 
Olimex-Web-Server ausprobiert.

Beispiel für Timer 1, 16-bit, Uhrenquartz:

#define TICKS_PER_SECOND               (8)        // 125ms blinzel für 
LED
#define CLOCK_FREQ     (32768)  // Hz
#define TICK_PRESCALE_VALUE            (8)        // willkürlich



#define TICK_TEMP_VALUE_1   (CLOCK_FREQ / (TICKS_PER_SECOND * 
TICK_PRESCALE_VALUE)) // Zeilenumbruch wg. #define beachten, gell?)
#define TICK_TEMP_VALUE        (65535 - TICK_TEMP_VALUE_1)




#define TICK_COUNTER_HIGH       ((TICK_TEMP_VALUE >> 8) & 0xff)
#define TICK_COUNTER_LOW        (TICK_TEMP_VALUE & 0xff)




#if (TICK_PRESCALE_VALUE == 2)
    #define TIMER_PRESCALE  (0)
#elif ( TICK_PRESCALE_VALUE == 4 )
    #define TIMER_PRESCALE  (1)
#elif ( TICK_PRESCALE_VALUE == 8 )
    #define TIMER_PRESCALE  (2)
#elif ( TICK_PRESCALE_VALUE == 16 )
    #define TIMER_PRESCALE  (3)
#elif ( TICK_PRESCALE_VALUE == 32 )
    #define TIMER_PRESCALE  (4)
#elif ( TICK_PRESCALE_VALUE == 64 )
    #define TIMER_PRESCALE  (5)
#elif ( TICK_PRESCALE_VALUE == 128 )
    #define TIMER_PRESCALE  (6)
#elif ( TICK_PRESCALE_VALUE == 256 )
    #define TIMER_PRESCALE  (7)
#else
    #error Invalid TICK_PRESCALE_VALUE specified.
#endif


Dann noch:
TICK_COUNTER_HIGH
TICK_COUNTER_LOW
in der Init- und ISR in die entsprechenden Timer-Register schreiben.


Eigentlich ganz easy. Ist aus ner Microchip AN.

von Gero N. (geronimo76)


Lesenswert?

Klar ist ein 16bit timer die elegantere lösung (ICH DEPP) ... bei Timer0 
schaltet mein Hirn automatisch synchron in den 8bit modus :))

und wenn ich mir das recht überlege, brauch ich dann nicht mal mehr den 
Overflow Interrupt... zählt er dann ja bis 65536 .. was rund 3,2 seks 
sind :)

gleich heut abend mal testen .. jetzt heißt es erstaml 8h arbeiten :(

von Joachim (Gast)


Lesenswert?

>zählt er dann ja bis 65536 .. was rund 3,2 seks
sind :)
Glaub ich nicht. Wenn dein PIC mit 20MHz/4 läuft, sind 256 * volle 16bit 
ca 0,3 sek. Zeit messen ist nix gescheites mit dem Takt, man sollte 
irgendwas Vielfaches von 16bit haben wenns genau werden soll... deswegen 
bin ich auf den Uhrenquartz ausgewichen... und selbst der geht 2sek/h 
weg...

von Gero N. (geronimo76)


Lesenswert?

Hab ich da jetzt nen Denkfehler?

20Mhz / Fosc(4) sind 5Mhz ... PreScaler von 256 macht doch knapp 
19.531,25 KHz => (1/s) => 0,0000512s pro zählwert .. also aller 0,0512ms 
erhöht der den 16bit counter um 1 ... => x65536 => 3355,66ms = 3,3...sek

Rechne ich da was falsch?

wenn ich mir anhand des Timer1 berechnungstools 
(http://www.best-microcontroller-projects.com/pic-timer-1.html) mal die 
werte für 1:8 prescale und 20Mhz ansehe, bin ich ja schon bei 104ms / 
kompletten durchlauf ,,, der T0 teilt aber 1:256 .. also das 32fache ... 
32x104ms sind auch wieder um die 3,3seks

von Joachim (Gast)


Lesenswert?

Mea culpa. Sorry, stimmt. 3,3 sek. Irgendwie wohl 'n 
Taschenrechner-Tippfehler.

Aber sag mal, gibt's DCF Empfängerroutinen nicht schon fix und fertig im 
Netz? Oder steckt da mehr dahinter?

von bjnas (Gast)


Angehängte Dateien:

Lesenswert?

Hallo

Genau wegen diesen Rechnereien die mir als Anfänger das Leben schwer 
machen, erstelle ich diese Javascript Hilfsmittel.

Ist zwar noch in Arbeit, möchte es noch erweitern mit der Anzeige der 
Interrupts, aber mit Euren Daten spuckt er 3.3555/sek aus.

Die Zahlen sollten stimmen, nehme gerne Korrekturen an.

P.S. Ist Fosc(4) ein zusätzlicher Teiler beim PIC??

Würde den noch einbauen.

bjn

von Peter D. (peda)


Lesenswert?

bjnas schrieb:
> Genau wegen diesen Rechnereien die mir als Anfänger das Leben schwer
> machen, erstelle ich diese Javascript Hilfsmittel.

Ooch nöö.

Der Compiler kann doch Konstanten prima selber ausrechnen.
Einfach nur die Formel hinschreiben als Define und benutzen.

http://www.mikrocontroller.net/articles/AVR_-_Die_genaue_Sekunde_/_RTC


Peter

von bjnas (Gast)


Lesenswert?

Das Tool ist auch nicht für so Profis gedacht wie Du einer bist.

Bin immer wieder begeistert wie Du den Code optimierst. Bis ich Laie den 
dann begreife, helfen mir diese Tools (manchmal!!).

bjn

von Joachim (Gast)


Lesenswert?

PIC, Peterchen, PIC!

Und ca 4 Posts weiter oben habe ich ebenfalls eine Lösung angesetzt...

von Joachim (Gast)


Lesenswert?

>P.S. Ist Fosc(4) ein zusätzlicher Teiler beim PIC??
Grau ist alle Theorie?

Jeder externe Osc.takt (Quartztakt) wird für das Rechenwerk in einer 
Vierer-Kombination genutzt:
Q1 -> Q2 -> Q3 -> Q4 -> Q1 -> Q2 usf.

Nur bei jedem 4. Takt (bei Q1) wird der Programmzähler auf die 
entsprechende Addresse neu eingestellt und damit der nächste Befehl 
abgearbeitet. Die dazwischen liegenden Takte braucht das Rechenwerk um 
beispielsweise ein Datum einzulesen, es zu verändern und 
zurückzuschreiben.

Siehe auch: PIC18 Instruction Cycle/CLOCKING SCHEME

Es gab mal Zeiten, da hat ein Vorgang beim 8051 nicht nur vier Osc.takte 
benötigt sondern zwölf...

von Peter D. (peda)


Lesenswert?

Joachim schrieb:
> PIC, Peterchen, PIC!

Das ist ja das schöne an C.
Ob 8051, ARM, AVR oder PIC ist egal, C bleibt C.
Die Konstanten muß also auch Dein PIC-Compiler schon zur Compilezeit 
ausrechnen und die Ergebnisse in die Register laden.

Die IO-Register heißen beim AVR halt anders und ihre Funktion ist 
ähnlich.


Peter

von Gero N. (geronimo76)


Lesenswert?

Mal zurück zum Thema interrupts .... nun hab ich es endlich hinbekommen, 
mein DCF signal sauber zu lesen und Datum/Uhrzeit daraus ermitteln zu 
können ..
Aber nun stehe ich wieder vor dem selben Problem, das ein PORTB Change 
Interrupt den PIC völlig aus dem konzept brinbt..

MainSchleife sieht so aus


while(1)
{
if(DCF77_Status == 0)  //hier hin, wenn Zeit abgeglichen werden muss
  {
  INTERRUPT_PortB_Off();
  INTERRUPT_Int2_Off();
  INTERRUPT_Int1_On();
  INTERRUPT_Timer0_On();
  INTERRUPT_Timer1_Off();
  INTERRUPT_Low_On();
  INTERRUPT_High_On();
  //DCF Initialiseren
  //Signal lesen und Flanken messen
  //Bit ermitteln -> zeit berechnen
  while(dcf_time == 0);  //innerhalb der interrupts setzte ich dann 
dcf_time auf 1, wenn zeit OK ist
  }
else  //hier hin, wenn Zeit OK => standard ausgabe
  {
  INTERRUPT_PortB_On();
  INTERRUPT_Int2_Off();
  INTERRUPT_Int1_Off();
  INTERRUPT_Timer0_Off();
  INTERRUPT_Timer1_On();
  INTERRUPT_Low_On();
  INTERRUPT_High_On();

  while(dcf_status == 1)
      {
      //Ausgabe LCD wie zeit, temp ect.
      //
      }
  }
} //ENDE MainWhile

alles funktioniert ... er gleich  die Zeit ab, wechselt die Interrupts 
und bleibt dann in der "Standard ausgabe" .. aber sobald ich eine taste 
drücke, die am PortB<7:4> hängt, spinnt er rum .. als würde er nen RESET 
ausführen. allerdings werden willkürlich interrupts gesetzt (xxxIE)

hat das event. was mit den eingeschalteten PULLUPS zu tun? ...

von Joachim (Gast)


Lesenswert?

1)
http://img826.imageshack.us/i/portb452.png/
Na ich würd' schon sagen daß man die Pull-ups wegnehmen muß, immerhin 
gegen die direkt auf den Porteingang.



2)
The interrupt flag bits must be cleared in software before re-enabling 
interrupts to avoid recursive interrupts.
Dein
INTERRUPT_Int1_Off();
macht das vermutlich, sprich: tut das entsprechende Int Enable Bit 
löschen, oder? Das eigentliche I-Bit (Flag) kann man nicht sperren.



3)
Najaah... ich würde hat einfach mal nach und nach Software-Teile 
abhängen um zu kucken wo's herkommt.

von Gero N. (geronimo76)


Lesenswert?

im ISR gehe ich natürlich nach den Anweisungen

1. Interrupt aus
2. Flag löschen
3. Code, was der interrupt eig. bewirken soll ....
4. Inerrupt wieder an

ich hab mir nur die kleinen funktionen dazu gebastelt, da es dann für 
mich übersichtlicher bleibt ,,, ansonsten muss ich ständig nachschauen, 
in welchen der 5 register die Enable-bits und welchen die Flag-bits 
stehen

... werd das ganze später mal ohne zugeschaltete Pullups testen .. hoffe 
es liegt daran

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.