Het gebruik van het Simplex3 68HC11 bord in het windmeter project.

© Harry Broeders. Laatste wijziging: 18 juli 2009

Deze pagina is bestemd voor EP1 studenten van de THRijswijk.

Inleiding.

Het windmeterproject wordt beschreven in het dictaat van het Ingenieurspracticum. Op deze webpagina kun je de benodigde software vinden. Je vind hier ook een beschrijving van de werking en enkele ideëen om deze windmetersoftware nog beter (of leuker) te maken. Het hart van de windmeter is de Simplex3 print met daarop de 68HC11 microcontroller. Aan dit bord wordt een door jou zelf gemaakt windmeterbordje gekoppeld. In het schema van het windmeterbordje kun je zien dat de puls afkomstig van de Hall sensor door het Simplex3 bord kan worden ingelezen via pin C25 van de connector. De led's kunnen door het Simplex3 bord worden aangestuurd via de pinnen A1 t/m A8 en A19 t/m A22 van de connector. In de beschrijving van de Simplex3 connector kun je opzoeken dat pin C25 van de connector verbonden is met pin PA2 van de 68HC11. Dit is een input capture ingang van de 68HC11 en met behulp van de input capture timer kunnen we de pulsduur van het signaal afkomsig van de Hall sensor bepalen. Ook kunnen we de pulsen op deze ingang gedurende een bepaalde tijd tellen. Maar hierover later meer. De pinnen A1 t/m A8 zijn verbonden met de pinnen PAA0 t/m PAA7 van de PSD 833F290J. De afkorting PSD betekent in dit geval Programmable System Device (en dus niet Programma Structuur Diagram). De pinnen A19 t/m A22 zijn verbonden met PPB0 t/m PPB3 van de PSD. Deze PSD is een vrij ingewikkelde component waarin verschillende soorten geheugen (RAM en EEPROM), verschillende I/O poorten, een aantal configureerbare logische blokken en een JTAG interface om deze blokken te configureren op één chip zijn geïntegreerd. De datasheet van deze component is veel te ingewikkeld om nu (in de P fase) al te kunnen begrijpen. Wij gebruiken alleen de A en B Input/Output poorten van deze chip en het RAM geheugen om ons programma te testen. Er zijn C functies beschikbaar om naar de A en B poorten van de PSD te schrijven. RAM staat voor Random Access Memory en dit is geheugen dat zowel gelezen als beschreven kan worden maar dat zijn informatie verliest als de spanning wegvalt. Tijdens het testen gebruik je het RAM geheugen van de PSD om je programma in op te slaan. Je kunt het programma later ook in het EEPROM geheugen van de PSD laden. EEPROM staat voor Electrically Erasable Programmable Read Only Memory dit geheugen kan alleen uitgelezen worden en niet worden beschreven. Wel kan dit geheugen op een speciale manier worden geladen (geprogrammeerd) en ook kan het indien nodig weer worden gewist (niet per byte maar in blokken).  Als je programma in het EEPROM geheugen geladen is hoef je het niet opnieuw te laden als de spanning wegvalt.

Test programma om de LED's aan te sturen.

We beginnen met een programma waarmee we de A en B poort van de PSD kunnen aansturen om de led aansturing te kunnen testen. Let op! De 68HC11 heeft zelf ook I/O poorten waaronder ook een A en B poort maar deze 68HC11 I/O poorten worden in dit eerste testprogramma niet gebruikt. De PSD op het Simplex3 bordje is zodanig geconfigureerd dat de A en B poorten van de PSD eenvoudig als input of als output te gebruiken zijn. In het zogenaamde Direction registers van de PSD kun je voor elke pin van poort A en poort B aangeven of deze pin als input (default) of als output wordt gebruikt. Vervolgens kun de Data In registers van de PSD gebruiken voor invoer en de Data Out registers voor output. Een overzicht van deze registers, met de adressen waar deze registers zich in de memory map van het Simplex bord, kun je vinden in de onderstaande tabel.

