Forum: Mikrocontroller und Digitale Elektronik PIC Timer einstellen auf 120sekunden


von Jesus N. (piccolado)


Lesenswert?

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

: Verschoben durch Moderator
von Dominik S. (dasd)


Lesenswert?

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.

von Jesus N. (piccolado)


Lesenswert?

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

von Dominik S. (dasd)


Lesenswert?

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).

von Jesus N. (piccolado)


Lesenswert?

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

von Jesus N. (piccolado)


Lesenswert?

Jesus Nvs schrieb:

> if(TMR0IE && TMR0IF) hier natürlich Timer1 mit 16Bit(65536)

von Dominik S. (dasd)


Lesenswert?

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.

von usuru (Gast)


Lesenswert?

Timer1 mit Quarz 32768 betreiben, maximaler Vorteiler, macht 2 Sekunden. 
Einen Zähler bis 60 zählen lassen ...

von pic (Gast)


Lesenswert?

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.

von pic (Gast)


Lesenswert?

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.

von Rolf R. (ultra-low)


Lesenswert?

#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) {};
  }

von EierlegendeWollMilchSau (Gast)


Lesenswert?

@pic
Du schreibst ---wird nähmlich der Wert---
und ---stimmt nähmlich nicht---
Das ist ziemlich dämlich.

von pic (Gast)


Lesenswert?

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.

von Der Rächer der Transistormorde (Gast)


Lesenswert?

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

von Scotty (Gast)


Lesenswert?

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.

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.