INCLUDE, programma's opsplitsen en programmadelen invoegen

Er zijn soms delen van een programma die in veel programma's hetzelfde zijn.
Bijvoorbeeld:

;Logische constanten
SYMBOL AAN     = 0            ;Geinverteerd ON
SYMBOL HOOG    = 1            ;Signaal met hoog niveau
SYMBOL LAAG    = 0            ;Signaal met laag niveau           
SYMBOL TRUE    = 1            ;Waar
SYMBOL FALSE   = 0            ;Niet waar 
SYMBOL OFF     = 0            ;
SYMBOL ON      = 1            ;
SYMBOL UIT     = 1            ;Geinverteerd OFF

Dit stukje programma komt voor in al mijn programma's en kan natuurlijk gewoon in elk programma worden geschreven.
Maar zo'n programmablokje kan ook apart worden opgeslagen, bijvoorbeeld als Logische_constanten.inc
In elk programma waar je minimaal één van deze constanten gebruikt, plaats je dan op de plek in je programma, waar normaal dit programmadeel zou staan, de regel INCLUDE "Logische_constanten.inc"

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

;Logische constanten
SYMBOL AAN     = 0            ;Geinverteerd ON
SYMBOL HOOG    = 1            ;Signaal met hoog niveau
SYMBOL LAAG    = 0            ;Signaal met laag niveau 
SYMBOL TRUE    = 1            ;Waar
SYMBOL FALSE   = 0            ;Niet waar 
SYMBOL OFF     = 0            ;
SYMBOL ON      = 1            ;
SYMBOL UIT     = 1            ;Geinverteerd OFF

OUTPUT PORTA.0                ;Stel PORTA.0 in als uitgang


;Hoofdprogramma
WHILE 1 = 1
  PORTA.0 = HOOG              ;Maak PORTA.0 hoog
  DELAYMS 500                 ;Even wachten
  PORTA.0 = LAAG              ;Maak PORTA.0 laag
  DELAYMS 500                 ;Even wachten
WEND

Boven- en onderstaande programma's zijn volledig gelijk aan elkaar, alleen is in onderstaande programma de lijst met logische constanten apart opgeslagen in een INCLUDE bestand met de naam "Logische_constanten.inc".
Het onderstaande programma is nu al overzichtelijker dan het bovenstaande, dus kun je nagaan wat dat scheelt als de lijst met constantenamen nog veel langer is.

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

INCLUDE "C:\PIC programmas\Logische_constanten.inc"

OUTPUT PORTA.0                ;Stel PORTA.0 in als uitgang


;Hoofdprogramma
WHILE 1 = 1
  PORTA.0 = HOOG              ;Maak PORTA.0 hoog
  DELAYMS 500                 ;Even wachten
  PORTA.0 = LAAG              ;Maak PORTA.0 laag
  DELAYMS 500                 ;Even wachten
WEND

Een lijst met constantenamen neemt geen enkele geheugenplaats van de PIC in, hoe groot die lijst ook is.
Alle programmaregels die in het INCLUDE bestand staan, worden gecompileerd alsof ze in het huidige programma staan, op de plek waar INCLUDE is geplaatst.


Let op dat bij INCLUDE tevens de extensie wordt opgegeven tussen de aanhalingstekens in het PIC Basic programma.

INCLUDE "Logische_constanten" werkt dus niet, want er is geen extensie opgegeven.

INCLUDE "Logische_constanten.inc" of INCLUDE "Logische_constanten.bas" werkt wel.

Ook een pathname mag worden opgegeven, let daarbij wel op dat sommige tekens niet worden geaccepteerd.