Registers voor het besturen van poort A en B van de PSD
Naam Adres Beschrijving
Data In A $1200 Via dit register kun je de pinnen van poort A inlezen.
Data In B $1201 Via dit register kun je de pinnen van poort B inlezen.
Data Out A $1204 Via dit register kun je de output pinnen van poort A aansturen.
Data Out B $1205 Via dit register kun je de output pinnen van poort B aansturen.
Direction A $1206 Via dit register kun je voor elke pin van poort A aangeven of het een input (0) of output (1) pin moet zijn.
Direction B $1207 Via dit register kun je voor elke pin van poort B aangeven of het een input (0) of output (1) pin moet zijn.

Het PSD (Programma Structuur Diagram) van een eenvoudig programma om leds te testen ziet er als volgt uit.

In 68HC11 assemblertaal kan dit als volgt (testleds.asm) geïmplementeerd worden:

doa	equ	$1204		Data Out A register van de PSD
dob	equ	$1205		Data Out B register van de PSD
da	equ	$1206		Direction A register van de PSD
db	equ	$1207		Direction B register van de PSD
	
	org	$2000
	ldaa	#$ff
	staa	da		PPA0 t/m PPA7 output
	ldaa	#$0f
	staa	db		PPB0 t/m PPB3 output, PPB4 t/m PPB7 input (niet gebruikt)	
lus	ldaa	#%01010101
	staa	doa		PPA0, PPA2, PPA4 en PPA6 aan rest uit
	ldaa	#%00000101
	staa	dob		PPB0 en PPB2 aan rest uit
	jsr	wacht
	ldaa	#%10101010
	staa	doa		PPA0, PPA2, PPA4 en PPA6 uit rest aan
	ldaa	#%00001010
	staa	dob		PPB0 en PPB2 uit rest aan
	jsr	wacht
	bra	lus

wacht	ldx	#$ffff		wacht enige tijd
nog	dex
	bne	nog
	rts

Hoe je een programma met behulp van THRSim11 op je Simplex3 bord kan draaien kun je lezen op: http://bd.eduweb.hhs.nl/simplex3. Als het goed gaat zie je afwisseld de even en de oneven ledjes branden (misschien kan je dit programma gebruiken als je de windmeter met Kerst in de boom hangt ;-).

In C kan dit als volgt (testleds.c) geïmplementeerd worden:

typedef unsigned char byte;

void wacht() {
        /* hou de processor even bezig... */
        int i;
        for (i=0; i<10000; ++i) {
                /* niets */
        }
}

int main() {
        volatile byte* doa=(byte*)0x1204;
        volatile byte* dob=(byte*)0x1205;
        volatile byte* da= (byte*)0x1206;
        volatile byte* db= (byte*)0x1207;
        
        *da=0xff;
        *db=0x0f;
        
        while (1) {
                *doa=0x55;
                *dob=0x05;
                wacht();
                *doa=0xaa;
                *dob=0x0a;
                wacht();
        }
        
        return 0;
}

Verklaring:

Hoe je een programma met behulp van THRSim11 op je Simplex3 bord kan draaien kun je lezen op: http://bd.eduweb.hhs.nl/simplex3. Om het programma te kunnen compileren kun je de volgende makefile en het linker script simplex3.ld gebruiken.

Misschien is het je opgevallen dat het Data Out A en het Data Out B register achter elkaar in de memory map staan. Dit zelfde geldt voor de Direction registers. We kunnen twee 8 bits registers die achter elkaar in de memory map staan benaderen alsof het één 16 bits register is.

16 bits Registers voor het besturen van poort A en B van de PSD
Naam Adres Beschrijving
Data In $1200 Via dit register kun je de pinnen van poort A (hoge deel) en B (lage deel) inlezen.
Data Out $1204 Via dit register kun je de output pinnen van poort A (hoge deel) en B (lage deel) aansturen.
Direction $1206 Via dit register kun je voor elke pin van poort A en B aangeven of het een input (0) of output (1) pin moet zijn.

Het 68HC11 assemblertaal om de leds te testen kan nu eenvoudiger als volgt (testleds.asm) geïmplementeerd worden:

