© Harry Broeders. Laatste wijziging: 18 juli 2009
Deze pagina is bestemd voor EP1 studenten van de THRijswijk.
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.
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.
| 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.
| 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;
}
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;
}
}
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.
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.
| 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!
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: