Ik zit hier even vast, waarschijnlijk een denk foutje.
Het gaat over een tijdklok(uren, minuten, seconden) mbv de TMR0.
Nu heb ik PSA op 0, voor de prescaler op de WTD
(denk dat hier de fout zit....)
Verder heb ik van de prescaler alle bits gecleared zodat ik 1 op 1 heb.
Verder tel ik dan iedere interrupt 6 bij de waarde van TMR0 op voor de compensatie. Dan zou dus naar mijn mening na 4000 interrups 1 seconden voorbij zijn.
Nou denk ik dat de fout bij de prescaler zit, maar ik kom er niet uit waar. Moet ik soms wanneer ik deze niet wil gebruiken ook ergens aangeven ofzo?
Wanneer ik de waarde van de prescaler veranderdt telt hij wel, dus dat is het probleem niet.
PS ik weet dat ik beter een occilater met een macht van 2 kan nemen.
Alle tips zijn welkom.
DEVICE 16F628A ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE ;Alle ingangen digitaal
CLEAR ;We gebruiken een 16F628A type
ON_INTERRUPT GOTO LED_UIT
; 76543210
TRISA = %00010000
TRISB = %11111111
SYMBOL T0IE = INTCON.5 ' TMR0 Overflow Interrupt Enable
SYMBOL T0IF = INTCON.2 ' TMR0 Overflow Interrupt Flag
SYMBOL GIE = INTCON.7 ' Global Interrupt Enable
SYMBOL PS0 = OPTION_REG.0 ' Prescaler ratio bit-0
SYMBOL PS1 = OPTION_REG.1 ' Prescaler ratio bit-1
SYMBOL PS2 = OPTION_REG.2 ' Prescaler ratio bit-2
SYMBOL PSA = OPTION_REG.3 ' Prescaler Assignment (1=assigned to WDT 0=assigned to oscillator)
SYMBOL T0CS = OPTION_REG.5 ' Timer0 Clock Source Select (0=Internal clock 1=External PORTA.4)
DIM hulp AS WORD
DIM seconden AS BYTE
DIM minuten AS BYTE
DIM uren AS BYTE
CLEAR
DELAYMS 500
CLS
GIE = 0 ' Disable global interrupts
WHILE GIE = 1 ' Make sure they are off
GIE = 0 ' Continue to clear GIE
WEND
GIE = 0 ' Turn off global interrupts
PSA = 0 ' Assign the prescaler to Interne WDT oscillator
PS0 = 0 ' Set the prescaler
PS1 = 0 ' to increment TMR0
PS2 = 0 ' every 128h instruction cycle
T0CS = 0 ' Assign TMR0 clock to internal source
TMR0 = 0 ' Clear TMR0 initially
T0IE = 1 ' Enable TMR0 overflow interrupt
GIE = 1 ' Enable global interrupts
GOTO MAIN
LED_UIT:
hulp= hulp+1
TMR0 = TMR0 + 6
T0IF=0
CONTEXT RESTORE
MAIN:
hulp=0
seconden=0
minuten=0
uren=0
WHILE 1=1
IF hulp = 4000 THEN
seconden = seconden + 1
hulp=0
ENDIF
IF seconden = 60 THEN
seconden = 0
minuten = minuten + 1
ENDIF
IF minuten = 60 THEN
minuten = 0
uren = uren+1
ENDIF
PRINT AT 1,1, "Tijd: ", DEC2 uren, ":", DEC2 minuten, ":", DEC2 seconden ;Scherm wissen
WEND
END
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Nu heb ik PSA op 0, voor de prescaler op de WTD
(denk dat hier de fout zit....)
PSA=0 = prescaler op timer 0, niet WDT. (staat in je eigen commentaar!)
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Dan is de prescaler aan de WDT gekoppeld, ja.
Prescaler 1:1 voor timer0 bestaat trouwens niet. '000' = prescaler 1:2...
Weet je dat zeker, want in de help van proton staat:
PS2 PS1 PS0 PSA=0 (External crystal OSC) PSA=1 (Internal WDT OSC)
0 0 0 1 : 2 1 : 1
0 0 1 1 : 4 1 : 2
0 1 0 1 : 8 1 : 4
0 1 1 1 : 16 1 : 8
1 0 0 1 : 32 1 : 16
1 0 1 1 : 64 1 : 32
1 1 0 1 : 128 1 : 64
1 1 1 1 : 256 1 : 128
1:2 zou ook niks uitmaken, maar dan moet ik even de waarde van mijn hulp variabele aanpassen.
Ik heb het net getest, maar hij doet het niet.
Zou het kunnen dat deze regel niet mag:
TMR0 = TMR0 + 6
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Weet je dat zeker, want in de help van proton staat:
[...]
Ja,en? Daar staat toch precies wat ik zei?
Wat is trouwens het nut van 'TMR0 = TMR0 + 6'? (Je kunt net zo goed 'TMR0 = 6' gebruiken...
(Misschien toch de datasheet eens een keertje goed doorlezen? Dat bespaart een hoop onnodige problemen....)
OK, dan zie ik dat verkeerd. Ik kijk namelijk in de kolom van PSA=1, daar zie ik toch 1:1 staan.
TMR0 = TMR0 + 6 en niet hetzelfde als TMR0=6 (dacht ik).
De timer gaat toch gewoon door met tellen ook al zit je bij de interrupt? Anders maak je hem toch weer 6 wanneer deze alweer bij bv 30 is?
Alvast bedankt Arco
PS Ik heb het hele stuk van de timer al eerder doorgelezen van de datasheet.
[Bericht gewijzigd door Rupke Flupke op (11%)]
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
TMR0 = TMR0 + 6 en niet hetzelfde als TMR0=6 (dacht ik).
Uit de eerste regels van de datasheet/timer0:
Interrupt on overflow from FFh to 00h
Timer 0 is dus altijd '0' bij een timer0 interrupt.
OK, dan zie ik dat verkeerd. Ik kijk namelijk in de kolom van PSA=1, daar zie ik toch 1:1 staan.
PSA=1 is (Internal WDT OSC), en dus niet timer0...
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Je moet bij
TMR0 = TMR0 + 6heel goed weten wat je doet.
Vaak kan een processor zoiets in in 1 instructie in de hardware doen. De compiler maakt er dan:
registerX=TMR0 ; registerX = registerX + 6; TMR0 = registerX;Met een beetje mazzel, verlies je precies twee clock cycles.
En ook al KAN de processor het in 1 instructie, dan zal er hardware matig iets gebeuren in de geest van:
TMR0 = TMRO + 6 || TMR0 = TMR0 + 1 ;Met "||" bedoel ik "parallel aan". Hopelijk heeft JOU opdracht (De eerste) voorrang. Maar dan nog verlies je 1 clock stapje van je TMR0.
In de praktijk moet je ECHT naar de assembly gaan kijken, of het wel kan werken.
Ik adviseer om dus iets te verzinnen waaarbij dit niet hoeft.
Een optie is mischien om een variabele bij te houden die aangeeft hoeveel je totaal bij TMR0 opgeteld zou willen hebben. Als het meer dan een volledige cyclus beslaat, doe je alsof je twee interrupts hebt gehad en trek je weer een volledige cyclus van de variabele af.
Ok, bedankt. Dat is duidelijk. Ik dacht namelijk dat de timer gewoon door telde bij wanneer deze naar de interrupt gesprongen was. Dus hij blijft gewoon 0 tot CONTECT RESTORE is geweest.
Nogmaals, Bedankt Arco
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Als je de timer met een bepaalde waarde wilt laden, moet je eigenlijk timer1 of 2 gebruiken, die zijn daar geschikt voor...
Turbokeu
Golden Member
I love watching conspiracy theorists use the airtight logic of the argument from incredulity: "Well I don't understand how it works so it can't be real!!!"
Op 3 november 2008 14:16:36 schreef Rob v:
Ik dacht namelijk dat de timer gewoon door telde bij wanneer deze naar de interrupt gesprongen was. Dus hij blijft gewoon 0 tot CONTECT RESTORE is geweest
De timer BLIJFT gewoon doorlopen na de interrupt (bij timer value=0), anders had het geen zin time critical routines te schrijven op basis van een timerinterrupt...
Je kan wel de beginwaarde van de timer aanpassen om de tijd tussen 2 interrupts te verkorten, maar éénmaal gestart (via het desbetreffende bit in het desbetreffende register) stopt deze nooit meer (of je moet hem bewust stoppen via vermeld bit/register).
Timer blijft idd gewoon doortellen, je moet alleen niet vergeten om de flag te clearen. Anders krijg je geen interruptjes meer.
Arco, Als je de prescaler op de WDT zet dan heb je 1:1 voor de timer. Ik denk dat rob dat bedoelt. Als je de presc op de timer zet heb je idd minimaal 1:2.
Oke, Ik heb vanalles over dat verhaal doorgelezen. Er is dus 1 prescaler, en jij moet kiezen of je hem voor je WDT of timer wilt. Dus als je hem op de de WDT zet gebruik je de hele prescaler niet, vandaar de 1:1?
Jap. De prescaler zit aan de WDT en kan dus niet door de timer gebruikt worden. De prescaler is er dus niet, dus 1:1.
sjors007
...
ik loop ook vast bij dit gedeelte. de seconden gaan te snel. Weet jij nou het gaat of niet Rupke Flupke?;)
MVG Sjors van den Berg
hadv
Just find out what you like and let it kill you
Op 3 november 2008 16:37:16 schreef Bas Smit:
Timer blijft idd gewoon doortellen, je moet alleen niet vergeten om de flag te clearen. Anders krijg je geen interruptjes meer.
En, zoals in de help van Proton staat, eerst te testen of de interrupt wel door Timer0 werd veroorzaakt (TMR0IF = 1).
Inderdaad het bovenstaande proberen. Als je dan geen interrupt krijgt post dan even de code. Dan kijk ik wel even. Gebruik je een kristal of de interne oscillator?
sjors007
...
nu nog interne van 4MHz ik heb alles al voor elkaar ik gebruikt prescaler 1:16 en laat dan een tellertje lopen tot 250 en dan tel ik 1 seconden alleen op de minuten loop ik ong 1,5 mis ik denk dat dat door de interne oscilator komt, straks even 20Mhz kristal bestellen denk dat het dan beter gaat;)
MVG Sjors
sjors007
...
ik gebruik nu nog de 4MHz oscilator dus ik heb de prescaler even op 1:16 gezet straks wanneer ik de 20MHz kristal heb moet ie op een ander..!
mijn instellingen zijn nu:
4MHz = 1.000.000 instructie cycles per seconde
mijn TMRO = 6
dan word het dus 256 - 6 = 250
1.000.000 / 250 = 4000 interrups per seconden
4000 / 16 = 250
dan maak ik een tellertje tot 250
dan zeg ik
als de teller bij 250 dan
seconden = seconden + 1
dan moet het volgens mij aardig kloppen
alleen hij telt nu even te snel dan komt denk ik door de interne oscilator of niet?? straks wanneer ik de 20 MHZ kristal heb moet het wel beter worden
hoeveel cycles zijn 20MHz eigenlijk?
4MHz = 1.000.000
MVG Sjors
Oké dan, op een 20Mhz kristal loopt die op 5Mhz.
Dan kun je beter een 4.096Mhz kristal nemen. Dan hoef je de timer niet met een waarde te laden.
Met de interne oscillator heb je altijd onnauwkeurigheden.
Wanneer je een nauwkeurige klok wil maken:
1) Een extern kristal (of TCXO) gebruiken, de interne RC oscillator is daar niet nauwkeurig genoeg voor.
2) Wanneer je niet tot 256 telt (of 65k) dan moet voor het opnieuw laden altijd een ADD instructie gebruikt worden omdate de interrupt latency niet constant is, je kan er dus 1 tick naastzitten (of meer wanneer je ook nog andere interrupts gebruikt).
3) Nooit de prescaler gebruiken, die wordt namelijk gereset bij een timer write aktie.
De laatste twee problemen kan je voorkomen door TMR2 te gebruiken, die is instelbaar en heeft een pre- en post- scaler waardoor het makkelijk is om bijvoorbeeld exact 100 interrupts per seconde te krijgen.
niet vergeten, als je aan je TMR0 register rommelt in je code (6 erbij optellen, om ipv. 256 cycles slechts 250 cycles te hebben tot de volgende interrupt) de Prescaler netjes op nul gezet wordt. stel dat de prescaler dus niet op nul stond (bij een 1:16 prescaler is die kans krap 94%) wordt die weer terug op nul gezet. gevolg is dat je dus een aantal klokcycli 'kwijtraakt'