Hallo, wie kann ich einen TimmerX auf 120sekunden einstellen. Ich habe eine Anweisung(siehe unten) wo ich jede 120s in die Anweisung rein möchte. if(Timerx > 120sec) (...) Fosc/4 = 1Mhz...Vorteiler auf 1/8..z.B Timer1(16Bit) 65536 sind es laut meiner Rechnung TMRx = [1MHz/(8*65536)] = 524ms Besten Dank JN
Kann hinkommen. Den Timer bekommst du prinzipiell nur auf einen gewissen Maximalwert gestellt (irgendwelche Millisekunden). Brauchst du größere Zeitabstände musst du in der ISR eine Variable hochzählen und das dann somit in Software machen. Auf diese Variable kannst du dann prüfen oder ein Flag setzen.
Dominik S. schrieb: > Kann hinkommen. > Den Timer bekommst du prinzipiell nur auf einen gewissen Maximalwert > gestellt (irgendwelche Millisekunden). > Brauchst du größere Zeitabstände musst du in der ISR eine Variable > hochzählen und das dann somit in Software machen. > Auf diese Variable kannst du dann prüfen oder ein Flag setzen. Kannst du das an einem Beispiel erläutern? Mfg
Naja... im einfachsten Fall:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
Den Timer so einstellen, dass du alle 100ms einen Überlauf hast. In der ISR hochzählen. counter/10 sind dann deine vergangenen Sekunden. Gibt natürlich noch diverse andere Umsetzungen. Du musst nur in irgend einer Form in deiner Software mitzählen wie oft der Timer schon übergelaufen ist (wie oft also schon 100ms vergangen sind).
Hi Dominik,
danke für deine Hilfe, ich habe daraus so etwas wie unten ableiten
können!
Kannst du es mir eventuell korrigieren! :))
if(TMR0IE && TMR0IF)
{
counter++;
if(counter==229) // 524ms * 229 = 120s
{
Schwellwert = ADCWert - offset;// Nach 120s neues Schwellwert
counter=0; //Reset Counter
}
//Clear Flag
TMR0IF=0;
}
}
würde das so funktionieren?
Mfg
Jesus Nvs schrieb: > if(TMR0IE && TMR0IF) hier natürlich Timer1 mit 16Bit(65536)
Jesus Nvs schrieb: > würde das so funktionieren? Kann ich dir so direkt leider nicht sagen, da ich mich mit den PICs gar nicht auskenne. In die innere If-Bedingung schreib besser >= statt ==. Es sollte zwar nicht passieren (können) aber wenn counter jetzt irgendwie doch mal auf >230 rutscht verpasst du es nicht. Was die äußere If-Abfrage macht weiß ich natürlich nicht so genau ("TMR0IE && TMR0IF"). Ich würde vermuten außen rum muss statt der If-Abfrage eher eine ISR (Interrupt Service Routine), wie oben zu sehen. Diese wird angesprungen sobald ein Interrupt auf tritt. Kann aber natürlich sein, dass das Konstrukt was PIC-spezifisches ist.
Gast
#2764476
Timer1 mit Quarz 32768 betreiben, maximaler Vorteiler, macht 2 Sekunden. Einen Zähler bis 60 zählen lassen ...
Gast
#2764512
Ja geht, kommt natürlich in den Interrupt Code rein.
vor counter solltest du "static char" machen.
Und auch wenn es geht, wäre etwas anderes generell besser.
if (!counter--) { /* code */ ; couner = 229 }
In diesem Falle wird nähmlich der Wert nach dem ersten Überlauf oder
Interrupt. Man kann einen Interrupt auch mittels das Setzen von TMR0IF
selbst forzieren, ansonsten würde der Wert erst nach 120 Sekunden
übernommen, was zu Kopfzerbrechen führen könnte.
Bei mir kommt dieser Wert raus: 228,8818359375
Wenn du den genau haben möchtest, dann sollte counter eine 16bit
Variable
sein und du müsstes bei jedem Interrupt den Wert 286 zuzählen, sowie
einen Startwert von 42 haben. Dann hast du keinen kummulativen Fehler.
In diesem Falle solltest
counter += 286;
if (C) { /* code */ ; counter = 42; }
Um dabei auch wieder gleich zu beginn eine Übername zu haben müsstest
du sowas haben:
static unsigned short counter = -286; // angenommen short = 16bit.
Und C ist das Carry Flag vom Status Register, wegen Überlauf sollte es
nicht bekannt sein.
Gast
#2764525
Habe hier nur den Windows Taschenrechner und der streikt, wenn du es ganauer haben willst, schreib es und dann rechne es ich dir aus, die 16bit Rechnung oben stimmt nähmlich nicht.
#define cpu_clock 8000000/4
//--- OSCCON: OSCILLATOR CONTROL REGISTER
OSCCONbits.IRCF = 0b111;
OSCCONbits.SCS= 1;
void pause_sek(uint16_t sek_temp)
{
while(sek_temp != 0)
{
pause_ms(1000);
sek_temp--;
}
}
void pause_ms(uint16_t ms_temp)
{
TMR0 = 0;
uint32_t temp_1 = (((cpu_clock / 256) * ms_temp) / 1000);
while(TMR0 < temp_1) {};
}
Gast
#2764665
@pic Du schreibst ---wird nähmlich der Wert--- und ---stimmt nähmlich nicht--- Das ist ziemlich dämlich.
Gast
#2764683
Tja passiert manchmal.
Wie gesagt, das von dir gepostete sollte funktionieren, hat aber das
Problem
daß die ersten 120 Sekunden nichts passiert.
Weiters brauchst du nur eine 8bit variable und keine 16bit, auch
solltest
du diese, wenn nicht extern gebraucht einfach als static in der Funktion
definieren, ansonsten wenn du das Ram nicht löscht, dann ist der
Variableninhalt undefiniert und du musst ihn explizit initieren.
Dieses geht auch, und counter sollte eine 8bit statische variable sein.
if (!counter--) { /* code */ ; counter = 229 }
Mit beiden hast du einen Fehler welcher ca 45 Sekunden am Tag ausmacht.
Auch diesen kann man korrigieren durch den Ansatz wie oben aufgezeigt.
Nur mit dem Windowsrechner ist es blöd das ausrechnen, wenn du es
brauchst,
dann rechne ich es dir am Montag aus.
Wenn es die Applikation aber nicht fordert, oder du den internen OSC
verwendest, oder auch nur ein Resonator dann bringt diese Berichtigung
nichts, da deine Taktquelle ein größere Fehler darstellt.
Gast
#2764706
Jesus Nvs schrieb: > wie kann ich einen TimmerX auf 120sekunden einstellen. gar nicht wg. overflow, musst halt selbst die Sekunden zählen. Programme die die Registerwerte ausrechnen gibt es mit einer google suche: pic timer calculator
Gast
#2764799
Falls du einen Timer hast, der auch im Sleepmode weiterläuft, kann man das eleganter lösen. Beispiel von einem 18F14K22:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
TMR3IF muß in der Interruptroutine gelöscht werden.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.