Welke denkfout maak ik hier nu:

Ik wil een timer maken met een frequentie van 50 Hz ofwel 20mS bij iedere Timer interrupt.

Ik heb:

PIC 16F628A

PCON.3 = 0 'freq 48.000Hz
T2CON = 0 1110 11 1 'prescale 16, postscale 15
PR2 = 0

De formule is fOSC/4/Pre/Post/(PR+1)

= 48.000/4/16/15/1 Dat zou 50 Hz moeten zijn.

Maar het wordt steevast 60Hz, ook bij wisseling van de PIC.
Een afwijking van 20% lijkt me erg veel.

Wat klopt hier nu niet?

't Is een wat vreemde combinatie... ;)

Ik heb eigenlijk nog nooit iemand de 48kHz oscillator zien gebruiken, wist niet eens dat die bestond... (ook PR2 met '0' laden weet ik niet of dat goed gaat)
Beter postscale op '1' zetten, en PR2 op '14'

Als ik pr2 op 14 zet en post op 1, dan zou het resultaat dus inderdaad

48.000 / 4 / 16 / 1 / 15 = 50 Hz moeten zijn.

Het blijft echter 60Hz.

Wanneer ik de pre en post op 1 zet en pr2 op 0, dan zou je in feite 48.000 / 4 = 12.000 Hz moeten krijgen. Het wordt echter 250 Hz.

Dus dacht ik dan zet ik Pr2 op 4, dan zou je dus 250 / (4+1) = 50 Hz moeten krijgen.

Het blijft echter 250 Hz, m.a.w de PR2 heeft geen effect meer wanneer beide pre- en postscale op 1 staat..

Raar allemaal.

De PIC16F628A kent vwb de interne oscillator alleen maar 48 Khz en 4 Mhz. Anders moet je weer met een kristal gaan werken.

Ik had nog een aantal van die dingen liggen En wilde ik een timer maken die iedere seconde een tik geeft (hoeft niet eens zo nauwkeurig).

Je kunt beter de 4MHz oscillator nemen, die is binnen 1% nauwkeurig.
(de 48kHz is uncalibrated en kan héél erg afwijken (-35% tot +60%... :) )

Ik heb inmiddels de 4Mhz gekozen.
Maar het blijft wel lastig om een puls iedere 1 seconde te krijgen.

Ik heb wat gespeeld met de waarden:

Pre: 16
Post: 4
PR2: 1

Dan kom je theoretisch uit op
4.000.000 / 4 / 16 / 4 / 2 = 7812,5 Hz.

In de praktijk wordt het 7706 Hz.
Dus heb ik maar een tellertje gemaakt die tot 7706 telt.

Dan kom ik aardig in de buurt. Maar helemaal fraai is het nog niet.

Ik heb ooit eens zelf een klok gemaakt die gebaseerd was op deze code van Roman Black
https://www.romanblack.com/one_sec.htm

Ik werk veel met LDmicro en daar hoef ik enkel de getallen voor de cycletime in te geven.
In onderstaande screenshots zie je de waarden (asm) die door LDmicro worden gecompileerd voor een 20mS tijdspanne.
Hoe je dat moet omzetten in een andere taal weet ik niet maar misschien kun je er wel iets van opsteken.

Dan kom ik aardig in de buurt. Maar helemaal fraai is het nog niet.

Tja,

't Is een oude pic, die kun je niet 'fine-tunen' (is maar op +/-1% nauwkeurig), als het toch precies moet neem je een kristal...
Ik zou deze waardes nemen:

pre = 4
post = 10
pr2 = 249

Geeft een 10ms interrupt en dan een counter tot 100 (eventueel +1/-1 voor correctie van de 1% afwijking)

Op 30 november 2022 10:17:48 schreef Arco:
[...]
Tja,

't Is een oude pic, die kun je niet 'fine-tunen' (is maar op +/-1% nauwkeurig), als het toch precies moet neem je een kristal...
Ik zou deze waardes nemen:

pre = 4
post = 10
pr2 = 249

Geeft een 10ms interrupt en dan een counter tot 100 (eventueel +1/-1 voor correctie van de 1% afwijking)

Dit is inderdaad een mooie waarde. Scheelt ook weer een extra tellertje.
:)

Kan allebei met één counter, alleen kan dat nu een byte zijn ipv een word (dat vindt een 8 bitter altijd fijner... ;) )
Beste de PR2 waarde altijd zo hoog mogelijk nemen...


'======================================================================================
Program Test
Dim Cnt As Byte

'========================================================================================
Sub procedure Interrupt() iv 0x0004 ics ICS_AUTO
'========================================================================================
  If TMR2IF_bit = 1 Then
    Inc(Cnt)
    If Cnt >= 100 then
      PortB.0 = Not PortB.0
      Cnt = 0
    End If
    TMR2IF_bit = 0
  End If
End Sub

'========================================================================================
Sub Procedure Init()
'========================================================================================
  TRISA  = 0x00
  TRISB  = 0x00
  PR2    = 249
  T2CON  = %01001101
  TMR2IE_bit = 1
  GIE_bit    = 1
  PEIE_bit   = 1
End Sub

'========================================================================================
main:

'========================================================================================
  Init()
  while true
  wend
End.

Wat grappig, ik had mijn MikroBasic programma vrijwel exact zo.
(Komt ook omdat ik de Arco-leergang heb doorlopen... :) )

Wel nieuw voor mij is dat een PIC liever niet van Words houdt.
Ik had zelfs een variant met een Longword

Stel je wilt 24 uur tellen. 86400 seconden.

Dat kan je doen met integer of Longword. (is ook 4 bytes dacht ik)
Maar het zou dan beter zijn dat in meerdere tellertjes van 1 byte op te delen?

Voor word/longword moet de compiler code genereren om 2 resp 4 bytes 'aan elkaar te lijmen' tot 1 variabele, omdat de controller alleen maar 8 bits kent.
(die weet niet wat een (d)word is)

Als er bij rekenkundige bewerking van byte 0 een carry geeft, moet dat verrekend worden met byte 1, als er daar ook een carry is moet dat verrekend met byte 2, enz...
Een variabele groter als 8 bits is voor een 8 bitter dus een stuk meer werk als een 'native' byte variabele...

Met een 16 bits pic is een word wel default (ik gebruik meestal de 24F serie)

Dank allen voor de suggesties! Het is opgelost. :)

Nog een klein nabrandertje: :)

Ik had een foutje gemaakt in mijn programma:



Dim CntSec As Byte
----
----

If CntSec = 3600 Then
---
---

Dat kan natuurlijk niet, een byte gaat niet verder dan 255.
Wat ik me dan even afvroeg: waarom waarschuwt de compiler hier niet voor?
Die weet immers dat het getal van 3600 niet kan worden afgevraagd.

Tja,

Je vraagt de compiler of 'ie CntSec met 3600 wil vergelijken, en dat doet hij...
Daar zit blijkbaar geen check op, wel op een assign (CntSec = 3600)

Van sommige dingen verwacht de compiler dat je die zelf in de gaten houdt. Een byte kun je ook oneindig blijven optellen of aftrekken.
(na 254,255,... krijg je gewoon een roll-over naar 0, 1, 2,...)

Mijn vermoeden is bevestigd.. :)
Thx

Als je trouwens typecasting gebruikt gaat het wel goed (de compiler gebruikt dan alleen de laagste 8 bits van 3600)


If CntSec = Byte(3600) then...

vergelijkt CntSec met 16, de waarde van het laagste byte... (3600 Mod 256 = 16)