PIC Timer einstellen auf 120sekunden

OP #2764216
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
#2764238
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.
OP #2764294
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
#2764306
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).
OP #2764322
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
#2764393
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.
Gast #2764512
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.
#2764541
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) {};
  }
Gast #2764683
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.
Gast #2764799
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren