Een toepassing realiseren
In dit deel wordt beschreven hoe een toepassing voor de SIMPLEX tot
stand komt. De beschrijving is stap- voor stap, en resulteert uiteindelijk
in een luxe en intelligente thermostaat voor een tropisch aquarium. Het
gaat bij dit voorbeeld vooral om de wijze waarop het ontwerp tot stand
komt.
De manier waarop tot het eindresultaat gekomen wordt is voor elke
toepassing te gebruiken.
Stap 1: Probleemstelling
Als eerste moet zo nauwkeurig mogelijk omschreven worden wàt we nu
eigenlijk willen maken. Eerst een probleemschets:
Tropische vissen voelen zich het prettigst bij ongeveer 24 graden
Celcius. In ons land betekent dit meestal dat het water verwarmd dient te
worden. 's Zomers echter kan het voorkomen dat gedurende langere tijd (een
paar dagen) de buitentemperatuur meer dan 24 graden wordt. Het
aquariumwater zal dan vanzelf ook warmer dan 24 graden worden. De vissen
kunnen hier gelukkig goed tegen. Waar vissen over het algemeen niet tegen
kunnen, is plotselinge veranderingen van de temperatuur. Wanneer b.v. na
een hittegolf plotseling een veel koelere periode aanbreekt, kan de
temperatuur van het aquariumwater te snel zakken. We willen nu een
intelligente thermostaat bouwen, die:
- Het water zo goed mogelijk op 24 graden Celcius houdt.
- Als het water 25 graden of warmer wordt, een LED aan zet.
- Ervoor zorgt dat het water in 4 uur niet meer dan 1 graad afkoelt.
Stap 2: De hardware
In de tweede stap wordt bepaald welke hardware er nodig is om de
gevraagde toepassing te kunnen realiseren, en op welke wijze de SIMPLEX
deze hardware moet gaan besturen.
In deze toepassing moeten de volgende zaken gemeten en bestuurd worden:
- De watertemperatuur moet gemeten worden.
- Er moet een LED bestuurd worden.
- Er moet een elektrische verwarming aan- en uitgezet kunnen worden.
De temperatuurmeting.
Voor het meten van de watertemperatuur is een temperatuursensor nodig.
Een voor de hand liggende keus is een NTC (een weerstand waarvan de waarde
verandert met de temperatuur.) Een NTC kan in een spanningsdeler
configuratie worden opgenomen en dan direct tussen aarde en één van de
analoge ingangen van poort E van de SIMPLEX aangesloten worden. Als nu
bekend is welke waarde de NTC zal hebben bij verschillende temperaturen,
kan berekend worden welke NTC-temperatuur bij de spanning op de analoge
ingang van de micro-controller hoort. Daarmee wordt het mogelijk om de
temperatuur te meten. Dit is slechts één voorbeeld, om temperaturen te
meten zijn veel oplossingen mogelijk.
Een andere mogelijkheid is om een speciale temperatuursensor te
gebruiken, één die door de fabrikant al is afgeregeld en waarmee heel
nauwkeurig gemeten kan worden. Deze SMARTEC
temperatuursensor is verkrijgbaar in een uitvoering waarbij de sensor
is ondergebracht in een metalen huisje zoals ook voor transistoren wordt
gebruikt, dus eenvoudig in te bouwen. De sensor moet gevoed worden met 5
Volt, en geeft als uitgangs signaal een blokgolf op TTL niveau. De
duty-cycle van dit signaal (de verhouding tussen de periodetijd en de tijd
dat het signaal een '1' is), is een maat voor de temperatuur. Vanwege de
nauwkeurigheid, en omdat de sensor een signaal op TTL niveau afgeeft,
kiezen we voor deze SMARTEC sensor.
De temperatuursensor geeft een signaal af, waarvan de duty-cycle
gemeten moet worden. Dit betekent dus, dat er in feite twee tijden gemeten
moeten worden: een periodetijd, en de tijd gedurende welke het signaal een
'1' is in één periode. Voor het meten van tijden zijn de timer-ingangen
van de micro-controller het meest geschikt. De sensor kan dus het beste
worden aangesloten op een timer-ingang, bijvoorbeeld op bit2 van poort A.
De 5 Volt voeding voor de sensor is beschikbaar op de connector.
De LED.
De LED die nodig is, is al aanwezig op de SIMPLEX zelf. Voor de andere
LED kan nog een toepassing bedacht worden. De tweede LED kan bijvoorbeeld
gebruikt worden om aan te geven dat de verwarming aan staat.
De sturing van de verwarming.
De verwarming wordt gevoed vanuit het lichtnet. Voorzichtigheid is hier
dus op zijn plaats! Het beste kan de verwarming bestuurd worden middels
een goed relais. De contacten van dit relais moeten uiteraard berekend
zijn op het vermogen dat de verwarming heeft. Voorts moet het relais
geschikt zijn om 230 Volt te schakelen.
De spoel van het relais kan worden bestuurd vanuit één van de
uitgangen van poort A. Met een eenvoudige transistor schakeling kan het
relais worden aangestuurd. Denk aan een goede isolatie van de 230 Volt
indien U deze schakeling daadwerkelijk bouwt!
Stap 3: De software
Nu bekend is welke hardware gebruikt zal gaan worden, en op welke wijze
deze op de micro-controller aangesloten is, kan aan het programma begonnen
worden. Evenals voor de hardware, moet ook voor de software een ontwerp
gemaakt worden. Hiervoor zijn vele technieken bedacht, maar een eenvoudige
en goed te begrijpen manier is om dit door middel van een stroom-diagram
te doen (flow-chart.) Hierin wordt een actie die door de micro-controller
moet worden ondernomen, weergegeven in een rechthoek. Een beslissing die
door de micro-controller moet worden genomen is weergegeven in een ruit.
Het stroom-diagram van het hoofdprogramma is eenvoudig, en voor bijna
alle toepassingen hetzelfde. Na Reset moet de micro-controller zijn
stackpointer laden, eventueel het RAM initialiseren, en daarna de I/O goed
zetten. Hierna kan het hoofdprogramma gestart worden. Het hoofdprogramma
wordt doorlopen totdat de SIMPLEX weer wordt uitgeschakeld.

Het blok 'doe hoofdprogramma' bevat het eigenlijke programma, dus dat
moet verder uitgewerkt worden.
In deze toepassing wordt de temperatuur van het water in een aquarium
geregeld. Overal waar iets geregeld moet worden zijn steeds twee waarden
van belang:
- De werkelijke waarde
- De gewenste waarde
Zolang deze waarden niet aan elkaar gelijk zijn, moet er kennelijk nog
iets gebeuren. Het doel van de regeling is immers ervoor te zorgen dat de
werkelijke temperatuur uiteindelijk gelijk wordt aan de gewenste
temperatuur.
Naast deze temperatuur regeling moet het programma nog een LED
besturen. Zo kan het stroom-diagram van het hoofdprogramma worden
opgesteld:

Eerst moet de werkelijke temperatuur van het water gemeten worden. Als
deze temperatuur meer dan 25 graden Celcius is, dan wordt de LED aan
gezet. Als deze temperatuur 25 graden of minder is, dan mag de LED uit. De
besturing voor de LED is hiermee klaar.
Daarna wordt gekeken of de verwarming aan- of uitgezet moet worden. Als
de temperatuur hoger is dan de gewenste temperatuur, dan moet de
verwarming uitgezet worden. Als de temperatuur van het water lager is dan
de gewenste temperatuur, dan moet de verwarming aangezet worden. Als de
temperatuur precies gelijk is aan de gewenste temperatuur, dan mag de
verwarming blijven staat zoals hij stond. De temperatuur is dan goed, en
er hoeft niets te gebeuren.
Het programma is nu zóver, dat het aquariumwater zo goed mogelijk
gebracht zal worden op de in het programma ingestelde gewenste
temperatuur. Als deze gewenste temperatuur altijd gelijk zou zijn,
bijvoorbeeld 24 graden Celcius, dan zou het programma nu klaar zijn. Er is
echter een eis gesteld aan de snelheid waarmee de temperatuur mag
veranderen. Als het water door zomers weer bijvoorbeeld 28 graden wordt,
dan moet de thermostaat ervoor zorgen dat het water in de volgende 4 uur
niet verder afkoelt dan 1 graad, dus tot 27 graden. Als na deze 4 uur de
temperatuur 27 graden is geworden, dan moet het water in de volgende 4 uur
verder afkoelen tot 26 graden, en zo verder totdat uiteindelijk na 16 uur
het water weer op 24 graden is gekomen. Hieruit blijkt dat de in het
programma in te stellen gewenste temperatuur variabel is. Deze gewenste
temperatuur moet dus elke keer opnieuw ingesteld worden. Dit gebeurt in
het blokje 'pas gewenste temperatuur aan'. Datgene wat er in dit blok
gebeurt is ook weer verder uitgewerkt in een stroom-diagram.

De gewenste temperatuur moet worden verhoogd als het water in het
aquarium te warm is geworden. Als aangenomen wordt dat de thermostaat het
water precies op de gewenste temperatuur kan houden, dan is een te hoge
temperatuur blijkbaar door andere omstandigheden veroorzaakt. De
thermostaat moet er dan voor gaan zorgen dat deze hoge temperatuur weer
langzaam afgebouwd wordt. Een te hoge temperatuur kan worden geconstateerd
als het water meer dan 1 graad warmer is dan de temperatuur waarop de
thermostaat het water probeert te brengen. Dus als de gemeten temperatuur
groter is dan de gewenste temperatuur + 1 graad, dan moet de thermostaat
deze graad teveel in 4 uur afbouwen. Hiertoe wordt een urenteller op 0
gezet, en de gewenste temperatuur wordt ingesteld op de gemeten
temperatuur - 1 graad. Dit betekent dat de temperatuur gedurende 4 uur
geregeld wordt naar een temperatuur die 1 graad onder de (te hoge) gemeten
temperatuur ligt, zodat het water in 4 uur ten hoogste 1 graad af kan
koelen. Dit is wat er gerealiseerd moet worden.
Als nu de gewenste temperatuur groter is dan 24 graden, dan is de
thermostaat blijkbaar bezig het water langzaam af te laten koelen. Deze
gewenste temperatuur mag na 4 uur met 1 graad worden verlaagd, dus als de
urenteller op 4 staat, mag de gewenste temperatuur met 1 worden verlaagd,
en gaat er een nieuwe periode van 4 uur in. Als de gewenste temperatuur
niet hoger is dan de standaard 24 graden, dan is er blijkbaar geen sprake
van een afkoelperiode, dus dan hoeft er verder niets speciaals te
gebeuren.
Stap 4: De software detailleren
Nu het hoofdprogramma vast ligt, kunnen de verschillende onderdelen
daarvan nader bekeken worden.
De alarm LED en het relais voor de verwarming zijn rechtstreeks
aangesloten op poort A. Deze hoeven niet verder bekeken te worden, het is
eenvoudig om poort A te besturen.
Daarnaast moet er een urenteller gerealiseerd worden. Deze teller moet:
- Terug op 0 gezet kunnen worden.
- Het aantal uren tellen dat is verstreken sinds hij op 0 werd gezet.
Voor de urenteller is een tijdbasis nodig. Een tijdbasis kan worden
afgeleid uit het kristal dat op de micro-controller is aangesloten.
Hiervoor kan de 'Real Time Interrupt' gebruikt worden, of één van de
output-compare timers. De real-time interrupt kan zodanig worden ingesteld
dat op regelmatige tijdstippen een interrupt gegenereerd wordt. De tijd
tussen twee interrupts kan worden gekozen uit 4 mogelijkheden. De
output-compare timers kunnen een interrupt geven na een tijd die
instelbaar is in eenheden van 0.5µs, en zijn dus veel nauwkeuriger in te
stellen. We zullen kiezen voor een output-compare timer, bijvoorbeeld
timer 1.
De timer wordt ingesteld op een tijdbasis van 25ms. Dit zijn 50.000
pulsen van elk 0.5 µs. Er gaan 40 interrupts in één seconde. In 1 uur
gaan 3600 seconden. Er moet daarom één teller komen die interrupts telt,
totdat er een seconde verstreken is. Deze teller mag één byte groot
zijn. Na het verstrijken van één seconde wordt deze teller terug op 0
gezet, en mag er een seconde in de secondeteller worden bijgeteld. De
secondeteller moet tot 3600 kunnen tellen, en dus twee bytes groot zijn.
Als er 3600 seconden zijn verstreken wordt de urenteller met één
verhoogd. De tijd wordt eenvoudig teruggezet op 0 door alle tellers op 0
te zetten. In de vorige lessen is meer informatie over de output-compare
timers te vinden.
Als laatste moet de temperatuur gemeten worden. Dit komt neer op het
meten van de duty-cycle op een input-capture ingang.
De berekening van de duty-cycle vereist twee metingen, die van de
periodetijd van het signaal, en die van de tijd dat het signaal een '1'
is. Beide tijden kunnen met een input-capture timer gemeten worden. De
meting wordt gestart als het ingangssignaal van een '1' naar een '0' gaat
(een neergaande flank.) Dit is het begin van een periode van het signaal.
De tijd waarop dit gebeurt wordt onthouden. Als daarna het signaal van een
'0' naar een '1' gaat (een opgaande flank) is dit het begin van de tijd
dat het signaal een '1' is. De tijd waarop dit gebeurt wordt ook
onthouden. Als daarna het signaal weer van een '1' naar een '0' gaat, is
de periode afgelopen en kan worden uitgerekend hoe lang de periode geduurt
heeft, en hoe lang het signaal een '1' was. Dit moment is tevens de start
van een nieuwe meting. In de vorige lessen is meer informatie over de
input-capture timers te vinden.
Na de meting zijn zowel de periodetijd als de '1' tijd van het signaal
bekend, en wel in eenheden van 0.5µs. Dit moet nog worden omgerekend naar
de temperatuur die hierbij hoort. Volgens het data-sheet van de SMARTEC
sensor is de duty-cycle afhankelijk van de temperatuur volgens de formule:
d.c. = 0.31924 + 0.00472 x Temperatuur (graden Celcius)
Hieruit volgt, dat de temperatuur is: 211.9 x ( d.c. - 0.31924) De
cijfers achter de komma moeten weggerekend worden. Dit kan door de formule
aan beide zijden met 216 (65536) te vermenigvuldigen. Er
onstaat dan:
Temperatuur x 65536 = 211.9 x ( 216 x d.c. - 20922)
Ofwel:
309 x Temperatuur = 216 x d.c. - 20922
Het getal d.c. x 216 kan eenvoudig berekend worden door de
'1' tijd van het signaal en de periodetijd van het signaal op elkaar te
delen via de 'fdiv' instructie. Deze instructie kan twee 16-bits getallen
op elkaar delen, maar vermenigvuldigt eerst het deeltal met 216
voordat het gedeeld wordt. Dat is precies wat in dit geval nodig is. Van
dit resultaat moet dan 20922 worden afgetrokken. Wat overblijft is een
getal, dat 309 keer het aantal graden celcius is dat we zoeken. Zo levert
bijvoorbeeld een temperatuur van 25 graden een resultaat op van ongeveer
25 x 309 = 7725. Het is eenvoudig om met deze getallen verder te rekenen.
De frequentie van het signaal van de sensor ligt tussen de 1 en 4 kHz.
Dat betekent dat elke milliseconde een nieuwe meetwaarde beschikbaar is.
Dat is veel sneller dan nodig. Daarvan kan gebruik gemaakt worden, door
niet over één, maar over bijvoorbeeld 256 perioden te meten. De tijden
die voor ieder van de 256 perioden worden gemeten worden opgeteld, en
later wordt de som weer door 256 gedeeld. De metingen duren dan ongeveer
¼ seconde. Dat is snel genoeg. Omdat over een langere tijd gemeten wordt,
zullen de meetwaarden beter bepaald kunnen worden, en vanwege het middelen
minder gevoelig zijn voor storingen.
Stap 5: Het assembler programma
Nu volledig is uitgezocht wat het programma moet gaan doen, en hoe de
verschillende onderdelen daarvan gerealiseerd kunnen worden, kan het
programma worden ingevoerd in de assembler.
De assembler programma's die als voorbeelden zijn opgenomen in deze
cursus hebben allemaal een gelijke opbouw. Hierin wordt eerst de definitie
gemaakt van het RAM en programma geheugen, daarna worden de
interrupt-vectoren benoemd. Het laden van de stack-pointer en het op 0
initialiseren van het RAM volgt daar op. Vervolgens wordt de code
ingevoerd voor de verschillende modulen. Daarna volgt, aan het einde van
de file, het hoofdprogramma.
De modulen hebben ook een eigen opbouw. Eerst wordt dataruimte voor de
module gereserveerd (indien nodig). Hierop volgt initialisatie code. Deze
code wordt afgesloten met een sprong-opdracht, die naar het eind van de
module springt. Tussen deze sprongopdracht en het eind van de module staan
de verschillende subroutines. Door deze opbouw te kiezen, wordt de
initialisatiecode voor een module automatisch doorlopen wanneer de
micro-controller gereset wordt. Het is verstandig om onderscheid te maken
tussen routines die voor gebruik door de module zelf zijn bedoeld, en
routines die door het hoofdprogramma aangeroepen mogen worden. Dit
onderscheid voorkomt vergissingen later. Door middel van commentaar kan
duidelijk aangeven worden, welke routine waarvoor bedoeld is.
In deze toepassing zijn de volgende modulen te herkennen:
- De alarm LED
- De verwarming
- De urenteller
- De temperatuur meter
De alarm LED.
Deze module heeft twee routines die vanuit het hoofdprogramma
aangeroepen moeten kunnen worden: 'alarm_aan', en 'alarm_uit'.
De verwarming.
Deze module heeft twee routines die vanuit het hoofdprogramma
aangeroepen moeten kunnen worden: 'verw_aan', en 'verw_uit'.
De urenteller.
Deze module heeft twee routines die vanuit het hoofdprogramma
aangeroepen moeten kunnen worden: 'uren_op_0', en 'aantal_uren'.
De temperatuur meter.
Deze module heeft één routine die vanuit het hoofdprogramma
aangeroepen moet kunnen worden: 'meet_temperatuur'.
Stap 6: Het testen
Wanneer de code voor een module in de assembler is ingevoerd kan deze
getest worden. Hiervoor moet een klein hoofdprogramma geschreven worden,
dat de module gebruikt op de manier zoals het uiteindelijke hoofdprogramma
dat ook zou doen. Omdat het testprogramma maar klein is, en er maar één
module tegelijkertijd aanwezig hoeft te zijn, is testen op deze wijze
eenvoudiger dan het hele programma in één keer te testen. Om de
urenteller te testen zou bijvoorbeeld een LED 4 uur aangezet kunnen
worden, en daarna weer 4 uur uit, etc. De temperatuurmeter kan getest
worden door de gemeten waarde via de seriële interface naar de PC te
sturen, en daar te beoordelen. In de eerder gegeven voorbeelden kunt U
vinden hoe de seriële poort bestuurd moet worden, en hoe de SIMPLEX
communiceert met een PC.
Als alle modulen naar behoren werken, kan het hoofdprogramma ingevoerd
worden. Omdat nu zeker is dat de modulen correct werken, is het ook
eenvoudiger om eventuele fouten uit het hoofdprogramma te halen.
Hieronder is de code gegeven waarvan eventueel uitgegaan kan worden
wanneer U de thermostaat wilt gaan maken. Bedenk dat de thermostaat in
deze vorm nog niet volledig betrouwbaar is. Een storing van buitenaf zou
bijvoorbeeld de micro-controller in de war kunnen brengen, waardoor het
programma niet goed meer wordt uitgevoerd. De 'watchdog' die in de
micro-controller zit kan helpen om in dit geval het programma weer in het
goede spoor te brengen.
De thermostaat is ook niet beveiligd tegen een losgeraakte sensor. Als
de sensor los is, zal er geen blokvormig signaal meer op de
micro-controller binnenkomen. Hierdoor zal de meting nooit 256 perioden
van het signaal kunnen meten, waardoor het programma oneindig lang gaat
wachten op signaal van de sensor. De watchdog biedt ook hier een oplossing
voor.
Als uitgangspunt is de hieronder gegeven code natuurlijk prima te
gebruiken.
Het programma
*************************************************
* definieren van de geheugen map
*************************************************
incl 'mapS3.asm'
*************************************************
* start van het programma
*************************************************
PROGRAM space |kies het programma?gebied
reset equ $ |na reset begint de micro op deze plaats
lds #stackend |begin met de stackpointer te laden
ldx #databeg |en zet dan het volledige datagebied op 00
clearram clr 0,x
inx
cpx #dataend
bls clearram
ldx #regsbeg |laat IX op de bank met I/O registers wijzen
*************************************************
* De alarm indicator
*************************************************
PROGRAM space
alarmstart equ $ |het beginadres van deze module
* hardware adressen
alarmport equ porta |Op deze poort is de LED aangesloten
alarmbit equ bit6 |Deze pin wordt gebruikt voor de LED
* initialisatie
PROGRAM space
bsr alarm_uit |neem aan dat er geen alarm is
bra alarmend |einde van de initialisatie
* subroutine voor het uitzetten van de alarmindicator
PROGRAM space
alarm_uit equ $
pshb |bewaar het B register op de stack
ldab alarmport |haal de stand van de poort op
andb #not(alarmbit)
stab alarmport |en maak het betreffende bit een '0'
pulb |haal daarna register B terug van de stack
rts
* subroutine voor het aanzetten van de alarmindicator
PROGRAM space
alarm_aan equ $
pshb |bewaar het B register op de stack
ldab alarmport |haal de stand van de poort op
orab #alarmbit
stab alarmport |en maak het betreffende bit een '1'
pulb |haal daara register B terug van de stack
rts
alarmend equ $ |einde van de alarm module
*************************************************
* De besturing van de verwarming
*************************************************
PROGRAM space
verwstart equ $ |het beginadres van deze module
* hardware adressen
verwport equ porta |Op deze poort is het relais aangesloten
verwbit equ bit0 |Deze pin wordt gebruikt voor het relais
* initialisatie
PROGRAM space
bsr verw_uit
bra alarmend |einde van de initialisatie
* subroutine voor het uitzetten van de verwarming
PROGRAM space
verw_uit equ $
pshb |bewaar het B register op de stack
ldab verwport |haal de stand van de poort op
andb #not(verwbit)
stab verwport |en maak het betreffende bit een '0'
pulb |haal daara register B terug van de stack
rts
* subroutine voor het aanzetten van de verwarming
PROGRAM space
verw_aan equ $
pshb |bewaar het B register op de stack
ldab verwport |haal de stand van de poort op
orab #verwbit
stab verwport |en maak het betreffende bit een '1'
pulb |haal daara register B terug van de stack
rts
verwend equ $ |einde van de alarm module
*************************************************
* De urenteller
*************************************************
* Deze module gebruikt output-compare 1 om eenheden van 25ms te tellen
* Na 40 van deze eenheden wordt een seconde teller verhoogd
* Na 3600 seconden wordt een urenteller verhoogd
PROGRAM space
urenstart equ $ |het beginadres van deze module
ms25 equ 50000 |het aantal klokperioden per interrupt
|een klokperiode duurt 0.5 micro?seconden
intspersec equ 40 |er gaan 40 interrupts in 1 seconde
secsperuur equ 3600 |aantal seconden in 1 uur
DATA space
oc1count rmb 1 |deze teller wordt bij elke interrupt verhoogd
seconden rmb 2 |hierin worden de seconden geteld
uren rmb 1 |hierin worden de uren geteld
* initialisatie van de output?compare interrupt
PROGRAM space
ldd tcnt |haal de systeemtijd
addd #ms25 |en zet deze 25 ms verder voor de eerste
std toc1 |interrupt, clear dan een eventuele interrupt
ldab #oc1f
stab tflg1 |enable daarna de interrupt van oc1
bset tmsk1?regsbeg,x,oc1i
bra urenend |einde van de initialisatie
* subroutine voor de afhandeling van de output?compare interrupt
PROGRAM space
oc1entry equ $
ldab #oc1f
stab tflg1 |reset de interrupt?vlag
ldab oc1count |en tel de interrupt
addb #1
stab oc1count
cmpb #intspersec
blo oc1entry9 |kijk of er 1 seconde verstreken is
clr oc1count |zoja, zet dan de interrupt teller op 0
ldd seconden |en verhoog de secondenteller
addd #1
std seconden
cpd #secsperuur |kijk of er al 1 uur verstreken is
blo oc1entry
ldd #0 |zoja, zet dan de secondenteller op 0
std seconden
inc uren |en verhoog de urenteller
oc1entry9 ldd toc1 |haal de tijd op het moment van de interrupt
addd #ms25 |en zet deze 25 ms verder voor de volgende
std toc1 |interrupt
rti
***** routines die door het hoofdprogramma gebruikt mogen worden
PROGRAM space
* haal het aantal verstreken uren op in register B
aantal_uren equ $
ldab uren
rts
* zet de urenteller op 0
* deze routine houdt de interrupts tijdelijk tegen, omdat anders het gevaar
* bestaat dat een interrupt van de output?compare de tellers verandert
* terwijl deze routine nog bezig is de tellers op 0 te zetten. Dit kan tot
* foutieve resultaten leiden.
uren_op_0 equ $
psha |bewaar register A op de stack
tpa |copieer het condition?code register naar A
psha |en zet het dan (via A) op de stack
sei |hou de interrupts tijdelijk tegen
clra
staa oc1count |en zet dan alle tellers op 0
staa seconden+1
staa seconden
staa uren
pula |haal het condition?code register terug
tap |via register A
pula |en haal register A terug van de stack
rts
urenend equ $ |einde van de urenteller module
*************************************************
* Temperatuur meting
*************************************************
* De temperatuurmeting telt gedurende 'nogtedoen' perioden van het ingangs?
* signaal de periodetijden op bij 'periodesom', en de tijden dat het signaal
* een '1' is op bij 'signaalsom'. Aan het eind van elke periode wordt
* 'nogtedoen' met 1 verlaagd. Als 'nogtedoen' op 0 komt, is de meting klaar
* en worden de sommen niet langer aangepast. De vlag 'meting_aan' wordt dan
* ook op '0' gezet. Om een meting te starten moet de vlag 'meting_aan' op
* '1' gezet worden, en 'nogtedoen' moet geinitialiseerd worden op het aantal
* perioden dat tijdens de meting gesommeerd moet worden. Ook moeten de
* sommen op 0 gezet worden.
PROGRAM space
tempstart equ $
* datagebied voor de temperatuur meting
DATA space
nogtedoen rmb 1 |aantal perioden dat nog gemeten moet worden
meting_aan rmb 1 |vlag om aan te geven dat er een meting loopt
periodesom rmb 3 |som van de periodetijden
signaalsom rmb 3 |som van de tijd dat het signaal een '1' is
periodestart rmb 2 |starttijd van een periode
starttijd1 rmb 2 |tijdstip waarop het signaal een '1' wordt
* initialisatie voor de temperatuur meting
PROGRAM space
ldab #$7E |zet de interrupt vector goed
stab tic1int
ldd #sensorint
std tic1int+1
ldx #regsbeg |start het meten met een neergaande flank
bclr tctl2+regsbeg,x,edg1a
bset tctl2+regsbeg,x,edg1b
ldab #ic1f |clear mogelijke interrupt
stab tflg1+regsbeg,x
bset tmsk1+regsbeg,x,ic1i
bra tempend
* subroutines voor de temperatuur meting
PROGRAM space
******* input capture interrupt routine *******
sensorint equ $
ldx #regsbeg |laat X op de I/O registers wijzen
* eerst de interrupt-vlag op '0' zetten
ldab #ic1f
stab tflg1+regsbeg,x
* daarna uitzoeken of het een op- of neergaande flank was
brclr tctl2+regsbeg,x,edg1a,sensorint1
* als het een opgaande flank is, dan zitten we in het midden van een meting
* onthoud de tijd waarop de flank kwam
ldd tic1+regsbeg,x
std starttijd1
* en wacht vervolgens op een neergaande flank
bclr tctl2+regsbeg,x,edg1a
bset tctl2+regsbeg,x,edg1b
bra sensorint9
* als het een neergaande flank is, dan zitten we aan het eind van een meting
* het eind van een meting is tevens het begin van een nieuwe meting
sensorint1 tst meting_aan |kijk of de meting gedaan moet worden
beq sensorint4
* als de meting gedaan moet worden:
* bereken de nieuwe som van de tijd dat het signaal een '1' is
ldd tic1+regsbeg,x
subd starttijd1 |reken uit hoe lang het signaal een '1' was
addd signaalsom+1
std signaalsom+1
bcc sensorint2
inc signaalsom |en tel dat op bij de som
* bereken de nieuwe som van de periodetijd van het signaal
sensorint2 ldd tic1+regsbeg,x
subd periodestart
addd periodesom+1
std periodesom+1
bcc sensorint3
inc periodesom |idem voor de periodetijd
* en verlaag het aantal perioden dat nog gemeten moet worden
sensorint3 dec nogtedoen
bne sensorint4
* als er geen perioden meer gemeten hoeven te worden, is de meting klaar
clr meting_aan
* leg de starttijd van de nieuwe periode vast
sensorint4 ldd tic1+regsbeg,x
std periodestart
* en ga op een opgaande flank wachten
bclr tctl2+regsbeg,x,edg1b
bset tctl2+regsbeg,x,edg1a
sensorint9 rti
* een meting van 256 perioden starten
startmeting equ $
tpa |bewaar (via A) het conditie?code register
psha |op de stack
sei |houd de interrupts tijdelijk tegen
ldd #0
staa nogtedoen |256 perioden sommeren
std periodesom |de periodesom op 0
staa periodesom+2
std signaalsom |de signaalsom op 0
staa signaalsom+2
ldab #1 |de meting starten
stab meting_aan
pula |haal (via A) het condition?code register
tap |terug van de stack
rts
***** routines die door het hoofdprogramma gebruikt mogen worden
PROGRAM space
* Meet de temperatuur, en laat het resultaat achter in D. Dit resultaat
* is 309 * het aantal graden in Celcius.
graad equ 309
meet_temp equ $
pshx |bewaar het IX register op de stack
bsr startmeting |start een meting van 256 perioden
meet_temp0 tst meting_aan |wacht totdat de meting klaar is
bne meet_temp0
ldx periodesom |de tijden worden door 256 gedeeld door
ldd signaalsom |alleen de twee meest significante bytes te
|gebruiken van de 3 bytes waarin de som staat
fdiv |bereken de duty?cycle
xgdx |zet het resultaat van de deling in D
subd #20922 |corrigeer daarna (zie de tekst in het manual)
pulx |haal X terug van de stack
rts
tempend equ $ |einde van de temperatuur meet?module
*************************************************
* het hoofdprogramma
*************************************************
alarmtemp equ 25*graad |temperatuur waarbij alarm gegeven wordt
optimaal equ 24*graad |de optimale temperatuur
houdtijd equ 4 |aantal uren dat de temperatuur wordt vastge?
|houden bij afkoelen
DATA space
gemeten rmb 2 |de gemeten temperatuur
gewenst rmb 2 |de gewenste temperatuur
PROGRAM space
cli |laat interrupts toe
jsr meet_temp |meet de temperatuur voor de eerste keer
ldd #optimaal
std gewenst |stel gewenste temperatuur in op optimaal
mainloop equ $ |de hoofdlus
jsr meet_temp |meet de huidige temperatuur
std gemeten
cpd #alarmtemp |moet alarm gegeven worden?
bls mainloop0
jsr alarm_aan |zoja, geef alarm
bra mainloop1
mainloop0 jsr alarm_uit |zonee, zet het alarm uit
mainloop1 cpd gewenst |huidige temperatuur > gewenst?
bls mainloop2
jsr verw_uit |zoja, zet de verwarming uit
mainloop2 cpd gewenst |huidige temperatuur < gewenst?
bhs mainloop3
jsr verw_aan |zoja, zet de verwarming aan
mainloop3 ldd gewenst
addd #graad
cpd gemeten |gemeten > gewenst + 1 graad?
bhs mainloop4
ldd gemeten |zoja, gewenst = gemeten ? 1 graad
subd #graad
std gewenst
jsr uren_op_0 |en start de urenteller
mainloop4 ldd gewenst
cpd #optimaal |gewenste temperatuur > optimale temperatuur?
bls mainloop |zoniet, dan is de lus klaar
jsr aantal_uren
cmpb #houdtijd |al voldoende tijd verstreken?
blo mainloop |zoniet, dan gewenst nog niet aanpassen
ldd gewenst |zoja, de gwenste temperatuur verlagen
subd #graad |met 1 graad
std gewenst
jsr uren_op_0 |de urenteller terugzetten
bra mainloop |en de lus herhalen
end
|