TMR0 på PIC16F628A går för långsamt

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
chrille112
Inlägg: 334
Blev medlem: 25 april 2005, 16:45:24
Ort: Uppsala

Inlägg av chrille112 »

Nu har jag fått igång tmr1, och den verkar gå mer exakt, men är fortfarande efter några sekunder varje minut. Så här gör jag nu:

Prescaler 1:8

Kod: Markera allt

void interrupt() {
  T1 = -2500000000;

  if(ms==10)
  {
            timeSECOND++;
            ms=1;
  }
  else
      ms++;

  PIR1.TMR1IF = 0;
}

void main() {
  ms=1;

INTCON.GIE = 1; //enable Interrupt
INTCON.PEIE = 1; //enable interrupt
T1CON = 0b00110001; // 1/8 prescaler
PIE1.TMR1IE = 1; // Interrupt bit Timer1
PIR1.TMR1IF = 0; // clear FLAG
  T1 = -2500000000;

Skulle gärna vilja köra "free-running", men förstår inte hur man får till det i praktiken... :cry:
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> och den verkar gå mer exakt,

TMR1 går *exakt* lika "exakt" som TMR0.

> Skulle gärna vilja köra "free-running", men förstår inte hur man får till det i praktiken...

Du skulle ju kunna läsa mitt föregående inlägg, men det är kanske
roligare att skriva nya... :-) :-)

Sen, om det ska vara någon mening alls att posta kod, så bör du nog
kommentera och tala om vad det är du gör på varje rad. T.ex
"T1 = -2500000000;" är inte så där direkt helt uppenbart för mig.
Vad är "T1" ? Och vad står "-2500000000" för ? Hur har du kommit fram
till (räknat ut) det värdet ??
Användarvisningsbild
chrille112
Inlägg: 334
Blev medlem: 25 april 2005, 16:45:24
Ort: Uppsala

Inlägg av chrille112 »

>TMR1 går *exakt* lika "exakt" som TMR0.
Jag menade att koden jag skrivit nu verkar vara mer exakt än den som jag gjorde förra gången

>>Du skulle ju kunna läsa mitt föregående inlägg, men det är kanske
roligare att skriva nya... Smile Smile
Jag läste din inlägg, men jag tycker att detta borde gå att göra utan en kristall till?

Jag har läst det här inlägget, det är därifrån jag fått kod http://www.mikroe.com/forum/viewtopic.php?t=6067

>>Vad är "T1" ?
unsigned T1 absolute 0x0E;
T1 is same address as TMR1L and TMR1H

>>Och vad står "-2500000000" för ? Hur har du kommit fram
till (räknat ut) det värdet ??
Kommer inte riktigt ihåg hur jag fick fram det, så jag gick in på länken och räknade om:

Om jag vill ha interrupt varje 1000 µS och kör prescaler 1:8 så räknar jag:
1000/1.6 = 625;

Nu har jag en interrupt på varje 1 ms, ökar en räknare, och när räknaren är uppe i 1000 så nollställer jag och ökar sekunder.

Med denna metoden har jag bäst resultat hittils, runt 1 sekund fel efter 5 minuters körning. Kan detta vara lösningen, eller vad tror ni? Låter den stå på under natten och hoppas på att den går lika rätt imorgon :)
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

1 sek på 5 min är ca 3.300 ppm fel.
En standard kristall bör ligga på ca 50 ppm, så du ligger
väl över 50 gånger sämre än vad du borde göra.

> unsigned T1 absolute 0x0E;
> T1 is same address as TMR1L and TMR1H

TMR1L = h'0E', TMR1H = h'0F'. Jag förstår inte vad de menar med "same address" !?

> Kommer inte riktigt ihåg hur jag fick fram det,

Precis !! Gissa nu varför man *SKA* kommentera sin kod !! :-) :-)

> Kan detta vara lösningen, eller vad tror ni?

Det verkar ju inte så, med tanke på hur fel det fortfarande går.
Det är också lite svårt att kommentera metoden bättre, utan att veta
var -2500000000 kommer ifrån.
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Då du FORTFARANDE sätter TMR1-värdet till ett visst värde är det FORTFARANDE fel väg att gå...

Och att du kan peta in ett 40-bitars värde (-2500000000) i ett 16-bitars register verkar ganska häftigt, det är mer än jag klarar av.

Nåväl, du har ett 20MHz kristall som klockbas, detta ger 5MHz som systemklocka.

Kod: Markera allt

void interrupt()
  { // Rate = 104857,6µs
  static unsigned long Sum; // Must be a big one
  PIR1.TMR1IF = 0; // Acknowledge interrupt
  Sum += 1048576; // Add the current part
  if(Sum >= 10000000)
    {
    timeSECOND++;
    Sum -= 10000000;
    }
  }

void main()
  {
  INTCON.GIE = 1; //enable Interrupt
  INTCON.PEIE = 1; //enable interrupt
  T1CON = 0b00110001; // 1/8 prescaler
  PIE1.TMR1IE = 1; // Interrupt bit Timer1
  PIR1.TMR1IF = 0; // clear FLAG
  while(1)
    {
    }
  }
