Beginners mini-cursus (deel 3)

Het vooraf opgeven (definiëren) van in- en uitgangen

Tot nu toe hebben we steeds de uitgangen aangestuurd met HIGH, LOW en TOGGLE.
Als je een PIC opstart staan alle poorten standaard als ingang ingesteld.
Door een poort (PORT) bijvoorbeeld een LED te laten aansturen met HIGH, LOW of TOGGLE, dan zorgt de PIC Basic compiler er zelf voor dat de betreffende poort wordt ingesteld als uitgang.
HIGH, LOW en TOGGLE werken lekker makkelijk voor beginners, je hoeft je niet druk te maken of de poort al is ingesteld als in- of uitgang, het gebeurt automatisch.

Toch zitten er nadelen aan het gebruik van deze 3 commando's.
Iedere keer als je in je programma weer een HIGH, LOW of TOGGLE commando plaatst, wordt de poort steeds weer omgezet naar uitgang, ook als deze al eerder als uitgang was ingesteld.
Dit kost allemaal tijd en geheugen van de PIC, je programma wordt er trager door en een PIC heeft maar een beperkt aantal geheugenplaatsen, dus daar moet zuinig mee worden omgesprongen.

We gaan het vanaf nu anders doen en gebruiken HIGH, LOW en TOGGLE niet meer.
Als je iets wilt bouwen weet je immers van tevoren al wat elk poortje gaat doen, zoals in ons voorbeeld schema.
Hier weet je al van tevoren dat PORTB.0, PORTB.1 en PORTB.2 ingangen zijn en PORTA.0, PORTA.1 en PORTA.2 uitgangen.
Ergens bovenin je programma kun je dit zelf eenmalig opgeven met de instructie TRIS.
TRIS komt van TRI-State (3-state), een poort kan in 3 toestanden verkeren, namelijk als uitgang hoog (= ON, +5V) óf laag (= OFF, 0V) óf zwevend (= hoog-ohmig), als ingang dus.

PORTA instellen gebeurt met TRISA en voor PORTB is dat TRISB.
Als het een ingang moet zijn geef je een 1 op en als het een uitgang moet zijn een 0.
(Ezelsbruggetje: 1 voor 1nput en 0 voor 0utput.)
In een programma schrijf je dat zo:

;        76543210           <<<Een hulpregeltje
TRISA = %11111000             ;PORTA.2, PORTA.1 en PORTA.0 zijn nu uitgangen                
TRISB = %11111111             ;Alle 8 poorten van PORTB zijn ingangen

Zoals je ziet staan van PORTA de eerste drie poorten (A.0, A.1 en A.2) als uitgang ingesteld (de laatste drie nullen) en van PORTB zijn alle 8 poorten als ingang ingesteld (allemaal enen).
Het procent tekentje (%) geeft aan dat je het binair (in bits) opgeeft.
Stel dat je PORTA.7 en PORTB.6 ook als uitgangen wilt instellen dan wijzig je dit als volgt:

;        76543210           <<<Een hulpregeltje
TRISA = %01111000             ;PORTA.7, PORTA.2, PORTA.1 en PORTA.0 zijn nu uitgangen       
TRISB = %10111111             ;Van PORTB is alleen PORTB.6 uitgang, de rest ingang

De TRIS instructie plaats je ergens bovenin je programma (zie zodadelijk in een voorbeeldprogramma).
Maar voordat je met TRIS een poort omschakelt als uitgang, moet je eerst instellen of deze dan een hoog (+5V) of een laag (0V) niveau heeft.
Als je dat niet doet dan start de PIC met een onbekend niveau als uitgang.
De ene keer kan bij opstarten van de PIC de poort hoog zijn en een volgende keer bij opstarten laag.
Om er voor te zorgen dat de PIC altijd opstart met de poorten op een vooraf ingesteld niveau (meestal wil de gebruiker bij opstart alle poorten laag hebben) moet eerst het poortregister ingesteld worden, en dan pas de poort van ingang naar uitgang worden omgeschakeld.
(Zoals bovenaan dit hoofdstuk is vermeld start een PIC altijd op met al zijn poorten als ingang).

Dat gaat zo:

;        76543210
PORTA = %00000000 ;Alle niveaus van PORTA eerst laag maken
PORTB = %00000100 ;Alle niveaus van PORTB laag, behalve PORTB.2, deze is als voorbeeld hoog 
TRISA = %11100001 ;PORTA.4, A.3, A.2 en A.1 omschakelen als uitgang, de rest blijft ingang 
TRISB = %00000000 ;Alle PORTB poorten omschakelen als uitgang

Als het andersom staat (eerst TRIS en dan PORT), is er de kans dat er heel even een superkort pulsje op de uitgang komt, omdat dan eerst naar uitgang wordt omgeschakeld en dan pas de poort laag wordt gemaakt.

In dit voorbeeld worden eerst de poortregisters van alle poorten op 0 (= laag) gezet, behalve PORTB.2, die wordt hier hoog als bij TRISB de poort als uitgang wordt omgezet.
Nadat de niveaus van de poorten goed zijn gezet (met PORTA = %00000000 en PORTB = %00000100, kan met TRIS worden ingesteld welke poorten uitgangen moeten worden en welke ingangen moeten blijven.
In het voorbeeld worden PORTA.4, A.3, A.2 en A.1 uitgang (de rest blijft dus ingang) en van PORTB worden hier alle poorten omgeschakeld als uitgang.

Het opstarten met willekeurige niveau (1 of 0, hoog of laag) komt ook voor bij variabelen, maar dit hebben we al opgelost door in elk programma steeds eerst alle variabelen op 0 te zetten (= resetten) met CLEAR.


Onthoudt goed dat niet alle poorten altijd hetzelfde zijn.
Op een PIC16F628A bijvoorbeeld is PORTA.4 een open drain uitgang, die kun je wel laag maken, maar niet hoog en PORTA.5 kun je zelfs helemaal niet als uitgang instellen, maar alleen als ingang gebruiken.
En als je een kristal gebruikt, dan kunnen PORTA.6 en A.7 ook niet gebruikt worden omdat daar dan het kristal aan zit.
Het is daarom belangrijk dat je altijd de datasheet van het PIC type waarmee je gaat werken deels doorleest, met name de specificaties van de poorten, de datasheet barst van de informatie hierover.
Datasheets van PIC's kun je downloaden vanaf de site van Microchip.

Ok, maar nu?
Nu staan de poorten wel juist ingesteld als in- of uitgang, hoe zet je nu een uitgang aan of uit?
Dat gaat eenvoudig.

Om bijvoorbeeld PORTA.0 aan te zetten (hoog maken) schrijf je: PORTA.0 = 1 en om hem uit te zetten schrijf je PORTA.0 = 0.
Maar we hebben geleerd eerst de dingen allemaal met SYMBOL een naam te geven, namelijk:

SYMBOL LED1 = PORTA.0         ;In plaats van PORTA.0 kan ook het woordje 'LED1' er staan
SYMBOL OFF  = 0               ;In plaats van 0 kun je nu ook het woordje 'OFF' er neerzetten 
SYMBOL ON   = 1               ;In plaats van 1 kun je nu ook het woordje 'ON' er neerzetten

Nu wordt het al duidelijker, je schrijft nu gewoon LED1 = ON of LED1 = OFF.

Tijd voor wat praktijk oefening:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

SYMBOL AAN  = 0               ;Geinverteerd AAN
SYMBOL OFF  = 0               ;UIT
SYMBOL ON   = 1               ;AAN
SYMBOL UIT  = 1               ;Geinverteerd UIT

SYMBOL LED1 = PORTA.0         ;Poort A.0 heeft nu de naam LED1
SYMBOL LED2 = PORTA.1         ;Poort A.1 heeft nu de naam LED2
SYMBOL S1   = PORTB.0         ;Poort B.0 heeft nu de naam S1
SYMBOL S2   = PORTB.1         ;Poort B.1 heeft nu de naam S2
SYMBOL S3   = PORTB.2         ;Poort B.2 heeft nu de naam S3

;        76543210
PORTA = %00000000             ;Alle PORTA poorten laag
TRISA = %11111100             ;Alleen PORTA.0 en A.1 als uitgang
TRISB = %11111111             ;Deze regel mag eventueel weggelaten worden 

PORTB_PULLUPS ON              ;On-chip pull-up weerstanden actief
CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  IF S1 = AAN THEN
    LED1 = ON                 ;Met S1 zet je LED1 aan
    LED2 = ON                 ;Met S1 zet je ook LED2 aan
  ENDIF
  
  IF S2 = AAN THEN LED1 = OFF ;Met S2 zet je LED1 uit
  IF S3 = AAN THEN LED2 = OFF ;Met S3 zet je LED2 uit
WEND

END

De REM-regel '76543210' zet je recht boven de binaire getallen van TRISA en TRISB als hulpje.
Zo kun je makkelijker zien welke poort je op 0 of 1 zet.

Eerst worden van PORTA alle poortregisters op 0 gezet, zodat je zeker weet dat deze poorten laag zijn, als deze poorten meteen daarna door TRIS als uitgang worden omgeschakeld.
PORTB = %00000000 zie je hier echter niet staan, omdat in dit voorbeeldprogramma, geen enkele poort van PORTB een uitgang zal worden.
Het heeft hier dus niet veel nut om de 8 bits van het poortregister van PORTB op 0 te zetten.

Zoals gezegd start een PIC altijd op met alle poorten als ingang.
Omdat alle poorten van PORTB hier ingang zijn (allemaal enen 11111111), kan deze TRISB regel eventueel worden weggelaten, maar het is netter om het erbij te zetten voor de duidelijkheid.

Nou, de werking van dit kleine programma moet nu toch duidelijk zijn.
Een lage puls (0V) op S1 (PORTB.0 dus) doet LED1 en LED2 oplichten.
Met een lage puls op PORTB.1 is LED1 uit te zetten en PORTB.2 zet LED2 uit.
Let wel, dit is maar een eenvoudig voorbeeld, het programma is nog niet beveiligd als alle knoppen tegelijk worden ingedrukt.
Als je dat doet gaan de LED's gedimd branden, omdat ze dan heel snel na elkaar aan en uit worden gezet.

Nog even een opmerking over waarom ON hier als vet (bold) wordt afgebeeld, dit komt door de editor en is geen fout (de editor is waar je je programma in schrijft, een soort tekstverwerker dus).
Er zijn namelijk instructies die ON als keyword hebben, zoals ON x GOTO en ON INTERRUPT, hierdoor wordt een losse 'ON' ook vet afgebeeld.
 

Toggle
Oke, aan en uitzetten is wel duidelijk nu, maar hoe kun je nu iets laten togglen als TOGGLE niet meer gebruikt gaat worden?

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

SYMBOL AAN  = 0               ;Geinverteerd AAN
SYMBOL OFF  = 0               ;UIT
SYMBOL ON   = 1               ;AAN
SYMBOL UIT  = 1               ;Geinverteerd UIT

SYMBOL LED  = PORTA.0         ;Poort A.0 heeft nu de naam LED
SYMBOL S1   = PORTB.0         ;Poort B.0 heeft nu de naam S1

;        76543210
PORTA = %00000000             ;PIC opstarten met alle PORTA poorten laag
TRISA = %11111110             ;PORTA.0 is uitgang (voor de LED)
TRISB = %11111111             ;Deze regel mag eventueel weggelaten worden

PORTB_PULLUPS ON              ;On-chip pull-up weerstanden actief
CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  IF S1 = AAN THEN
    LED = LED ^ 1             ;Als LED aan was dan uitzetten anders aanzetten
    DELAYMS 25                ;Anti contactdender bij het indrukken van de toets 
    WHILE S1 = AAN : WEND     ;Wacht tot S1 wordt losgelaten
    DELAYMS 25                ;Anti contactdender bij het loslaten van de toets
  ENDIF
WEND

END

Met TRISA wordt PORTA.0 als uitgang gedefinieerd om de LED aan te kunnen sturen, de overige poorten blijven dus ingang.
Hoe kun je nu zonder TOGGLE toch een LED aan en uitzetten met een druk op de knop?
Dat kan met bitwise XOR.
 

Eerst even wat uitleggen:
In de mini-cursus deel 2 hebben we de instructie XOR behandeld.
Dat is wat anders dan de bitwise XOR ( ^ ).
Er zijn 2 soorten AND, OR en XOR, namelijk de relationele en de bewerkende (operationele).

De instructies van mini-cursus deel 2, AND, OR en XOR zijn relationele instructies, die bekijken of aan alle condities is voldaan (bekijken of allen waar (TRUE) zijn) en voeren dan pas de bewerking(en) uit.
Een voorbeeld met de relationele instructie AND:
"IF S1 = AAN AND S2 = AAN THEN"
Hier wordt bekeken of S1 aan is en of S2 aan is.
Zoja, dan zijn beide condities waar en worden de bijbehorende instructies (die na THEN komen dus) uitgevoerd.
Bij AND moeten ze dus allebei TRUE (= waar) zijn, wil de regel uitgevoerd worden.
Bij OR moet minimaal 1 van de condities waar zijn en bij XOR mag er maar 1 conditie waar zijn.
Dat was dus in mini-cursus deel 2.

Maar nu gebruiken we de (rekenkundige) operanden, aangeduid met tekens.
Voor AND is dat '&', voor OR is dat '|' (meestal een langwerpige dubbelepunt op het toetsenbord) en voor XOR is dat het dakje '^'.

Bitwise AND
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
Bitwise OR
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
Bitwise XOR
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0


Terug naar de LED.
Om een LED aan en uit te kunnen zetten met 1 drukknop gebruiken we de bitwise XOR instructie, aangeduid met het dakje( ^ ).
Vergeleken met de 3e tabel hierboven, die van de bitwise XOR, kun je al iets na gaan wat er gebeurt.
In het bovenstaande programmavoorbeeld staat geschreven:

LED1 = LED1 ^ 1

Als de LED uit is dan staat er eigenlijk:   LED = 0 ^ 1.
Kijken we in de bitwise XOR tabel dan zien we bij 0 ^ 1 dat de uitkomst 1 is, dus LED aanzetten (ON = 1).
Als de LED aan is dan staat er eigenlijk: LED = 1 ^ 1.
Kijken we in de bitwise XOR tabel dan zien we bij 1 ^ 1 dat de uitkomst 0 is, dus LED uitzetten (OFF = 0).

Pfff, wat ingewikkeld allemaal, maar je hoeft dit ook allemaal niet meteen te onthouden, dat komt vanzelf in de loop van de tijd wel.
Zolang je maar toggled met het simpele regeltje LED = LED ^ 1.
Het lijkt omslachtiger dan het TOGGLE commando, maar later als je verder bent zul je merken dat TOGGLE toch niet zo fijn is dan gedacht.

Dan nog even de rest van het programma doornemen.

WHILE 1 = 1                   ;Oneindige lus
  IF S1 = AAN THEN
    LED1 = LED1 ^ 1           ;Als LED1 aan was dan uitzetten anders aanzetten 
    DELAYMS 25                ;Anti contactdender bij het indrukken van de toets 
    WHILE S1 = AAN : WEND     ;Wacht tot S1 wordt losgelaten
    DELAYMS 25                ;Anti contactdender bij het loslaten van de toets
  ENDIF
WEND

WHILE S1 = AAN : WEND
Het programma blijft in dit (lege) WHILE-WEND lusje totdat de schakelaar wordt losgelaten.
Zou je deze regel weglaten (probeer het maar eens) dan wordt de LED constant (heel snel) aan en uit gezet omdat het programma continu in die andere lus (WHILE 1=1) rondloopt.

Een dubbele punt kun je gebruiken om meerdere instructies op 1 regel te zetten.
Normaal moet je dit nooit doen want dat gaat ten koste van het overzicht.
Maar een leeg WHILE-WEND wachtlusje op 1 regel, zoals hier, bevordert juist het overzicht.
*Attentie, de dubbele punt werkt niet voor alle commando's in de PIC-Basic LITE (demo) versie.

 
DELAYMS 25 tegen contactdender
Vroeger werden schakelaars altijd voorzien van kleine condensatoren over de ingangen ter voorkoming van contactdender.
Maar met de komst van microcontrollers zoals de PIC kan dit softwarematig worden opgelost en kunnen die condensatoren vervallen.
Als een schakelaar wordt ingedrukt "stuiteren" de contacten heel even.
Door even te wachten weet je zeker dat de contacten goed op elkaar zitten.
En als een schakelaar wordt losgelaten wordt er heel even gewacht zodat de contacten van de schakelaar echt goed los van elkaar zijn.
Je zou de DELAYMS regeltjes weg kunnen laten en in plaats daarvan een kleine condensator over de ingang kunnen zetten, maar waarom zou je dat doen als het ook softwarematig kan, het spaart je printruimte en een condensator uit.
De tijd is met 25 milliseconden behoorlijk ruim, hoogst waarschijnlijk is 1 milliseconde ook al voldoende (DELAYMS 1)
Programmeer de PIC maar eens zonder de instructie DELAYMS 25, dan zul je zien dat hij soms (niet altijd!) de LED bijvoorbeeld uitzet als de schakelaar wordt ingedrukt, maar weer aan gaat als je de schakelaar loslaat, DELAYMS 25 voorkomt dat hier.
 

Conclusies:

HIGH, LOW en TOGGLE zijn wel handig voor de PIC-Basic LITE (demo) versie, omdat die een limiet heeft van maximaal 50 Basic instructie regels en je met deze 3 commando's gelijk de poort goed zet.
Maar bij de volledige versie kun je beter de poorten eerst definiëren, voordat je de uitgangen aanstuurt.
De geschreven Basic programma code is korter, maar de van daaruit gegenereerde code, die uiteindelijk in de PIC komt, is langer, omdat steeds weer opnieuw de uitgang wordt gedefinieerd, ook al is de betreffende poort al eerder als uitgang gedefinieerd.
In de volgende delen van deze mini-cursus worden HIGH, LOW en TOGGLE dan ook niet meer gebruikt.

 


Het kristal

Sommigen zullen zich afvragen hoe het kan dat de PIC zonder kristal werkt, een microcontroller heeft namelijk net als een microprocessor uit een PC altijd een klokfrequentie (van een oscillator) nodig.

Dat zit zo:
Vele PIC controllers hebben een ingebouwde RC oscillator die je kunt gebruiken als de nauwkeurigheid niet zo'n grote rol speelt.
Echt nauwkeurig zijn deze ingebouwde oscillatoren niet, temperatuur en voedingsspanning hebben relatief grote invloed op de snelheid ervan, dus als je bijvoorbeeld een seriële verbinding wilt opzetten met de buitenwereld, dan moet je haast wel een externe oscillator, zoals een kristal, gebruiken want die is veel nauwkeuriger en veel minder gevoelig voor o.a. temperatuur.
Maar als het alleen om het besturen van bijvoorbeeld LED's, LCD's en motoren gaat is de ingebouwde RC oscillator nauwkeurig genoeg en je krijgt er 2 poorten extra bij die anders voor het kristal nodig waren (op de PIC16F628A zijn dat PORTA.6 en A.7, zie schemaatje).

Ook als je sneller wilt zul je een kristal moeten nemen want de interne oscillator van bijvoorbeeld de PIC16F628A heeft een vaste frequentie (= fixed frequency) van ongeveer 4MHz.
Er bestaan ook PIC types waarvan je de snelheid van de interne oscillator door middel van de (PIC Basic) software in kunt stellen.

In deze mini-cursus werken we meestal met de interne oscillator.
Om toch even te laten zien wat je moet doen om de PIC op een kristal te laten werken in PIC Basic even een voorbeeld:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF, HS_OSC ;INTRC_OSC_NOCLKOUT verwijderd 
ALL_DIGITAL TRUE              ;Alle ingangen digitaal
XTAL 20                       ;Kristal van 20MHz

SYMBOL KnipperTijd = 1000     ;Om de 1000 milliseconden (= 1 seconde) LED knipperen

SYMBOL LED = PORTA.2          ;Poort A.2 heeft nu de naam LED

;        76543210
PORTA = %00000000             ;PIC opstarten met alle PORTA poorten laag
TRISA = %11111011             ;Maak PORTA.2 uitgang voor LED aansturing


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  LED = LED ^ 1               ;Toggle de LED
  DELAYMS KnipperTijd         ;De LED knippert de opgegeven tijd
WEND

END

Er zijn bovenin het programma 3 dingen aangepast.
Ten eerste is INTRC_OSC_NOCLKOUT verwijderd uit de CONFIG, zodat de PIC niet overschakelt op zijn interne oscillator.
Daar is nu bij gekomen HS_OSC (= High Speed Oscillator).
In de CONFIG zet je HS_OSC als je een kristal aansluit dat sneller is dan 4MHz.
Als je dat niet invult, gaat de PIC Basic compiler er vanuit dat je een kristal van 4MHz (of lager) hebt aangesloten (XT_OSC (= Externe oscillator)).
En ten derde moet je nog opgeven wélk kristal je op de PIC hebt aangesloten.
Dat doe je met het keyword XTAL met daarachter de frequentie in MHz van het kristal, in bovenstaand voorbeeld dus 20MHz.
Als je XTAL weglaat in je programma, gaat de PIC Basic compiler er vanuit dat je kristal een 4MHz exemplaar is.

De PIC kan niet controleren of je ook echt een kristal van 20MHz hebt aangesloten.
Als je 20MHz opgeeft in het programma, maar een 10MHz kristal op de PIC aansluit, dan kloppen diverse tijden niet meer.
DELAYMS 2000 duurt dan geen 2 seconden, maar duurt 4 seconden, omdat 10MHz de helft langzamer is dan de opgegeven 20MHz.
Ook diverse verbindingen met de buitenwereld werken nu niet goed omdat bijvoorbeeld een opgegeven 1200 Baud niet wordt verzonden met 1200 bits per seconde, maar met maar 600 bits per seconde.
Dus de opgegeven kristalwaarde ook daadwerkelijk aansluiten op de PIC.

Als je het kristal aansluit op PORTA.6 en A.7, denk dan ook aan de 2 condensatoren van 22pF die aan massa (0V) moeten worden gelegd.
Plaats deze zo dicht mogelijk bij het kristal, het kristal zelf ook zo dicht mogelijk bij de PIC plaatsen.
Meer hierover vindt je in de datasheets van de PIC's.
*Attentie: Bedenk dat in de PIC-Basic LITE (demo) versie alleen een kristal waarde van 4MHz of 20MHz is toegestaan, dit is dus een beperking van de demo versie.



De resonator
Een ander vrij nauwkeurige oscillator is een resonator (op de foto rechts een 20MHz exemplaar).
Deze is minder nauwkeurig dan het duurdere kristal, maar stukken nauwkeuriger dan de interne oscillator van de PIC.
Bovendien zijn bij de resonator de 2 condensatoren al ingebouwd, dus die hoeven ook niet meer los bij de PIC geplaatst te worden, alleen de resonator is voldoende.
De resonator heeft drie pinnen, waarvan de middelste met massa (GND, 0V) moet worden verbonden.
De buitenste twee komen aan de oscillator ingangen van de PIC (pin 15 en 16 van de 16F628A).


OSCCAL (= oscillator callibration)
De snelheid van een PIC die loopt op zijn interne oscillator is dus lang zo nauwkeurig niet dan een PIC die draait op een kristal of resonator, maar nauwkeurigheid is ook niet altijd nodig.
Bij sommige PIC types is de interne oscillator te kalibreren (= fijner af te regelen) (helaas niet mogelijk bij de 16F628A).
Let op, dat is wat anders dan de besproken instelbare snelheid van interne oscillatoren die sommige PIC types hebben.
Het afregelen (kalibreren) gebeurt met OSCCAL = ?, waarbij op de plaats van het vraagteken een waarde van 0 ... 255 kan worden ingevuld.
Zodoende is de onnauwkeurige interne oscillator van de PIC fijner af te regelen.
Let wel, voor iedere PIC kan die waarde anders zijn omdat deze instructie er juist voor is om de toleranties bij de PIC's onderling op te vangen.
Met OSCCAL kun je de frequentie iets hoger of lager instellen om op (bijna) precies 4MHz uit te komen.


Uit het laatste getal op de PIC is het bouwjaar van de PIC af te leiden.
 

Zelfs van PIC's die in dezelfde periode zijn gemaakt zitten er verschillen in de interne oscillator.
Heb je bijvoorbeeld meerdere PIC's met bouwkenmerk 0709086 (zie de 14-pins 16F676 op de foto), dan kunnen er nog steeds grote verschillen zitten in de snelheid van de interne oscillator van deze PIC's onderling.
De eerste vier cijfers van het bouwkenmerk bevatten de bouwdatum, waarvan de eerste twee cijfers het jaartal en de twee daaropvolgende cijfers het weeknummer is.
De bouwdatums van de PIC's op de foto zijn dus:

16F676 0709086 2007, weeknr.09 (0709xxx)  
16F628A 060340E 2006, weeknr.03 (0603xxx) (kalibreren niet mogelijk)
12F675 0248 2002, weeknr.48 (0248)  
18F2455 05074RA 2005, weeknr.07 (0507xxx) (kalibreren met OSCTUNE)

Voor degenen die ermee willen experimenteren een tip:
De 8-pins PIC type 12F675 kan wel fijngeregeld worden.
Onderstaand programma laat een LED knipperen om de seconde:

DEVICE 12F675                 ;LET OP, HIER DE 8-PINS 12F675
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, MCLRE_OFF
ALL_DIGITAL TRUE

OSCCAL = 112                  ;112 is hier een voorbeeld waarde

WHILE 1 = 1                   ;Oneindige lus
  TOGGLE GPIO.0               ;LED met serieweerstand aansluiten op GPIO.0 
  DELAYMS 1000                ;1 seconde wachten
WEND

Door steeds een andere waarde achter OSCCAL te zetten, het programma weer te compileren en in de PIC te programmeren, zul je zien dat de knipperfrequentie van de LED (iets) is verandert.
Op deze manier is ook de juiste waarde voor OSCCAL te bepalen, gewoon een programma schrijven dat een LED om de seconde laat knipperen.
Blijft de LED behoorlijk in de pas lopen met de secondewijzer van een klok, dan is de waarde achter OSCCAL goed.
Knippert de LED sneller dan een seconde, dan moet de waarde achter OSCCAL worden verlaagd, waardoor de PIC langzamer zal gaan lopen, en als de LED langzamer knippert, dan de waarde verhogen.
 

SET_OSCCAL
PIC fabrikant Microchip heeft bij de PIC's die gekalibreerd kunnen worden (dus helaas niet de 16F628A), de optimale interne oscillatorwaarde op het één na laatste adres van het programmageheugen van de betreffende PIC geplaatst.
De PIC is dus al wel gekalibreerd door de fabriek, alleen moet het PIC Basic programma dit nog doorgeven aan het oscillator kalibreer register.


Uitlezing van een nieuwe, nog ongeprogrammeerde PIC 12F675 met BumbleBee.
De kalibreer waarde van de fabriek is geplaatst op het één na laatste adres van het programmageheugen.
Deze waarde kan dus verschillen bij de PIC's onderling.

 

De fabriekswaarde die hier staat kan automatisch ingevuld worden (in het OSCCAL register, later meer hierover), door ergens bovenin het PIC Basic programma SET_OSCCAL te plaatsen:

DEVICE 12F675                 ;LET OP, HIER DE 8-PINS 12F675
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, MCLRE_OFF
ALL_DIGITAL TRUE

SET_OSCCAL                    ;Stel interne oscillator in op fabrieksgekalibreerde waarde 

WHILE 1 = 1                   ;Oneindige lus
  TOGGLE GPIO.0               ;LED met serieweerstand aansluiten op GPIO.0 
  DELAYMS 1000                ;1 seconde wachten
WEND

Als het goed is dan zou de LED met bovenstaand programma (met SET_OSCCAL dus) aardig nauwkeurig elke seconde aan of uit moeten gaan.
Denk er wel aan dat bij het wissen van het geheugen van de PIC deze fabriekswaarde ook gewist kan worden en daardoor de fabriekswaarde verloren gaat.
Programmeren van SET_OSCCAL in een PIC die al eens helemaal gewist is resulteert in een niet werkende PIC.
Je zult dan zelf (met OSCCAL = ?) de juiste instelling moeten opgeven.

Lees meer hierover in de HELP bestanden van PIC Basic (zie SET_OSCCAL) en de datasheets van de 12F6xx.

N.B.
Helaas wist BumbleBee de fabriekswaarde tijdens programmeren.
XWisp bewaard wél de fabriekswaarde tijdens PIC programmeren.


In deel 4 wordt het weer leuker.
Dan gaan we teksten met een (HD44780 of compatible) LC-Display (LCD) afbeelden.