INCLUDE "C:\PIC programma's\Logische_constanten.inc" werkt niet door de apostrof (= het ' teken).

INCLUDE "C:\PIC programmas\Logische_constanten.inc" werkt wel, omdat de apostrof in het woord programma's is weggehaald.
Het pathname op de harde schijf zelf mag dus ook geen apostrof bevatten.


INCLUDE is ook handig bij verbindingen tussen meerdere PIC's.
Ikzelf heb thuis zo'n 7 PIC's her en der in huis liggen, die allen met elkaar verbonden zijn (sommige draadloos).
De PIC's besturen van alles in huis afhankelijk van o.a. DCF77 tijd, temperatuur, RC5 afstandsbediening, telefoonafstandsbediening, LDR, infraroodsensoren, enz.
Iedere opdracht heeft een eigen waarde (een getal tussen 0 en 255) die over de lijn wordt verzonden/ontvangen naar/door alle PIC's.
De PIC die in zijn programma de ontvangen waarde in zijn SELECT CASE lijst heeft staan gaat de opdracht uitvoeren en de overige PIC's, die de opdrachtwaarde ook ontvangen, doen er verder niets mee, omdat de ontvangen waarde niet in zijn SELECT CASE tabel voorkomt (zie cursus deel 6).

Elke opdrachtwaarde heeft nu een constantenaam gekregen, waardoor er een hele lijst is ontstaan.
Een selectie daaruit:

;Woning opdrachtcodes
ThermostaatComfort  = 36  ;Nefit thermostaat volgens laatst ingestelde temp.
ThermostaatEconomic = 37  ;Nefit thermostaat laagstand (15.0 graden)
Thermostaat190      = 38  ;Nefit thermostaat 19.0 graden (deel getal door 2)
Thermostaat195      = 39  ;Nefit thermostaat 19.5 graden
Thermostaat200      = 40  ;Nefit thermostaat 20.0 graden
Thermostaat205      = 41  ;Nefit thermostaat 20.5 graden
Thermostaat210      = 42  ;Nefit thermostaat 21.0 graden
Thermostaat215      = 43  ;Nefit thermostaat 21.5 graden
Thermostaat220      = 44  ;Nefit thermostaat 22.0 graden
RaamKamerOpenen     = 60  ;Kamerraam openen als deze dicht is
RaamKamerSluiten    = 61  ;Kamerraam sluiten als deze open is
RaamKamerToggle     = 62  ;Openen als raam dicht is/sluiten als raam open is
RaamKeukenOpenen    = 63  ;Keukenraam openen als deze dicht is
RaamKeukenSluiten   = 64  ;Keukenraam sluiten als deze open is
RaamKeukenToggle    = 65  ;Openen als raam dicht is/sluiten als raam open is
CancelRamen         = 66  ;Sluit ramen en cancel automatisch ramen openen voor deze dag
BadVullen           = 67  ;Waterkleppen aansturen om bad te vullen
CancelBadVullen     = 68  ;Stop bad vullen en cancel automatische bad vullen voor die dag 
LuxaflexOpenen      = 69  ;Luxaflex openen als deze dicht is
LuxaflexSluiten     = 70  ;Luxaflex sluiten als deze open is
LuxaflexTippen      = 71  ;Luxaflex sluiten of openen tot gewenste halfstand
PosterNaarLinks     = 72  ;Poster naar links verschuiven
PosterNaarRechts    = 73  ;Poster naar rechts verschuiven
SpiegelOpenen       = 74  ;Open beamer spiegel
SpiegelSluiten      = 75  ;Sluit beamer spiegel
ResetCancels        = 76  ;Reset alle cancelopdrachten
DCF77updating       = 77  ;Maak de RTC weer gelijk aan DCF77 tijd

Stel je voor dat je in je PIC Basic programma deze lijst (en dit is nog maar een klein deel ervan) moet plaatsen.
Als je verschillende PIC programma's hebt (in mijn geval dus 7), die allemaal dezelfde lijst gebruiken, dan is het lastig als er iets in die lijst wordt verschoven omdat je dan al die programma's moet nalopen.
Door de lijst apart op te slaan en in elk programma INCLUDE te plaatsen, wordt het allemaal veel eenvoudiger en overzichtelijker, en het voorkomt vergissingen.

Als nu bijvoorbeeld de DCF77 klok om 19:00 uur het ligbad moet vullen, dan staat er in de PIC met het DCF77 programma:
CASE
 1900 : SEROUT PORTA.0, Baud, [BadVullen]

Als de PIC met de IR-ontvanger een RC5 code ontvangt die de opdracht bad vullen moet uitvoeren dan staat er in dat PIC programma:
CASE
 BadVullen : SEROUT PORTA.0, Baud, [BadVullen]

Als de PIC van de telefoonprint bijvoorbeeld de DTMF toon van toets 1 van een bellend (mobiel) telefoontoestel ontvangt om het bad te vullen, dan staat er in het programma van de telefoonprint:
CASE
 1 : SEROUT PORTA.0, Baud, [BadVullen]

'BadVullen' is een constantenaam uit de lijst en staat voor waarde 67.
Alle 7 PIC's bij me thuis ontvangen deze opdracht (waarde 67 dus), maar alleen de PIC die de waterkleppen voor het bad vullen bestuurt, doet er wat mee, namelijk het aansturen van de waterkleppen zodat het bad vult met water.

Maar nu het voordeel als je INCLUDE gebruikt.
De voorgaande lijst constantenamen met bijbehorend getallen wordt in geen één PIC programma geplaatst, maar wordt apart opgeslagen in een bestand met de naam "Woning_opdrachtnamen.inc".
Door nu in alle PIC programma's voor de woningbesturing bovenin deze programma's te zetten: INCLUDE "C:\PIC programmas\Woning_opdrachtnamen.inc" is de gehele actuele lijst beschikbaar voor elke PIC die bij de woning betrokken is.

Het voordeel is ondermeer dat er nu geen verschillen in de lijsten van de PIC's onderling kunnen zijn.
En een wijziging of toevoeging in de lijst met constantenamen hoeft maar eenmalig te gebeuren, waardoor alle 7 verschillende PIC programma's in één keer is gewijzigd.
Zonder INCLUDE zou ik alle 7 PIC Basic programma's moeten wijzigen met alle kans op fouten.

Voor alle drie bovenstaande voorbeelden, heeft 'BadVullen' nu dezelfde waarde (namelijk 67 in dit geval).
Wanneer om een bepaalde reden 'BadVullen' een andere waarde moet krijgen, dan hoeft alleen het INCLUDE bestand te worden aangepast.


Meerdere INCLUDE's in één programma is toegestaan, bijvoorbeeld:

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

INCLUDE "C:\PIC programmas\Logische_constanten.inc"
INCLUDE "C:\PIC programmas\Woning_opdrachtnamen.inc"

;Poortnamen
SYMBOL Toets        = PORTA.0 ;Ingang voor toets
SYMBOL Uitgang      = PORTA.1 ;Uitgang voor seriele communicatie


;Hoofdprogramma
WHILE 1 = 1
  IF Toets = AAN THEN SEROUT Uitgang, Baud, [BadVullen] ;Bij toetsindruk, bad vullen     
  DELAYMS AntiDender          ;Ontdenderingstijd voor 'Toets'
  WHILE Toets = AAN : WEND    ;Wacht zolang de 'Toets' is ingedrukt
  DELAYMS AntiDender          ;Ontdenderingstijd voor 'Toets'
WEND

Zoals in bovenstaand voorbeeld is te zien, zijn de namen 'AAN', 'AntiDender', 'BadVullen' en 'Baud' niet in het programma zelf gedeclareerd, maar staan deze in één van de INCLUDE bestanden.
Doordat de baudrate 'Baud' voor de SEROUT opdracht in het INCLUDE bestand staat, is het heel eenvoudig om van alle 7 PIC's bij me thuis de onderlinge communicatiesnelheid in één handeling te wijzigen.


Plaats een INCLUDE bestand op die plek in je programma, waar normaal de inhoud van dat bestand in het programma zou staan.
Er kunnen dus ook INCLUDE bestanden ergens middenin of onderaan het programma staan.
Als het INCLUDE bestand echter (assembler) subroutines bevat, dan moet dit INCLUDE bestand altijd bovenin het programma worden geplaatst, dus nog vóór het hoofdprogramma, dit om verdeling over meerdere geheugenbanken in de PIC te voorkomen.

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

INCLUDE "C:\PIC programmas\Logische_constanten.inc"
INCLUDE "C:\PIC programmas\Woning_opdrachtnamen.inc"

;Poortnamen
SYMBOL Toets        = PORTA.0 ;Ingang voor toets
SYMBOL Uitgang      = PORTA.1 ;Uitgang voor seriele communicatie

GOTO HoofdProgramma           ;Spring over de subroutine(s)


;Subroutine(s)
INCLUDE "C:\PIC programmas\Subroutines.inc"


HoofdProgramma:
WHILE 1 = 1
  IF Toets = AAN THEN SEROUT Uitgang, Baud, [BadVullen] ;Bij toetsindruk, bad vullen 
  DELAYMS AntiDender          ;Ontdenderingstijd voor 'Toets'
  WHILE Toets = AAN : WEND    ;Wacht zolang de 'Toets' is ingedrukt
  DELAYMS AntiDender          ;Ontdenderingstijd voor 'Toets'

  GOSUB MeetTemperatuur       ;Spring naar een subroutine in het (derde) INCLUDE bestand 
WEND

Om ervoor te zorgen dat bij het starten van de PIC niet meteen een subroutine wordt binnengelopen, moet er over de subroutine(s) en de INCLUDE bestanden die subroutines bevatten worden gesprongen (in het voorbeeld door GOTO HoofdProgramma).


In een INCLUDE bestand kan precies hetzelfde worden geplaatst als in een normaal programma.
Programmalabels, subroutines, assemblerroutines, programmalussen, declaraties, alles kan.
Het kan dus ook complete delen van programma's bevatten.

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

INCLUDE "C:\PIC programmas\Logische_constanten.inc"
INCLUDE "C:\PIC programmas\KnipperLED.inc"

Bovenstaande vijf regels is een compleet werkend programma, dat een LED laat knipperen op PORTA.0.

Het INCLUDE bestand "KnipperLED.inc" bevat hierbij het volgende:

SYMBOL LED = PORTA.0          ;Op PORTA.0 zit een LED aangesloten 

OUTPUT LED                    ;Maak van poort 'LED' een uitgang

WHILE 1 = 1                   ;Oneindige lus
  LED = AAN                   ;LED aanzetten
  DELAYMS 500                 ;Even wachten
  LED = UIT                   ;LED uitzetten
  DELAYMS 500                 ;Even wachten
WEND                          ;Terug naar WHILE

De constantenamen 'AAN' en 'UIT' staan hier in INCLUDE bestand "Logische_constanten.inc" en deze worden op hun beurt weer gebruikt in INCLUDE bestand "KnipperLED.inc".
Het is hierom van belang dat "KnipperLED.inc" ónder "Logische_constanten.inc" staat, want als je deze bóven "Logische_constanten.inc" zou plaatsen, dan zijn de constantenamen 'AAN' en 'UIT' nog niet bekend en dan krijg je tijdens compileren een foutmelding.

Houdt ook in de gaten dat labels, constante- en variabelenamen niet dubbel voorkomen, dus dat er bijvoorbeeld niet in meerdere INCLUDE bestanden de naam 'LED' wordt gedeclareerd, want dan krijg je de error Duplicate Declaration tijdens het compileren.


(INCLUDE is in de PIC Basic LITE versie niet te gebruiken.)