doab	equ	$1204		Data Out AB register van de PSD
dab	equ	$1206		Direction AB register van de PSD
	
	org	$2000
	ldx	#$ff0f
	stx	dab		PPA0 t/m PPA7 en PPB0 t/m PPB3 output, PPB4 t/m PPB7 input	
lus	ldx	#%0101010100000101
	stx	doab		PPA0, PPA2, PPA4, PPA6, PPB0 en PPB2 aan rest uit
	jsr	wacht
	ldx	#%1010101000001010
	stx	doab		PPA0, PPA2, PPA4, PPA6, PPB0 en PPB2 uit rest aan
	jsr	wacht
	bra	lus

wacht	ldx	#$ffff		wacht enige tijd
nog	dex
	bne	nog
	rts

In C kan het programma nu ook eenvoudiger geïmplementeerd worden (testleds.c):

typedef unsigned short word;

void wacht() {
        /* hou de processor even bezig... */
        int i;
        for (i=0; i<10000; ++i) {
                /* niets */
        }
}

int main() {
        volatile word* doab=(word*)0x1204;
        volatile word* dab= (word*)0x1206;
        
        *dab=0xff0f;
        
        while (1) {
                *doab=0x5505;
                wacht();
                *doab=0xaa0a;
                wacht();
        }
        
        return 0;
}

Testprogramma voor de timing.

Om de windsnelheid te kunnen meten moet je de pulsjes afkomstig van de Hall sensor een bepaalde tijd kunnen tellen. Om een bepaalde tijdsduur te wachten maken we gebruik van de zogenaamde "Real Time" counter van de 68HC11. Deze counter zal telkens na 4.096 ms (later in H1 zul je leren dat deze waarde instelbaar is) het zogenaamde bit RTIF uit het TFLG2 register van de 68HC11 setten. We kunnen dit bit weer resetten door er een 1 naar toe te schrijven. Nee, dat is geen typefout! Je maakt het RTIF bit 0 door er een 1 naar toe te schrijven, raar maar waar. Dit is te vergelijken met een repeterende wekker die telkens na een bepaalde tijd weer afloopt en die je telkens kunt uitdrukken (je kent dat wel;-). Door nu te tellen hoeveel maal deze "wekker" is afgelopen kun je de verstreken tijd bepalen. Het TFLG2 register bevindt zich op adres $1025 van de memory map en bit RTIF is bit 6 van dit register.

In het assembler testprogramma voor de leds kan nu telkens een halve seconde worden gewacht door de subroutine wacht als volgt aan te implementeren (testleds.asm):

wacht	ldaa	#122		wacht 122 * 4.096 ms = (ongeveer) 0.5 sec 
nog	ldab	$1025
	andb	#%01000000
	beq	nog		wacht tot RTIF = 1
	ldab	#%01000000
	stab	$1025		maak RTIF 0 (door er een 1 naar toe te schrijven)
	deca			wacht 122 keer
	bne	nog
	rts

In C kan de functie wacht dan als volgt geïmplementeerd worden (testleds.c):

typedef unsigned char byte;

void wacht() {
        /* hou de processor 0.5 sec bezig... */
        volatile byte* tflg2=(byte*)0x1025;
        byte i;
        for (i=0; i<122; ++i) {
                while ((*tflg2&0x40)!=0x40) {
                        /* niets */
                }
                *tflg2=0x40;
        }
}

Testprogramma voor de Hall sensor.

Het van de Hall sensor afkomstige pulsvormige signaal is aangesloten op ingangspin PA2 van de 68HC11. Elke keer dat de windmeter een rondje draait zal de Hall sensor een puls afgeven. De Input Capture Timer van de 68HC11 kan zo ingesteld worden dat het bit ICF1 uit het TFLG1 register van de 68HC11 wordt geset bij een opgaande flank op de PA2 ingang. Met behulp van de Input Capture Timer van de 68HC11 kunnen we ook de tijdsduur tussen 2 pulsen meten maar daar maken we nu geen gebruik van (dat leer je later in H1 bij de onderwijsmodule MICB1). Het TFLG1 register bevindt zich op adres $1023 van de memory map en bit IC1F is bit 2 van dit register. Je maakt het IC1F bit 0 door er een 1 naar toe te schrijven, raar maar daar ben je nu wel aan gewend. Om de Input Capure timer het IC1F bit bij elke opgaande flank van PA6 te laten setten moet de waarde $10 naar het TCTL2 register (adres $1021) van de 68HC11 worden geschreven.

