elomax

[ Techniek ] [ Shop ] [ Site map
TCNT ] Capture (IC) ] [ Compare (OC) ] OC Voorbeeld 1 ] OC Voorbeeld 2 ] OC Voorbeeld 3 ] IC Voorbeeld 1 ]

Terug
Omhoog

Output-compare timers

Er zijn in de micro-controller 5 output-compare systemen aanwezig, waarvan er één eventueel als input-capture geprogrammeerd kan worden. De output-compare functie is dan niet beschikbaar.

Output-compare timers worden gebruikt om gebeurtenissen in de buitenwereld te besturen, en werken dus als uitgangen. Het is mogelijk om de I/O schakeling rond een output-compare zodanig te programmeren dat bijvoorbeeld een pin van de micro-controller een '1' gemaakt wordt op het moment dat de inhoud van de free-running counter gelijk wordt aan de inhoud van het compare register. Het is ook mogelijk de pin een '0' te maken, of te inverteren. Daarnaast kan bij het optreden van een compare een interrupt gegenereerd worden.

Elk van de maximaal 5 output-compares heeft een eigen uitgang. Eén van de output-compares (output-compare 1) kan ook op maximaal 5 uitgangen tegelijkertijd werken. Hiermee kunnen relatief complexe digitale patronen opgewekt worden.

De output-compare registers 2 t/ 5 hebben elk de controle over één uitgang. Output-compare register 1 kan geprogrammeerd worden om op maximaal 5 uitgangen tegelijk te werken. Wanneer de free-running counter de waarde bereikt die in het output-compare register staat opgeslagen, kan als gevolg hiervan het logisch niveau op een uitgangspin veranderd worden, of op maximaal 5 uitgangen tegelijk in het geval van output-compare 1.

Voor elk van de output-compares 2 t/m 5 bevat het TCTL1 register twee bits die voor de betreffende output-compare bepalen wat er met de betreffende uitgang moet gebeuren als de free-running counter de waarde in het compare register bereikt:

OMx

OLx

verandering van de uitgang

0

0

geen verandering

0

1

inverteren

1

0

een '0' maken

1

1

een '1' maken

Output compare 1 kan op maximaal 5 uitgangen tegelijkertijd werken. Welke uitgangen worden aangepast wanneer er een output-compare 1 optreedt, wordt opgegeven in het OC1M register. Dit register bevat de bits OC1M7, OC1M6, OC1M5, OC1M4 en OC1M3. Wanneer OC1M7 een '1' is, wordt bij het optreden van output-compare 1 PA7 aangepast. Evenzo bepaalt OC1M6 of PA6 wordt aangepast, OC1M5 of PA5 wordt aangepast, etc.

De data die bij een output-compare 1 op de uitgangen PA7 .. PA3 moet worden gezet (mits de overeenkomende OC1Mx bits een '1' zijn), wordt bepaald door de OC1D7, OC1D6, OC1D5, OC1D4 en OC1D3 bits in het OC1D register. Deze bits worden door output-compare 1 naar de betreffende uitgangen gekopiëerd op het moment dat er een output-compare optreedt.

Bij een output-compare kan een interrupt gegenereerd worden. Dit wordt mogelijk gemaakt door het bij de betreffende output-compare behorende OCxI bit in het TMSK1 register een '1' te maken. Daarnaast wordt bij elke output-compare een vlag gezet in het TFLG1 register. Dit OCxF bit kan worden teruggezet op '0', door op de betreffende plaats in het TFLG1 register een '1' te schrijven.

Wanneer een output-compare register wordt geschreven door de micro-controller, doet deze dat in twee slagen: eerst het meest significante byte, en daarna het minst significante byte. Stel nu dat het output-compare register de waarde $ABCD bevat, en dat de micro-controller er de nieuwe waarde $0123 in schrijft. Eerst wordt het meest significante byte geschreven, waardoor het output-compare register tijdelijk de waarde $01CD krijgt. Daarna wordt ook het minst significante byte geschreven, waardoor het register uiteindelijk de correcte waarde $0123 zal hebben. Er bestaat nu de kans dat de free-running counter tijdens het schrijven van de nieuwe waarde in het output-compare register de waarde $01CD heeft. Hierdoor zou een compare kunnen optreden op het verkeerde moment. Om dit te voorkomen wordt de compare tijdelijk geblokkeerd nadat het meest significante byte van het output-compare register wordt geschreven. De compare actie wordt maar gedurende 1 cycle geblokkeerd, daarom komen voor het schrijven van de output-compare registers alleen de 16-bits instructies in aanmerking (zoals STD, STX of STY instructies.)

De namen van de verschillende bits en registers voor de 5 output-compares is volgens de volgende tabel:

systeem

OMx

OLx

OCxI

OCxF

register

pin

compare1

-

-

OC1I

OC1F

TOC1

PA7..PA3

compare2

OM2

OL2

OC2I

OC2F

TOC2

PA6

compare3

OM3

OL3

OC3I

OC3F

TOC3

PA5

compare4

OM4

OL4

OC4I

OC4F

TOC4

PA4

compare5

OM5

OL5

OC5I

OC5F

TOC5

PA3

Uit de bovenstaande tabel blijkt al, dat het mogelijk is meer dan één output-compare te laten werken op een bepaalde uitgang. Wanneer zowel output-compare 1 als een andere output-compare op hetzelfde moment een uitgang zouden willen veranderen, dan krijgt de uitgang de waarde zoals die is bepaald door output-compare 1. De andere output-compare heeft in dat speciale geval geen invloed.

Output-compare 5

Zoals gezegd heeft output-compare 5 een gedeelde plaats met een input-capture register. Of dit register als input-capture werkt, dan wel als output-compare, wordt bepaald door het I4O5 bit in het PACTL register. Door een '1' in dit bit te schrijven, wordt het register een output-compare register. Wanneer de micro-controller start, is het register als input-capture geconfigureerd.
Wanneer het register als output-compare geconfigureerd wordt, zal PA3 automatisch een uitgang zijn. Het DDRA3 bit in het PACTL register heeft dan geen invloed meer op PA3.

PA7

PA7 is behalve als uitgang voor output-compare 1 ook bestemd als ingang voor de pulsteller (zie verder.) Of PA7 een uitgang is of een ingang, wordt bepaald door het DDRA7 bit in het PACTL register. PA7 is een uitgang als dit bit een '1' gemaakt wordt. Als de micro-controller start, is PA7 als ingang geprogrammeerd.

Registers voor de besturing van de output-compares

De I/O registers die de bits bevatten voor de besturing van de output-compare timers zijn:

TCTL1 $1020

om2

ol2

om3

ol3

om4

ol4

om5

ol5

 

TMSK1 $1022

oc1i

oc2i

oc3i

oc4i

ic4i,oc5i

ic1i

ic2i

ic3i


TFLG1 $1023

oc1f

oc2f

oc3f

oc4f

ic4f,oc5f

ic1f

ic2f

ic3f


OC1M $100C

oc1m7

oc1m6

oc1m5

oc1m4

oc1m3

-

-

-

 

OC1D $100D

oc1d7

oc1d6

oc1d5

oc1d4

oc1d3

-

-

-

 

De I/O registers die de waarde bevatten die de free-running counter moet hebben voor het optreden van een output-compare zijn:

TOC1 $1016, $1017

bit15

bit14

bit13

bit12

bit11

bit10

bit9

bit8

bit7

bit6

bit5

bit4

bit3

bit2

bit1

bit0

 

TOC2 $1018, $1019

bit15

bit14

bit13

bit12

bit11

bit10

bit9

bit8

bit7

bit6

bit5

bit4

bit3

bit2

bit1

bit0

 

TOC3 $101A, $101B

bit15

bit14

bit13

bit12

bit11

bit10

bit9

bit8

bit7

bit6

bit5

bit4

bit3

bit2

bit1

bit0

 

TOC4 $101C, $101D

bit15

bit14

bit13

bit12

bit11

bit10

bit9

bit8

bit7

bit6

bit5

bit4

bit3

bit2

bit1

bit0

 

TIC4, TOC5 $101E, $101F

bit15

bit14

bit13

bit12

bit11

bit10

bit9

bit8

bit7

bit6

bit5

bit4

bit3

bit2

bit1

bit0

Output-compare forceren

Het is niet noodzakelijk dat de micro-controller afwacht totdat de waarde van de free-running counter gelijk wordt aan de waarde in één van de compare-registers voordat een output-compare optreedt.

Voor elk van de 5 output-compare registers is er in het CFORC register een bit aanwezig waarmee de compare voor één of meer van de output-compares onmiddelijk kan worden opgewekt. Als in één of meer van de FOCx bits een '1' wordt geschreven, treedt meteen de voor de betreffende output-compare(s) geprogrammeerde actie op. Voor output-compare 1 heet dit bit FOC1, voor compare 2 heet het bit FOC2, etc.

Het CFORC register ziet er als volgt uit:

CFORC $100B

foc1

foc2

foc3

foc4

foc5

-

-

-

Output-compare als timer

Hoewel de output-compare timers oorspronkelijk bedoeld zijn voor het genereren van uitgangs-pulsen, is dit niet strikt noodzakelijk. De timers kunnen ook gebruikt worden voor het genereren van een interrupt op regelmatige tijdstippen. Een alternatief hiervoor is de real Time Interrupr (RTI) Deze RTI interrupt heeft een beperkt aantal instelmogelijkheden voor de tijd tussen twee interrupts. De output-compare timers kunnen veel nauwkeuriger ingesteld worden. Met de klok voor de free-running counter op 2 MHz, kan de interrupt-tijd worden ingesteld in stapjes van 0.5µs. Hiervan wordt in het volgende programma gebruik gemaakt.

*************************************************
* definiëren van de geheugen map
*************************************************
		incl "map512.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
*************************************************
* output compare interrupt
*************************************************
PROGRAM		space
oc1start	equ $		|het beginadres van deze module
oc1time		equ 2000	|het aantal klokperioden per interrupt
				|een klokperiode duurt 0.5 micro?seconden
DATA		space
oc1count	rmb 1	|deze teller wordt bij elke interrupt verhoogd
oc1rate		rmb 1	|het aantal interrupts dat geteld wordt
* initialisatie van de output?compare interrupt
PROGRAM		space
		ldx #regsbeg	|IX wijst naar de I/O registers
		ldd #oc1intentry
		std toc1int+1	|die de interrupt afhandelt
		ldab #100	|initialiseer de snelheid
		stab oc1rate
		ldd tcnt	|haal de systeemtijd
		addd #oc1time	|en zet deze 'oc1time' verder voor de eerste
		std toc1	|interrupt, clear dan een eventuele interrupt
		ldab #oc1f
		stab tflg1	|en enable de interrupts van output?compare 1
		bset tmsk1+regsbeg,x,oc1i
		bra oc1end	|einde van de initialisatie
* subroutine voor de afhandeling van de output compare interrupt
PROGRAM		space
oc1intentry	equ $
		ldab #oc1f
		stab tflg1	|reset de interrupt?vlag
		inc oc1count	|en tel de interrupt
		ldd toc1	|haal de tijd op het moment van de interrupt
		addd #oc1time	|en zet deze 'oc1time' verder voor de volgende
		std toc1	|interrupt
		rti

VECTOR		space
		org oc1vec	|zet een vector in de interrupt vector tabel
		fdb oc1intentry
PROGRAM		space
***** output compare 1 interrupt interface routines
PROGRAM		space
* test op time?out. zet de zero?vlag indien er een time?out is.
checkoc1	equ $
		pshb
		sei		|houd interrupts tijdelijk tegen
		ldab oc1count	|kijk hoe vaak er een interrupt was
		subb oc1rate	|indien er minimaal 'oc1rate' interrupts
		blo checkoc19	|zijn geweest, dan is er een time-out en moet
		stab oc1count	|'oc1rate' van de teller worden afgetrokken
		clrb		|daarnaast moet de zero-vlag gezet worden
checkoc19	cli		|daarna kunnen de interrupts weer worden
		pulb		|doorgelaten
		rts
oc1end		equ $		|einde van de output?compare interrupt module
*************************************************
* LED's
*************************************************
PROGRAM space
ledstart	equ $		|het beginadres van deze module
ledport		equ porta
led1		equ bit6
led2		equ bit5
		ldx #regsbeg	|IX wijst naar de I/O registers
		bclr ledportx,x,(led2 or led1)
		bra ledend	|einde van de initialisatie
ledend equ $ |einde van de led module
* het aantal bytes dat deze module nodig heeft in het programma gebied
ledsize equ ledend?ledstart
*************************************************
* het hoofdprogramma
*************************************************
PROGRAM space
		cli		|laat de interrupts door
main0		jsr checkoc1
		bne main0	|wacht op een time-out van output-compare
		bclr ledportx,x,(led1)
main1		jsr checkoc1
		bne main1
		bset ledportx,x,(led1)
		bra main0	|herhaal dit oneindig
		end

De timing in dit programma wordt verzorgd door een output-compare. De output-compare module genereert elke milli-seconde een interrupt, en heeft een interface-routine die gebruikt kan worden om te controleren of een variabel ingesteld aantal van deze interrupts zijn opgetreden. Het hoofdprogramma reageert hierop door een LED te laten knipperen.


De output-compare interrupt module bevat de van modulen bekende onderdelen:

  • initialisatie

  • interne subroutines

  • interface routines

In de kop van de module wordt de PROGRAM pointer gekozen. Het eerste adres van de module krijgt een naam, zodat later (in de listing) te zien is op welk adres in het programmageheugen de module begint. Daarna wordt een constante gedefiniëerd die verderop in de module gebruikt wordt om de timing te bepalen.

Na selecteren van de DATA pointer wordt een byte gereserveerd dat wordt gebruikt om het aantal interrupts dat de output-compare heeft gegenereerd te tellen. Het aantal interrupts dat afgewacht moet worden voordat een time-out gedetecteerd wordt is opgeslagen in een variabele, zodat deze door het hoofdprogramma aangepast kan worden. Wanneer deze waarde aangepast wordt, zal een time-out eerder of later optreden, zodat de snelheid waarmee de LED gaat knipperen later eenvoudig veranderd kan worden.

Initialisatie

De initialisatie van de output-compare interrupt module zorgt voor:

  • invullen van de JMP instructie in de interrupt tabel

  • instellen van de interrupt tijd

  • aanzetten van de output-compare interrupts

De routine die de interrupt afhandelt heet in het programma 'oc1intentry'. Het adres van deze routine wordt in de interrupt vector tabel gezet.

De interrupt tijd wordt ingesteld, door de variabele die de time-out waarde vastlegt, te laden met de beginwaarde 100. Een interrupt komt elke milli-seconde, dus 100 interrupts duren 100 milli-seconde.

De eerste interrupt wordt gegeven, precies 1 milli-seconde nadat de volgende instructies worden uitgevoerd. De waarde van de vrijlopende teller wordt gelezen en met 2000 verhoogd. De resulterende waarde wordt in het output-compare register gezet, dus wanneer de vrijlopende teller 2000 stapjes verder is zal de eerste compare optreden.

Daarna wordt de interrupt-vlag van output-compare 1 gereset, en de interrupts van output-compare 1 worden vrijgegeven.

Bedenk, dat het I-bit in het CCR nog niet op '0' gezet is. Ofschoon de output-compare interrupt 'lokaal' vrijgegeven is, wordt de interrupt nog steeds geblokkeerd door het I-bit.

Na de initialisatie wordt uit de module gesprongen.

De output-compare interrupt module heeft één interne subroutine. Deze subroutine wordt door de output-compare 1 interrupt geactiveerd. Dus elke milli-seconde krijgt de processor een interrupt, zoekt uit dat de interrupt van output-compare 1 komt, en springt naar het betreffende adres dat in de vector tabel staat.

De interrupt handler routine zet de interrupt-vlag van de output-compare interrupt weer uit, en verhoogt de interrupt teller. Wanneer de interrupts niet langdurig geblokkeerd zijn, wordt deze teller dus elke milli-seconde met één verhoogd. Daarna leest de routine op welk tijdstip de interrupt werd gegenereerd (dit is de inhoud van het compare-register), en verhoogt deze tijd met 1 milli-seconde. Daardoor zal de volgende interrupt precies 1 milli-seconde na de vorige gegenereerd worden.

Als de interrupts tijdelijk geblokkeerd zijn (via het I-bit) terwijl de output-compare interrupt wel 'afloopt', springt de processor niet naar de afhandelingsroutine. Daardoor blijft de interrupt-vlag een '1'. De interrupt blijft dus aktief, maar wordt (nog) niet afgehandeld. Zodra het I-bit de interrupts weer doorlaat, is de interrupt aanvraag er al, en wordt dan meteen afgehandeld. Door dit mechanisme is het veilig de interrupts tijdelijk te blokkeren. De aanvraag voor een interrupt blijft actief totdat de interrupt afgehandeld is. Daardoor zullen er geen interrupts verloren gaan.

De interface routine is de routine die bedoeld is om door het hoofdprogramma te worden aangeroepen. In dit voorbeeld moet het hoofdprogramma uitzoeken of het al tijd is de LED aan- of uit te zetten. De interface routine wordt vanuit het hoofdprogramma aangeroepen, en wanneer de routine de Z-vlag in het CCR een '1' maakt, is dit een teken dat het tijd is voor een LED knipper.

De routine bewaart het register dat intern gebruikt wordt (B) op de stack. Daarna wordt de inhoud van de interrupt-teller vergeleken met de waarde in de variabele die de knipper snelheid bepaalt. Door deze variabele een andere waarde te geven kan de knipper snelheid veranderd worden.

Als er voldoende interrupts geteld zijn (voldoende tijd verstreken is), wordt de verstreken tijd van de teller afgetrokken, en zet de routine de Z-vlag in het CCR. Als nog niet voldoende interrupts geteld zijn, wordt de Z-vlag een '0'. Aan het eind van de routine wordt register B weer hersteld door het van de stack te halen.

Met de 'sei' instructie bovenaan de routine worden de interrupts geblokkeerd, met de 'cli' instructie onderaan de routine worden de interrupts weer vrijgegeven. De reden hiervoor werd behandeld in 'Mutual Exclusion'.


Vorige ] Volgende ]

© 2005...2008 Elomax [Voorwaarden ]