Då får du en klocka som är långtidsstabil.

Ett alternativ är självklart att välja ett kristall som är "binärt" som sodjan skriver om, ytterligare ett alternativ är att använda Timer2 där du kan ställa vad den ska räkna till innan den ska flöda över och ge interrupt. Man kan även ställa prescale och postscale och det är ju perfekt till detta.
Senast redigerad av Icecap 21 januari 2008, 16:58:25, redigerad totalt 1 gång.
Användarvisningsbild
chrille112
Inlägg: 334
Blev medlem: 25 april 2005, 16:45:24
Ort: Uppsala

Inlägg av chrille112 »

Tack för koden Icecap! Jag ska testa den det första jag gör ikväll.
Hur kom du fram till Rate = 104857,6µs?

Nu när jag jämför klockan så går den 1 min 49 sekunder före. Inte bra, men helt klart mitt bästa resultat hittils :)
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

5MHz delad med 65536 (en 16-bit räknare) = 0,0131072s (65536/5000000) intervall = 13107,2µs mellan varje puls. Du har en prescaler på 8 inkopplat = 13107,2µs * 8 = 104857,6µs mellan varje puls.

Skyller på tidig morgon efter en natt med en snart-2-månaders-tjej om jag har räknat lite fel...
Senast redigerad av Icecap 21 januari 2008, 17:24:36, redigerad totalt 1 gång.
bos
Inlägg: 2314
Blev medlem: 24 februari 2007, 23:29:15
Kontakt:

Inlägg av bos »

sodjan skrev:TMR1L = h'0E', TMR1H = h'0F'. Jag förstår inte vad de menar med "same address" !?
Jag skulle gissa på att T1 är ett 16bit-värde som innehåller TMR1H:TMR1L, men "same address" är äckligt luddigt formulerat isåfall.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Jo, det kan det vara, men det är inget som går att adressera direkt
i processorn. Så på något sätt måste värdet delas upp på "H" resp "L"
och skrivas via flera register accesser. Tyvärr däöljer det bara ytterligare
vad som igentligen händer i koden.
Användarvisningsbild
chrille112
Inlägg: 334
Blev medlem: 25 april 2005, 16:45:24
Ort: Uppsala

Inlägg av chrille112 »

Icecap: Det är något som inte stämmer med din kod. Först så går klockan väldigt snabbt, tippar på att sekunderna går 10 gånger snabbare än vad de borde. Sedan, efter en varierande tid runt 2-5 minuter så börjar klockan gå i vad som verkar vara rätt fart.

Jag kan filma och lägga upp om ni vill se?

Mycket tacksam för din hjälp!
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Flytta då ut 'Sum' till main och nolla den:

Kod: Markera allt

unsigned long Sum; // Must be a big one

void interrupt()
  { // Rate = 104857,6µs
  PIR1.TMR1IF = 0; // Acknowledge interrupt
  Sum += 1048576; // Add the current part
  if(Sum >= 10000000)
    {
    timeSECOND++;
    Sum -= 10000000;
    }
  }

void main()
  {
  Sum = 0; // Make it start from the beginning
  INTCON.GIE = 1; //enable Interrupt
  INTCON.PEIE = 1; //enable interrupt
  T1CON = 0b00110001; // 1/8 prescaler
  PIE1.TMR1IE = 1; // Interrupt bit Timer1
  PIR1.TMR1IF = 0; // clear FLAG
  while(1)
    {
    }
  }
Om 'Sum' startar som 0xFFFFFFFF blir det 429 sekunder ganska snabbt och det är ju 0:07:09... Så det beror nog på att 'Sum' inte starter på 0, RAM'en på en PIC (och alla andra µC jag har jobbat med) är odefinierat vid power-on.
Användarvisningsbild
chrille112
Inlägg: 334
Blev medlem: 25 april 2005, 16:45:24
Ort: Uppsala

Inlägg av chrille112 »

Koden fungerar utmärkt, och vad jag kan se så går den helt rätt nu efter 1½ timme. Tack för all hjälp! :)
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Efter vad jag förstår är detta sätt just det som Marta har förespråkad hur många gånger som helst...
Användarvisningsbild
chrille112
Inlägg: 334
Blev medlem: 25 april 2005, 16:45:24
Ort: Uppsala

Inlägg av chrille112 »

Jag har lagt in lite kod i interrupt som kollar knappars lägen var 100 ms. Behöver jag kompensera för detta i tidskoden? Jag har fått för mig att den inte går lika exakt som innan.

Så här ser interupt-funktionen ut

Kod: Markera allt

  PIR1.TMR1IF = 0; // Acknowledge interrupt
  Sum += 1048576; // Add the current part
  checkButtons();
         
  if(Sum >= 10000000)
  {
         timeSECOND++;
         Sum -= 10000000;
  }
Gör det någon skillnad om jag lägger checkButtons() efter if-satsen istället? Eftersom timern hela tiden är igång så borde det inte spela någon roll, så länge man lägger det efter PIR1.TMR1IF = 0, eller?
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Då du inte återladdar Timern men uteslutande använder interrupten kan du göra vad du vill (om det går snabbt!) i ISR'n.
Skriv svar