Door nu in de wacht subroutine van het testleds.asm programma niet meer een vaste tijd te wachten maar te wachten totdat een opgaande flank op de PA2 ingang is gedetecteerd zullen de leds "verspringen" als de windmeter een rondje heeft gedraaid.

doab	equ	$1204		Data Out AB register van de PSD
dab	equ	$1206		Direction AB register van de PSD
	
	org	$2000
	ldaa	#$10
	staa	$1021		zorg ervoor dat IC1F 1 wordt bij een opgaande flank op PA2
	ldx	#$ff0f
	stx	dab		PPA0 t/m PPA7, PPB0 t/m PPB3 output, PPB4 t/m PPB7 input
lus	ldx	#%0101010100000101
	stx	doab		PPA0, PPA2, PPA4, PPA6, PPB0 en PPB2 aan rest uit
	jsr	wacht
	ldx	#%1010101000001010
	stx	doab		PPA0, PPA2, PPA4, PPA6, PPB0 en PPB2 uit rest aan
	jsr	wacht
	bra	lus

wacht	ldab	$1023		
	andb	#%00000100
	beq	wacht		wacht tot IC1F = 1
	ldab	#%00000100
	stab	$1023		maak IC1F 0 (door er een 1 naar toe te schrijven)
	rts

In C kan dit als volgt geïmplementeerd worden (testleds.c):

typedef unsigned char byte;
typedef unsigned short word;

void wacht() {
        /* wacht op een opgaande flank van PA2 (Hall sensor) */
        volatile byte* tflg1=(byte*)0x1023;
        while ((*tflg1&0x04)!=0x04) {
                /* niets */
        }
        *tflg1=0x04;
}

int main() {
        volatile byte* tctl2=(byte*)0x1021;
        volatile word* doab=(word*)0x1204;
        volatile word* dab= (word*)0x1206;
        
        *tctl2=0x10;
        *dab=0xff0f;
        
        while (1) {
                *doab=0x5505;
                wacht();
                *doab=0xaa0a;
                wacht();
        }
        
        return 0;
}

TODO: Onderstaand probleem oplossen!

Hmmm... is die hardware wel OK. Als de windmeter stil staat met de magneet voor de Hall sensor dan wordt een mooie "pulstrein" opgewekt. Als de windmeter traag draait ontstaat ook een "pulstreintje" van enkele pulsen (meestal 2) als de magneet de sensor passeerd. Als de windmeter wat sneller draait komt er wel netjes 1 puls uit.

De windsnelheidsindicator.

Door nu het tellen van Real Time counter "perioden" en het tellen van pulsen van de Hall sensor met elkaar te combineren kun je een programma maken waarmee een indicatie voor de windsnelheid op de leds wordt weergegeven.

Windmeter variabelen tabel
naam type omschrijving
IC1F bit bit 2 in het TFLG1 register van de 68HC11 wordt gebruikt om pulsen afkomstig van de Hall sensor te tellen
RTIF bit bit 6 in het TFLG2 register van de 68HC11 wordt elke 4.096 ms geset en wordt gebruikt om 2 s af te tellen
pulsen word hierin wordt het aantal pulsen, gedurende 2 s, afkomstig van de Hall sensor geteld
RT_perioden word hierin wordt het aantal Real Time perioden geteld. 1 periode = 4.096 ms dus 488 perioden = 488 * 4.096 = ongeveer 2 s
aantal_leds word het aantal_leds wat moet branden, wordt elke 2 s berekend met behulp van de waarde van pulsen
patronen word[13] op plaats X in deze array staat het patroon om de eerste X leds te laten branden (X = 0 t/m 12)
led_partoon word patroon dat naar de leds wordt gestuurd, wordt elke 2 s gelijk gemaakt aan patronen[aantal_leds]

In C kan dit als volgt geïmplementeerd worden (windmeter.c):

