Sida 1 av 1
Realtids klocka?
Postat: 25 augusti 2006, 16:36:03
av SweLogan
Hej, undrar hur man ska bygga en klocka som håller tiden. Byggde en idag.
typ sek = sek + 1 osv sedan hade jag en pause 1000. Men efter några minuter så började klockan gå fel med någon sek. Jag har mina aningar varför, om porgrammet tar 1 hundradel så måste man ju ha en pause på 999. Men i vilket fall hur gör man detta smidigast?
Postat: 25 augusti 2006, 16:48:11
av Icecap
Man börjar med en stabil oscillator. Dallas har DS32KHZ om man vill vara noga men mindre kan göra det.
Sen ställer man en timer till att ge avbrott med lämpligt intervall, baserat på den klocka.
Dessa avbrott lyftar egentligen bara en flagga och en huvudrutin räknar upp den egentliga räkningen. Jag hade gjort så att timer-interrupten ville inkrementa en variabel och när den variabel överstiger ett visst värde kommer main-rutinen att reagerar på det, räkna upp tiden och subtrahera det "viss värde" från variablen.
Kod: Markera allt
Pseudokod:
Flagga: 1 byte
Timme: 1 byte
Minut: 1 byte
Sekund: 1 byte
#define Value 10
interrupt-rutin:
Flagga = Flagga + 1;
return-from-interrupt
main:
Kör Initialiserings-rutin;
Loop-Evigt:
if(Flagga >= Value)
{
Flagga = Flagga - Value;
Sekund = Sekund + 1;
if(Sekund > 59)
{
Sekund = 0;
Minut = Minut + 1;
if(Minut > 59)
{
Minut = 0;
Hour = Hour + 1:
if(Hour > 23) Hour = 0;
}
}
}
goto Loop-Evigt
Initialiserings-rutin:
Ställ timer till att ge 'Value' interrupts/sek
Såklart kan man även koppla in en RTC-krets men den biten kan du nog själv klura ut.
Postat: 25 augusti 2006, 22:59:24
av sodjan
> pause 1000...
Det fungerar inte i MPASM, så du kanska ska tala om vad det är du kör i.
Vad betyder "hålla tiden" för dig ?
Sen, som Icecap redan har förklarat, så fungerar det aldrig att göra så där...
*Timers* är vad du ska läsa på om i databladet.
Det är normalt inget större problem att få en "klocka" som har i alla fall
lika stort "fel" som kristallen (eller hur nu processorn körs).
Postat: 26 augusti 2006, 02:54:14
av Chribbe76
Här är ett exempel på en sekund-räknare som använder 4Mhz kristallen som bas utan att använda interrupt.
Otestad Pseudokod skriven av en trött Chribbe:
Kod: Markera allt
Dim TimerTmp as Word
Dim TimerOld as Word
Dim TimerDiff as Word
Dim TimerTot as 24bitars signed
Dim TidBasen as 24bitars signed eller unsigned (kan vara en konstant)
;TMR1 har 16bitar och ska initieras för att räkna cycler
TidBasen=1000000 (antal steg som TMR1 räknar per sekund)
Denna rutin ska anropas så ofta som möjligt, minst 30gånger/sekund.
TimerTmp=TMR1
TimerDiff=TimerTmp-TimerOld ;denna beräkning måste kunna "slå runt"
TimerTot=TimerTot-TimerDiff
TimerOld=TimerTmp
if TimerTot<0 then
TimerTot=TimerTot+TidBasen
Sekund=Sekund+1
endif
Om man inte kan ha 24-bitars variabler går det bra med 32bitars.
Har man inte tillgång till en 16-bitars timer går det bra med 8bitars timer och valfri prescaler men programmeringen blir inte lika enkel.
Om man inte kan använda 24/32bitars tal i ditt programspråk så är det dags att byta språk.
Postat: 26 augusti 2006, 13:07:59
av bengt-re
Assamber använder 8-bitar och det räcker för det mesta. Det går att göra allt ändå...
Och varför inte inte använda timerinterupt? I 80% av alla program så kan man göra det utan problem. Och i de fall man inte kan det på grund av att man vekligen behöver us timing i sin huvudloop och man ändå behöver en klocka så är det väl lika bra att använda en RTC? Du kan bygga en egen RTC med en PIC10f629 - kör den med INTOSC för programmet och sätt dit en klockkristall (32kHz) som osc till TIMER1. Skriv sedan en egen RTC i programmet. Lite onödigt eftersom det finns billiga färdiga RTC, men en 12F629 är också billlig och ger dig friheten att designa din rtc som du vill ha den.
Postat: 26 augusti 2006, 15:00:26
av sodjan
Chribbes kod skulle jag inte vilja ha i en större applikation.
Hur ska man garantera att det anropas "minst 30 gånger/sekund"
på ett snyggt/praktiskt sätt utan att använda timer-interrupt ?
Och med 24/32 bitars signed beräkningar blir det lite onödigt
mycket beräkningar "minst 30 gånger/sekund". Dessutom håller
den bara reda på hela sekunder, min/tim/osv beräkningen tillkommer
utöver koden i exemplet Normalt har man 8-bitars register som
håller reda på sek/min/timmar/o.s.v och justerar alla register i RTC-
rutinen.
Men, så snart man kommer upp på datumhantering så är nog en
separat RTC krets att föredra där men får hantering av t.ex veckodagar,
månadernas längd och skottår "på köpet" så att säga...
Postat: 26 augusti 2006, 15:14:43
av Chribbe76
Vad du vill bryr iaf inte jag mig om.
Alla mina projekt har alltid haft en Mainloop som sysslar med lite av varje och har aldrig varit långsammare än 100 varv/sekund.
Jag använder interrupt till det som är absolut tidskritiskt och vill inte ha fler interruptkällor än nödvändigt för då fördröjer man viktiga processer.
Visst ser koden lite klumpig ut men i assembler(om man modifierar metoden lite) blir det riktigt bra.
Jag läser bara höga delen av TMR1 så låga delen agerar bara prescaler.
Otestad kod ihopsläng på några minuter.
Kod: Markera allt
;TimerTotL,TimerTotH,TimerTotU är ett 24bitars tal
;TidBasenL,TidBasenH,TidBasenU är en 24bitars konstant
movf TMR1H,w
movwf TimerTmp
movf TimerOld,w
subwf TimerTmp,w
movwf TimerDiff
movf TimerTmp,w
movwf TimerOld
movf TimerDiff,w
subwf TimerTotH
btfss STATUS,C
decf TimerTotU
btfss TimerTotU,7
goto InteMinus
movf TidBasenL,w
addwf TimerTotL
movf TidBasenH,w
btfsc STATUS,C
incfsz TidBasenH,w
addwf TimerTotH
movf TidBasenU,w
btfsc STATUS,C
incfsz TidBasenU,w
addwf TimerTotU
incf Sekund
InteMinus:
Postat: 27 augusti 2006, 15:16:33
av sodjan
> Jag använder interrupt till det som är absolut tidskritiskt
OK, det är ett sätt att se på det.
Andra använder interrupt som ett verktyg för att få välstrukturerad kod
som är lätt att underhålla. Man slipper till stor del snårig kod i main.
D.v.s att man använder interrupt till allt där det *går* att använda
interrupt för att t.ex slippa pollning eller liknande i main.
> ...inte ha fler interruptkällor än nödvändigt för då fördröjer man viktiga processer.
Om man har några "viktiga processer" som inte får avbrytas så är det
enkelt att tillfälligt stänga av interrupt.
Olika designfilosofier bara...

Postat: 27 augusti 2006, 16:01:10
av Chribbe76
Jag skulle kunna sluta här men jag vill ändå säga......
Jag tycker inte att några call (där varje rutin pollar om vad som ska hända) i main är snårig kod.
Det är lika snårigt med en interrupt-rutin som måste göra många tester för att styra programmet till rätt ställe.
"Om man har några "viktiga processer" som inte får avbrytas så är det
enkelt att tillfälligt stänga av interrupt. "
Jag menar att viktiga interrupt kan stå väntande för att ett mindre viktigt interrupt har "lagt beslag på execveringen", det är svårt att lösa genom att stänga av interrupt.
Finns den någon annan designfilosofi än maximal prestanda?!

Postat: 27 augusti 2006, 16:19:47
av sodjan
> Jag skulle kunna sluta här
Detsamma, men...
> Finns den någon annan designfilosofi än maximal prestanda?!
*Rätt* prestanda kanske ?
Eller *tillräcklig* prestanda ?
Och "prestanda" är sällan den *enda* designparametern...