PIC Timer einstellen auf 120sekunden

OP #2764216
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.
OP
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
volatile uint16_t counter;
2

3
ISR_100ms /* timer overflow interrupt, wird alle 100ms ausgelöst */
4
{
5
  counter++;
6
}
7

8
int main(void)
9
{
10
while(1)
11
{
12
  if(counter > 1200) /* sekunden mal 10, da 10 Interrupts pro Sekunde */
13
  {
14
    /* blub */
15
    counter = 0;
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).
OP
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:
> 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
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
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
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
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
Falls du einen Timer hast, der auch im Sleepmode weiterläuft, kann man 
das eleganter lösen. Beispiel von einem 18F14K22:
1
void Sleep100Ms(uint16_t delay)
2
{  while(delay_multiplier)
3
  { TMR3IE = 1;          // enable Timer3 interrupt
4
    TMR3H = 0x9E;        // high byte, Timer3 counts upwards, -> 0xFFFF-0x61A8 = 9E57
5
    TMR3L = 0x57;        // low byte, 8MHz/(8*4) -> 4 µsec * 25000 ~ 100 msec
6
    T3CON = 0b11111101;  // enable Timer3, clocked by Fosc/4, prescaler 1:8, 16 bit mode
7
    sleep();             // sleep until Timer3 interrupt, reset TMR3IF in interrupt routine!!!
8
    T3CON = 0;           // disable Timer3
9
    delay--;
10
  }
11
}

TMR3IF muß in der Interruptroutine gelöscht werden.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 14 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.