Interrupt-Wie mach' ich's richtig?

Begonnen von Ottmar, 09.09.2024, 17:24:41 CEST

Vorheriges Thema - Nächstes Thema

Ottmar

Mein Beitrag vom 8.9.2024 10:52:25 CEST  zum Thema "Feuchten Keller trocknen"
Das dort von mir dort beiläufig angeschnittene Thema 'Interrupt" ist in einem neuen Thema wohl besser aufgehoben.

Zitat
Ein genaues Zeitintervall kann mittels Interrupt erreicht werden. Dann hängt die Genauigkeit nur von der verwendeten Zeitbasis ab (INTOSC / Quarzoszillator).
Beispiel:
Zeitbasis 4MHz, ISR-Intervall 4ms (4000us)
TMR0 als 8Bit-Counter
1 working cycle (wc) = 1us
TMR0-Prescaler: 4000us/256 = 15,625 nächsthöherer Wert =1:16
TMR0-Preset:      259-4000us/16 = 6
Indem jedoch die ISR aufgerufen werden muß,, was wohl mindestens 2 wc erfordert, wird wohl der Preset bei 7 liegen und der genaue Abgleich erfolgt mit einigen 'nop' (1wc)-Befehlen.
Im beiliegenden Code (für den 18F14K22 geschrieben) findest Du ein Beispiel dazu, allerdings für 8MHz, was sich aber nur im Prescaler 1:32 von obigem Rechenweg unterscheidet. Dort werden die Zeiten s, min, Std und Tag generiert.
Ende Zitat

Zitat pic18 vom 8.9.2024  10:07:25 CEST "Feuchten Keller trocknen "
@Ottmar, so ähnlich hatte ich es früher gemacht ist aber zu ungenau. Heute stelle ich den Timer fest ein. Im Interrupt zähle ich einen festen Wert hinzu um mit geraden Zahlen zu arbeiten, sobald ein Wert von x überschritten wird dann ziehe ich die eine gerade Zahl für z.B. 100ms ab. Also ich stelle nicht auf Null. Somit habe ich nach einer gewissen Zeit eine Korrektur. Wenn die 100ms erreicht sind setze ich eine Flagge. Da ich den Interrupt recht kurz halten will zähle ich die Sekunden usw im Hauptprogramm zusammen wenn die Flagge erreicht ist. (Es darf natürlich hier die Schleife nicht zu lange sein)
Ich kann dadurch noch andere Abläufe im Interrupt ausführen. Mein Hauptprogramm ist natürlich viel komplexer. Ich frage hier viele Temperaturfühler ab und habe etliche Schnittstellen. Auch habe ich Internetzugang, wo ich die Werte herausschicke und auch Einstellungen vornehmen kann. Ich hole mir auch die Internetzeit vom Server.
Ende Zitat

Hi pic18
Du hast sicher gute Gründe, um so mit dem Interrupt einen Zeittakt zu erzeugen bzw. auszugeben. Für mich, der bisher immer die von mir mitgeteilte Methode verwendet hat, ist nun nicht ersichtlich, wo jeweils die Vor- und Nachteille zu finden sein könnten.

Könntest Du mir da bitte ein wenig auf die Sprünge helfen?

Im MPLAB-Simulator (V.8.92) habe ich schon bemerkt, daß mit der Zeit sich Abweichungen summieren, habe aber nie dafür die Ursache finden können. Bei -Messungen mit einem Frequenzzähler, sind mir solche Abweichungen nicht aufgefallen (hab's vielleich nicht beachtet ;.( .


mfg. Ottmar

pic18

Ich habe hier im Anhang ein C-Programm, das alle 10ms den Zähler weiterzählt.
Es ist eine Taktfrequenz von 40Mhz, ich zähle (in TimerIsr) bei jedem Interrupt 256 dazu, wenn der Wert >= 3125 dann ziehe ich 3125 ab. Die Berechnung habe ich im Kommentar. In Assembler kannst Du natürlich einfach das Hi-Byte um 1 erhöhen (+256)
void initTimer(void) {
/*
    T0CONbits.T08BIT = 1; // 0 - 16 bit; 1 - 8 bit
    T0CONbits.T0CS = 0; // 0 = Internal clock (FOSC/4)
    T0CONbits.PSA = 0; // 0 = Timer0 prescaler is assigned. Timer0 clock input comes from prescaler output.
    T0CONbits.T0PS = 7; // Prescaler 1:32

    T0CONbits.TMR0ON = 1; // 1 - Timer enabled
*/

    INTCONbits.TMR0IF = 0; // Clear Timer0 overflow flag
    INTCONbits.TMR0IE = 1; // Enable Timer0 overflow interrupt

//TMR0ON T08BIT T0CS T0SE PSA T0PS2 T0PS1 T0PS0
//  1 1   0   0? 0 1 0 0
 T0CON = 0xc4;
}

void TimerIsr(void) {

/*     	##### TIMER0 10 ms bei 40MHz ######
		8 Bit 1:32 / Clock_Rate 10ms
   		(256*32*4)/(40*10^6 s^-1 * 10^10-3 s) = 8,192E-2 =(256/3125)
*/
	INTCONbits.TMR0IF = 0;
    timer_inc += 256;

    if (timer_inc >= 3125) {
        timer_inc -= 3125; // = 10 ms vorbei
		timer10ms++;

timer.txt

vloki

Ich bin etwas irritiert ;-)

Das mit der Korrektur des Timerwertes macht ihr aber nur,
wenn ihr keinen Timer zur Verfügung habt, der eine COMPARE Funktion hat, oder?
MPLABX  XC8  KiCAD

Ottmar

Mit dem von pic18 vorgeschlagenen Weg habe ich mich nun beschäftigt und kann keine Vorteile erkennen. Die Taktgebung in der ISR wie von mir dargestellt (nicht auf meinem Mist gewachsen!), ist erheblich einfacher und mit weniger Rechenaufwand verbunden. Auch hier kann ein Flag gesetzt und im Hauptprogramm ausgewertet werden, wenn man in der ISR Rechenzeit sparen will.
Wenn ich das C-Beispiel in Assembler umzusetzen versuche, kann ich keinen Gewinn an Genauigkeit erkennen, indem ja der Zähler bei jedem Interrupfaufruf nicum einzelne, sondern um 256 Arbeitszyklen incrementiert wird.
Gibt die ISR nur ein Flag aus, welches im Hauptprogramm zeitgerecht ausgewertet werden soll, kann es geschehen, daß z.B. durch eine zeitaufwendige Ausgabe im LCD oder eine aufwendige Rechenoperation, das in der ISR gesetzte Flag "übersehen" wird.

M.E. ist die Zeitmessung wie von mir mittels ISR dargestellt, nur von der Genauigkeit des Prozessor-Arbeitstaktes abhängig, welche z.B. mittels Quarz oder internem Oszillator bereitgestellt wird.

Schnellantwort

Name:
Tastenkürzel: Alt+S Beitrag schreiben oder Alt+P für Vorschau

Similar topics (2)