Sida 1 av 2
Oregelbunden hastighet på klocka
Postat: 17 november 2007, 15:41:54
av Frisk
Har som säkert en del av er sett byggt en klocka (mer info
här)
Har nu kört klockan under några dygn, trodde först det var mitt reload-värde till timern som var fel, men verkar mer som ett hårdvarufel.
Klockan började först med att dra sig 30-40 minuter första 2-3 dagarna, sen plötsligt hade den tagit in den tiden på bara någon dag.
Just nu går den 5-10min för fort/dygn, utan att ändrat något med programmeringen.
Klockkristallen sitter så nära pinnarna på picen jag lyckade placera den, och klockkondensatorerna är ytmonterade, sitter mer eller mindre direkt på lödöarna för krisallen.
Vad är troligast är fel? Har jag brännt kondensatorerna vid lödningen, eller har kristallen fått sig en smäll, eller blivit överhettad?
Kan det vara programmeringsfel? men tycker i så fall det borde bli lika mycket fel varje dygn.
Postat: 17 november 2007, 15:45:57
av Icecap
Hur styr ditt program tiden?
Är det med timer-interrupt?
Postat: 17 november 2007, 16:18:16
av Johan.o
Känner igen det, det är livsfarligt (enligt mig) att försöka få till en långtids-stabil klocka
i en mikrodator som kör annat än själva klockan. Själv kodade jag i assembler, och använde
en interrupt rutin som hade prioritet för att sköta tids-räkningen.
Kunde "dra sig" några sekunder per timmen, rätt slumpmässigt.
Det bästa är att köpa eller bygga en liten separat RTC, med bra stabil kristall. Endast då kan man verkligen få det riktigt bra och pålitligt.
Postat: 17 november 2007, 16:44:31
av Frisk
Programmet är skrivet i C,vilket jag antar är en dålig början. kör räkningen via timer-interruppt.
just nu gör jag inte mycket mer än sköter klockan med processorn,men tänkte även lägga in I2C,blir kanske ännu värre då.. Har även planer på lampdimmer,i annan processor,kanske bättre att bygga tiden nollgenomgångarna? eftersom allt kommer vara ihopkopplat via I2C kommer detta förhoppningsvis funka ganska smärtfritt.
Postat: 17 november 2007, 16:57:27
av Icecap
Vad har C med problemet att göra?
HUR kör du timer-interrupten? Lägger du till ett offset på timervärdet? Kanske du ska testa att rensa ut lite i programmet och posta det, det räcker med timer -ISR + initialiseringen av timern.
Jag har programmerat klockor som går kristall-stabilt utan problem via en timer-interrupt så den biten är inget problem.
Postat: 18 november 2007, 15:40:16
av Frisk
Tänkte mer att om man skrev i Assembler så vet man precis vad som händer.
Precis, lägger till ett preload-värde på timern, och räknar upp sekunderna med ett.
Är inte speciellt mycket kod så slänger med hela, hoppas den är hyffsat överskodlig.
Kod: Markera allt
#include <pic18.h>
static int sec = 0, min =0, h = 0;
void main(void){
INTCON = 0b11000000;
INTCON2 = 0b11110000;
INTCON3 = 0b00000000;
PIE1 = 0b00000001;
IPR1 = 0b00000001;
T1CON = 0b10001111;
TRISA = 0b11000000;
TRISB = 0b11000000;
TRISC = 0b00000011;
TRISD = 0b11000000;
TRISE = 0b00000000;
PORTC = 0;//sätter "jord" på MUXen för katoderna, är där för att kunna reglera ljusstyrka med PWM.
while(1){
if (sec == 60){
min++;
sec=0;
}
if (min == 60){
h++;
min = 0;
}
if (h == 24){
h = 0;
}
PORTA = sec;
PORTB = (min %8) <<3;
PORTE = (min/8);
PORTD = ((h%12)*5)+(min/12); //räknar om för 5 lägen/timme
}
}
void interrupt NewSec(void){
TMR1IF = 0;
sec++;
TMR1L = 0b00000001;
TMR1H = 0b01111010;
}
Postat: 18 november 2007, 15:53:33
av sodjan
> Klockkristallen sitter så nära pinnarna på picen jag lyckade placera den,
Är det frågan om en Timer1-osc kristall ?
Hur har du räknat ut de nya TIMERL/TIMERH värderna ?
Normalt gör man ADD till TIMER'n för att slippa räkna på
overhead.
Bäst är att låta timern vara freerunning hela tiden (00-FF eller 0000-FFFF)
så slipper man effekterna vid omladdning av timern. Det kan bli tätare
interrupt, men det är bara att räkna til det blir en sekund (eller vilken
tidbas man nu vill ha). Utan omladdning så blir det mycket enklare att få
timern att gå p åett förväntat sätt.
Postat: 18 november 2007, 16:21:45
av Frisk
Det stämmer bra, Timer1-osc.
Jag räknade först på värderna, och har därefter justerat. Enligt beräkningarna skulle preload vara 8000 hex.
Kör jag timern som 16-bitars och freerunning kommer jag få 2s interruppt, men kanske kan vara idé att istället köra den som 8-bitars...
Blir ju en del extrainterrupt, men då inte klockprocessorn har mycket mer i uppgift än att sköta just klockan spelar det ingen större roll.
Postat: 18 november 2007, 16:49:06
av bearing
Om preload är 8000h borde du kunna OR:a TMR1H med 80h vid interruptet bara. Eller så använder du Comparemodulen med 32768 som period.
Postat: 18 november 2007, 17:59:07
av sodjan
Som sagt, normalmetoden är att *lägga till* värdet, då tas det automatiskt
hänsyn till att timern ha hunnit köra en liten bit sedan interruptet.
Men som sagt, enklast är att låta den bara snurra runt med ett lämpligt
intervall och bara räkna antalet varv.
Postat: 18 november 2007, 18:22:53
av Icecap
Jupp, felet är hittat:
TMR1L = 0b00000001;
TMR1H = 0b01111010;
Big no no!!!
Håller i övrigt med de förra talare.
Postat: 18 november 2007, 18:32:12
av Frisk
Icecap, vad är felet? att jag sätter fasta värden, som övriga påpekat? Ska istället addera lämpligt tal?
Får testa addera ett värde då, se om den går tillräckligt exakt då, fungerar inte får jag testa sodjans förslag med att bara låta timern rulla.
Tack för hjälp och förklaringar om mina fel!
Postat: 18 november 2007, 18:48:20
av Icecap
Det är generellt fel att lägga in fasta tal eller addera, det rätta är att hårdvaran ställs en gång och sedan använder man interrupten till att räkna på. Därför finns det kristaller med "knasiga" värden, för att timrar och deras delningar ska passa med 1/10/100Hz.
Det framgår inte vilken PIC du använder annat än att det troligt blir en PIC18.
Jag har just avslutat ett projekt som helt var timerberoende, jag använde Timer2 på en PIC16F628A och kunde ställa in den till att ge en 100Hz (100,16...) och det räckte för mitt behov, den kan man ställa prescaler, postscaler och delningsgrad på och få nära nog vilken frekvens man vill ha på interrupten.
Om du tar t.ex. ett 3,6864MHz kan du lätt få ut ett "binärt" värde på 100,000Hz, och då är det bara att räkna till 0-99 och vid 100 slå över räknaren till noll och addera 1 till sekunderna.
Postat: 18 november 2007, 18:51:00
av bearing
Skriv bara:
Kod: Markera allt
void interrupt NewSec(void){
TMR1IF = 0;
sec++;
TMR1H |= 0x80;
}
istället. Är väl den elegantaste lösningen.
Postat: 18 november 2007, 19:06:45
av Frisk
Jag använder en klockkristall, 32,758kHz, tyvärr skapar ju denna bara interrupt varannan sekund, därav preloadvärdet.
Kan ju klart underlätta om jag säger vad det är för saker jag kör på ja... är en PIC18F4550.
Får testa bearings förslag, hoppas på att det funkar.