typedef unsigned char byte;
typedef unsigned short word;

int main() {
        volatile byte* tctl2=(byte*)0x1021;
        volatile word* dab= (word*)0x1206;
        *tctl2=0x10;
        *dab=0xff0f;
        while (1) {
                volatile byte* tflg1=(byte*)0x1023;
                volatile byte* tflg2=(byte*)0x1025;
                volatile word* doab=(word*)0x1204;
                word pulsen=0, RT_perioden=488, aantal_leds;
                word patronen[13]={0x0000, 0x0100, 0x0300, 0x0700,
                        0x0f00, 0x1f00, 0x3f00, 0x7f00, 0xff00,
                        0xff01, 0xff03, 0xff07, 0xff0f};
                do {
                        if ((*tflg1&0x04)==0x04) {
                                *tflg1=0x04;
                                pulsen=pulsen+1;
                        }
                        if ((*tflg2&0x40)==0x40) {
                                *tflg2=0x40;
                                RT_perioden=RT_perioden-1;
                        }
                }
                while (RT_perioden!=0);
                aantal_leds=pulsen*25/100; /* nog afregelen! */        
                if (aantal_leds>12) {
                        aantal_leds=12;
                }
                *doab=patronen[aantal_leds];
        }
        return 0;
}

In 68HC11 assembler kan dit als volgt geïmplementeerd worden (windmeter.asm):

doab	equ	$1204		Data Out AB register van de PSD
dab	equ	$1206		Direction AB register van de PSD
tctl2	equ	$1021		TCTL2 register van de 68HC11
tflg1	equ	$1023		TFLG1 register van de 68HC11
tflg2	equ	$1025		TFLG2 register van de 68HC11

	org	$2000
	ldx	#$ff0f
	stx	dab		PPA0 t/m PPA7, PPB0 t/m PPB3 output, PPB4 t/m PPB7 input
	ldaa	#$10		zorg ervoor dat IC1F 1 wordt bij een opgaande flank op PA2
	staa	tctl2		herhaal voor altijd {
*				   herhaal {	
lus	clrb			      zet pulsen teller op 0
	ldx	#488		      zet rtperiode teller op 488 (488*4.096 ms = ongeveer 2 s)
test	ldaa	tflg1		
	anda	#%00000100
	beq	npuls		      als IC1F == 1 {
	ldaa	#%00000100	         maak IC1F 0 (door er een 1 naar toe te schrijven)
	staa	tflg1		
	incb			         verhoog pulsen teller met 1
npuls	ldaa	tflg2		      }
	anda	#%01000000
	beq	test		      als RTIF == 1 {
	ldaa	#%01000000	         maak RTIF 0 (door er een 1 naar toe te schrijven)
	staa	tflg2		
	dex			         verlaag rtperiod teller met 1
	bne	test		      }
	ldy	#tabel		   } zolang rtperiod teller ongelijk aan 0
	ldaa	#25		   aantal leds = aantal pulsen * 25 / 100 (nog afregelen!)
	mul
	ldx	#100
	idiv
	xgdx
	cmpb	#12		   als aantal leds > 12 {
	bls	ok		      aantal leds = 12
	ldab	#12		   }	
ok	aby			   zet aantal leds om naar patroon voor om leds aan te sturen
	aby			   met behulp van "look up table"
	ldx	0,y
	stx	doab		   stuur patroon naar leds
	bra	lus		}
*
tabel	fdb	%0000000000000000,%0000000100000000,%0000001100000000,%0000011100000000
	fdb	%0000111100000000,%0001111100000000,%0011111100000000,%0111111100000000
	fdb	%1111111100000000,%1111111100000001,%1111111100000011,%1111111100000111
	fdb	%1111111100001111

Nog doen!

Mogelijke uitbreidingen:

Mogelijke verbeteringen:

In het eerste semester en tweede semster van de hoofdfase (H1 en H2) leer je nog veel meer over microcontrollers in het algemeen en de 68HC11 in het bijzonder. Als je de onderwijsmodulen MICB1 en MICB2 volgt zal blijken dat er nog andere (betere) mogelijkheden zijn: