8051 Microcontroller Embedded Systemen Een gids voor XC888 toepassingen.

Maat: px
Weergave met pagina beginnen:

Download "8051 Microcontroller Embedded Systemen Een gids voor XC888 toepassingen."

Transcriptie

1 8051 Microcontroller Embedded Systemen Een gids voor XC888 toepassingen. Versie: /10/ /07/ /07/2014 Auteurs: Pauwels D. Roggemans M.

2 Inhoudsopgave: Inhoudsopgave:... 2 Inleiding... 9 Hoofdstuk 1 Historiek Inleiding Historiek Hoofdstuk 2 Embedded systemen Inleiding Wat is er uniek aan het ontwerp van embedded systemen? Hoe krachtig zijn embedded processoren? Embedded systemen werken meestal "REAL-TIME" Een typisch microprocessorsysteem MTBF Ontwerp van een PCB Overige nadelen Een microcontroller systeem Wat is er op de markt? Een voorbeeld uit elke categorie Bit controller: EM Bit controller: XC bit controller: XC167 van Infineon Bit controller: De MB91F361 van Fujitsu Hoofdstuk hardware Inleiding De oorspronkelijke 8051 architectuur Memory map van de 8051 CPU De inwendige geheugenruimte De externe systeemarchitectuur De externe geheugenruimte De bus architectuur De externe timing I/O systemen Mapping/Paging van SFR s (XC888) HOOFDSTUK 4 De 8051 instructieset Inleiding De CPU en zijn basisregisters De PSW Adresseringsmethoden Algemeen Voorbeelden MOV A,#03FH MOV A,03FH MOV A,Rn MOV A,@Ri MOVX A,@DPTR MOVC A,@A+DPTR MOVX A,@Ri... 64

3 Voorbeeldprogramma s algemene opmerkingen en eerste voorbeeld: LJMP 16bit_address naam EQU getal naam DATA getal naam BIT getal Voorbeeldprogramma EQU: Wiskundige instructies Inleiding Overzicht talstelsels: ADD(C) Voorbeeld van een 8 bit optelling Voorbeeld van een 16 bit optelling SUBB Voorbeeld van een 8 bit verschil Voorbeeld van een 16 bit verschil INC/DEC Voorbeeld inc en dec instructies INC DPTR MUL AB Voorbeeld mul instructie DIV AB DA A Logische instructies Inleiding ANL/ORL/XRL Voorbeelden orl,anl,xrl Specifieke accumulator instructies CLR A CPL A Voorbeelden Rotate Voorbeelden RL, RR, RLC en RRC SWAP A Voorbeeld SWAP A Verplaats instructies De exchange instructie De systeemstack, stackpointer en de PUSH / POP instructies De systeemstack en stackpointer (call instructies) Push en POP instructies PUSH register POP register Voorbeelden push en pop Voorbeeld gebruik stack Bit manipulaties Inleiding Berekeningen op bit variabelen Voorbeelden van bewerkingen op bitvariabelen Programma- en machinecontrole Inleiding Jump instructies

4 LJMP Voorbeeld van een ljmp AJMP Relatieve sprong instructies SJMP Voorbeeld sjmp instructie Relatieve voorwaardelijke sprong instructies JC JNC JB JNB JBC JZ JNZ CJNE Extra mogelijkheid CNJE instructie DJNZ Voorbeelden van spronginstructies De (L)CALL instructie De NOP instructie Uitvoeringstijd van een instructie Hoofdstuk 5 Toepassingen Inleiding I/O driver xcez1.inc Inleiding LED s en dipswitch Voorbeeld initialisatie LED s en schakelaars (onvolledig) Voorbeeld initialisatie LED s en schakelaars (volledig) Testprogramma kopieer schakelaars naar de LED s Testprogramma met xcez1.inc driver Functie toetsen Van schakelaar tot keyboard, algemeenheden De keyboard hardware basics Een matrix (keyboard) scanning algoritme LCD scherm Voorbeelden gebruik LCD display, backlight en buzzer: db In/uit schakelen backlight/buzzer I2C bus Voorbeeldprogramma 1 uitlezen LM Voorbeeldprogramma 2 uitlezen LM ADC Voorbeeldprogramma inlezen potentiometer SIO Voorbeeldprogramma SIO/UART Wiskundige berekeningen Voorbeeldprogramma wiskundige routines Diverse Tips en trucs Inleiding

5 5.3.2 Software tijdsvertraging Voorbeeldprogramma looplicht met software tijdsvertraging Aanmaken en uitlezen van tabellen Voorbeeldprogramma: looplicht met tabel (tellen aantal bytes in tabel) Voorbeeldprogramma: looplicht met tabel (verboden code) Voorbeeldprogramma: afdrukken tekst uit tabel (PC of LCD) Een tabel gebruiken om te vertalen voor linearisering HEX, BCD, BIN inlezen en uitschrijven Omrekening HEX naar BCD Omrekening BCD naar HEX Vermenigvuldigen en delen van grote getallen Vierkantswortel berekenen Referenties naar de ftp site Hoofdstuk 6 XC888 hardware units Inleiding Interrupt Inleiding Interrupt bronnen Interrupt vectoren Interrupt prioriteit Interrupt initialisatie Vormvereisten interrupt routines Voorbeeld van programma met een timer 0 interrupt Voorbeeldprogramma uurwerk Timer0 en timer Inleiding bit timer/counter bit timers: periodemeting bit genereren van periodische timeroverflows of 'timeticks' bit auto reload mode bit TIMER met autoreload voor het genereren van timeticks Controleregisters Timer2 en timer Inleiding Basis counter T Auto reload mode en toepassingen Capture mode Controleregisters Capture/Compare Unit 6 (CCU6) Inleiding PWM sturing UART en UART Inleiding Baud rate generator SFR registers UART Voorbeeldprogramma initialisatie subroutine UART 9600 baud Voorbeeldprogramma zenden 1 byte Voorbeeldprogramma ontvangen 1 byte LIN interface SSC

6 6.7.1 Inleiding Controleregisters CAN Inleiding CAN SFR s Analoog naar digitaal omvormer (ADC) Inleiding ADC instellingen en gebruik Voorbeeldprogramma ADC MDU Inleiding Werking en gebruik van de MDU XCEZ1 driver en MDU CORDIC Inleiding CORDIC werking in de rotation mode A) Vectorrotatie over een hoek B) Rotatie van de eenheidsvector over een hoek C) Opdeling van de hoek in en aantal (getabuleerde) subhoeken D) De iteratie procedure E) Vereenvoudigingen voor de hardware-implementatie CORDIC werking in vector mode A) Bepaling van ARCSIN via CORDIC B) Bepaling van ARCCOS via CORDIC Uitbreiding van CORDIC naar lineaire en hyperbolische functies A) Berekening van lineaire functies met CORDIC (m=0) B) Berekening van hyperbolische functies met CORDIC (m=-1) WDT Inleiding SFR s en instellingen watchdog OCDS inleiding ROM floating point routines Inleiding Rom routines en hun gebruik FP-notatie Low power modes Inleiding Uitschakelen onderdelen microcontroller Algemene low power modes De ACTIVE mode De IDLE mode De POWER-DOWN mode De SLOW-DOWN mode Stroomverbruik XC Flash als data opslag Inleiding IAP (in application programming) Systeem klok Inleiding

7 Blokdiagram klokgenerator Klokgenerator na reset Omschakelen tussen RC en kristal Voorbeeldprogramma omschakelen RC naar kristal 12MHz Besluit & bedenkingen Appendix A XC888 instructionset (snel geheugen) Appendix B XC888 instructionset (reële core) Appendix C SFR pages (XC888) Appendix D xcez0.inc functies beknopt Appendix E ASCII code tabel Bronvermelding:

8 8

9 Inleiding Deze cursus kan gebruikt worden als zelfstudiemateriaal of als gids bij het volgen van de lessen. In beide gevallen is de aangereikte informatie slechts indicatief en niet algemeen toepasbaar. De auteur kan ook niet aansprakelijk gesteld worden voor eventuele onjuistheden die in het cursus materiaal zijn geslopen. Het is dus noodzakelijk voor elke specifieke toepassing het nodige opzoekwerk en berekeningen uit te voeren. Het WWW kan hierbij een nuttige bron van bijkomende informatie zijn. Gelet op het algemene karakter van de aangeboden informatie zal de cursist de nodige kritische ingesteldheid moeten tonen bij het verwerken ervan. Dit is ook zo bij het verwerken van informatie die via andere bronnen bekomen wordt. De cursus bevat informatie die op verschillende controllers/computers toepasbaar is. De familie van 8051 microcontrollers staat centraal. Meer specifiek wordt de XC888 microcontroller van Infineon als voorbeeld gebruikt. De beoordeling van het vak verloopt via een praktijkexamen. De student moet een professionele oplossing kunnen aanreiken voor gerelateerde problemen. Dit houdt in (indien van toepassing) een schema opstellen, verklaren van de principiële werking en verduidelijken van gebruikte begrippen, het opstellen van een flowchart, schrijven en debuggen van een programma. Het is duidelijk dat een combinatie van verschillende technieken noodzakelijk kan zijn. De wijze van evaluatie is voor alle types van studiecontracten, en voor alle evaluatieperiodes dezelfde. Door de uitvoerige bespreking van die voorbeelden tijdens de hoorcolleges willen we een kritische ingesteldheid aanmoedigen. Een actieve participatie aan de lessen is dan ook aanbevolen. De cursus is bedoeld, tijdens en na de studies, als naslagwerk. Eventuele constructieve kritiek en voorstellen tot aanvulling/aanpassing zijn steeds welkom. De voorbeelden in de cursus gebruiken directieven en include files die afhankelijk zijn van de gebruikte software op de PC (IDE), of de beschikbare versie van de betreffende bestanden (include files). In de lessen wordt de uitleg gegeven i.f.v. de op dat ogenblik gebruikte IDE en versie van bestanden. 9

10 Hoofdstuk 1 Historiek 1.1 Inleiding Alvorens dieper in te gaan op de 8051 familie van microcontrollers, en meer specifiek de XC888 van Infineon, willen we kort een overzicht geven van de evolutie op gebied van computers. Deze technologie is (zoals de meeste technologieën) vrij recent en in continue evolutie. Vooral de miniaturisatie en het gebruik van halfgeleiders heeft de weg geëffend voor het algemeen gebruik ervan. 1.2 Historiek Computers vinden hun oorsprong is de noodzaak om berekeningen sneller te kunnen maken, maar evenzeer uit de behoefte om productieprocessen te automatiseren. In figuur wordt een telraam weergegeven. Het is een mechanisch hulpmiddel dat vandaag de dag nog steeds in gebruik is. Figuur Telraam De eerste geautomatiseerde rekenmachines dateren van de 17 e eeuw. In 1642 doet Blaise Pascal een poging met de niet erg betrouwbare Pascaline (figuur 1.2.2). Beide apparaten zijn bedoeld om getallen te manipuleren. De sturing van een weefgetouw (figuur 1.2.3), ontworpen door Basil Bouchon kon met ponskaarten bediend worden en was ontworpen om een productieproces te automatiseren. Door beide systemen te combineren ontstaan de eerste computers die de elementaire onderdelen bevatten die we tot op vandaag in moderne computers terugvinden. 10

11 Figuur De Pascaline Figuur Weefgetouw In het begin van de 20 e eeuw ontstaan computers die elektromechanisch zijn opgebouwd, en tegen WWII worden elektronenbuizen gebruikt als schakelelementen 11

12 Figuur laat de architectuur en praktische uitwerking zien van de computer die door Konrad Zuse werd gebouwd. Figuur Konrad Zuse (WWII) 12

13 Het blokdiagram van de architectuur van de Z3 is principieel nog steeds van toepassingen op alle moderne computersystemen. In de Verenigde Staten (1944) wordt de Harvard Mark 1 ontworpen door IBM (figuur 1.2.5). Het toestel weegt 5 ton en bevat ongeveer componenten. Hij is in staat om in 0.3 seconden een optelling uit te voeren. Voor een vermenigvuldiging zijn er 6 seconden nodig. De computer bestaat hoofdzakelijk uit (elektro)mechanische onderdelen. De computer bleef in gebruik tot Hij was gemiddeld 1 keer per week defect. Figuur Harvard Mark 1 Door het vervangen van elektronenbuizen door geïntegreerde schakelingen (IC s) werden de systemen compacter, daalde het stroomverbruik en verhoogde de rekensnelheid. Door de hogere MTBF van halfgeleiderschakelingen t.o.v. elektronenbuizen nam ook de betrouwbaarheid enorm toe. Vanaf ongeveer 1975 komen er computers op de markt die betaalbaar zijn voor het brede publiek (figuur 1.2.6). Vanaf dan zal de steeds verder doorgedreven miniaturisatie er voor zorgen dat de systemen evolueren naar de mogelijkheden die we vandaag kennen. Hierbij maken we een belangrijk onderscheid tussen computersystemen en embedded systemen. In figuur is het algemeen blokschema van een computer weergeven. Dit is van toepassing op beide systemen. In het volgende 13

14 hoofdstuk gaan we verder in op het onderscheid tussen beide benaderingen van het begrip computer. Figuur :Tandy TRS80 (kostprijs 600$) X-tal Osc. POR ADRES DECODER ADRESBUS CPU ROM (FLASH) (EPROM) (EEPROM) SRAM PAR. POORT SER. POORT TIMER COUNTER DATABUS Figuur Algemeen blokschema van een computer 14

15 Hoofdstuk 2 Embedded systemen 2.1 Inleiding Embedded systemen zijn elektronische systemen waarin computers zijn verwerkt, zonder dat de gebruiker hiervan kennis moet hebben. Het embedded systeem is de elektronische schakeling die in het apparaat is ingebouwd, en verantwoordelijk is voor de besturing. Het is best mogelijk dat er in 1 toestel meerdere embedded systemen zijn ingebouwd. Een voorbeeld hiervan is een auto (figuur 2.1.1) Figuur Embedded systemen in een auto We worden omringd door een groot aantal embedded systemen die we onbewust gebruiken, en die een grote impact hebben op ons dagelijks leven. Je kan nauwelijks nog een toestel bedenken waar geen computer bijdraagt tot de werking of de bediening. Keukentoestellen, audio- en video applicaties, voertuigen, communicatieapparatuur, werktuigen en machines, Vaak zijn we afhankelijk van het correct functioneren van deze schakelingen. 15

16 Door computers in te bouwen in applicaties worden een aantal streefdoelen bereikt: vereenvoudigen van het systeemontwerp flexibiliteit in bediening en werking het drukken van de kostprijs per systeem verhogen van het bedieningscomfort verhogen van de functionaliteit optimalisatie van rendement Door de besturing van het apparaat via een computer te laten verlopen volstaat een eenvoudige aanpassing van de software (firmware = software die instaat voor de besturing van het computersysteem, en door de gebruiker niet aangepast wordt) om: tekortkomingen te verbeteren mogelijkheden van het toestel aan te passen De hedendaagse embedded systemen zijn zo goedkoop geworden dat ze bijna in elk toestel zitten dat we gebruiken. Onze desktop PC is ontworpen om verschillende toepassingen uit te voeren zoals versturen, tekstverwerking doen, spreadsheets en databases raadplegen. De gebruiker kan zelf de functionaliteit van de PC aanpassen door extra software te installeren en eventueel bijkomende hardware toe te voegen. Zo kan je met een PC, een DVB-T ontvanger (USB stick van enkele euro s) en wat software TV kijken en DAB radio beluisteren. Een embedded systeem is ontworpen om slechts een beperkt aantal taken uit te voeren zoals het instellen van de kookcyclus in de microgolfoven. De gebruiker kan zelf (meestal) geen aanpassingen aan software (in dit geval firmware) of hardware aanbrengen. De desktop PC bestaat gek genoeg ook uit een aantal embedded systemen. Hieronder staat een niet limitatieve lijst van subsystemen die een eigen computer bevatten: klavier HD DVD USB-controller grafische kaart beeldscherm muis In een optische muis zit een embedded systeem (bestaat uit 2 computers) die er voor zorgen dat: de bedieningsknoppen ingelezen worden het beeld van de camera omgezet wordt in bewegingsinformatie de gegevens doorgezonden worden naar de PC 16

17 2.2 Wat is er uniek aan het ontwerp van embedded systemen? Het ontwerp van een embedded systeem vormt een uitdaging op het gebied van betrouwbaarheid, performantie en systeemkost. Omdat embedded systemen o.a. verantwoordelijk kunnen zijn voor de veiligheid van de gebruiker (ABS systemen, pacemakers, sturing van liften, ) is hun betrouwbaarheid essentieel. Ontwerpers moeten rekening houden met het feit dat hun systemen niet eenvoudig even opnieuw opgestart kunnen worden (reboot) als het misgaat. In vele gevallen zijn ze (zonder uitschakelen) jaar in, jaar uit actief. Een kookplaat wordt enkel nog in stand by gezet. De software en hardware zullen zodanig ontworpen worden dat een fail safe werking gegarandeerd wordt. Daarom zijn solide ontwerpmethoden en een grondige testfase heel belangrijk voor elk embedded systeem, zowel wat de hardware- als de software implementatie betreft. Door de behoefte om te communiceren met sensors, actuatoren, toetsenborden, displays enz. moet de programmeur een goede kennis hebben over hoe men op alternatieve manieren aan I/O kan doen, zodat de vereisten qua snelheid, complexiteit en systeemkost op elkaar afgestemd kunnen worden. Alhoewel we meestal (afhankelijk van de gebruikte processor of controller) programmeren in een hogere programmeertaal voor een betere productiviteit, zal de intense interactie tussen hardware en software aanleiding geven om af te dalen tot op het hardwareniveau van het systeem en te programmeren in machinetaal (assembler). 2.3 Hoe krachtig zijn embedded processoren? De embedded systemen die we vinden in de meeste consumer producten bevatten een microcontroller (single chip computersysteem figuur 2.3.1). De eigenschappen van elk computersysteem (en dus ook van een microcontroller) zijn terug te brengen tot volgende kernbegrippen: hoeveelheid geheugen (ROM en/of RAM) rekenkracht (aantal instructies per seconde, grootte van de variabelen, bewerkingen die de processor kan uitvoeren (floating point?) ) beschikbare I/O (poorten, AD, DA, PWM, communicatie, ) stroomverbruik De figuur geeft een typisch embedded systeem weer. 17

18 Figuur Blokdiagram 8051 microcontroller 18

19 Figuur Blokdiagram embedded systeem met microcontroller Omdat microcontrollers single chip computers zijn, bevatten ze minder transistoren dan een PC, die opgebouwd is uit meerdere geïntegreerde schakelingen. De prestaties van beide kunnen dan ook niet zomaar vergeleken worden. Microcontrollers zijn meestal geoptimaliseerd naar een bepaald type toepassing. Zo zal de microcontroller die op een identiteitskaart zit niet onmiddellijk geschikt zijn om een GSM te besturen. Het aanbod van verschillende types en fabrikanten is dan ook overweldigend. Het maken van de juiste keuze is geen eenvoudige taak. Embedded systemen (microcontrollers) kunnen gebaseerd zijn op 4-bit (vb. uurwerken), 8-bit (het merendeel van de toepassingen), 16-bit (vb. motion control) en 32-bit (o.a. PDA, GSM, gaming) processoren. Het aantal bit is bepalend voor het grootste getal dat de CPU in een operatie kan verwerken. Een 8 bit CPU kan in een keer getallen manipuleren tussen 0 en 255. Grotere getallen zullen in meerdere stappen verwerkt moeten worden. De stelling hoe meer bit hoe krachtiger gaat niet steeds op. Zo zal een PLC vooral bit variabelen manipuleren. Voor dit type toepassing is het belangrijk dat de CPU individuele bits eenvoudig en snel kan manipuleren of testen. 19

20 2.4 Embedded systemen werken meestal "REAL-TIME" Real-time systemen verwerken 'events'. Events zijn gebeurtenissen die voorkomen aan systeem inputs en die andere gebeurtenissen veroorzaken aan systeem outputs. Een voorbeeld van een event is het blokkeren van een wiel van een wagen bij het remmen. De reactie van het ABS systeem (embedded systeem) hierop is het gepulseerd bekrachtigen van de rem zodat het wiel weer gaat draaien en de wagen opnieuw bestuurbaar wordt. De reactietijd van een real-time embedded systeem moet dan ook minimaal zijn. Het ABS systeem moet het blokkeren van het wiel detecteren binnen enkele milliseconden. Een vertraging van enkele seconden zou hier ontoelaatbaar en zelfs potentieel dodelijk zijn. Wat real-time betekent voor een embedded systeem is afhankelijk van de toepassing. Zo zal de besturing van een TV minder tijdskritisch zijn en zullen we tevreden zijn als de microcontroller zijn reactie zo snel mogelijk berekent. Er is immers geen echte deadline, de gebruiker of de installatie is niet in gevaar als de response iets langer duurt. We spreken hier van soft real-time. Wanneer er wel een deadline is opgelegd aan het systeem, zoals in het geval van het ABS systeem spreken we van hard real-time systemen. 2.5 Een typisch microprocessorsysteem Om de voordelen van een microcontroller te duiden, gaan we eerst even het blokschema van een typisch embedded microprocessor systeem van nabij bekijken (figuur 2.5.1). De CPU (een single chip CPU wordt een microprocessor genoemd) is verbonden met de nodige geheugenchips (ROM en RAM) en met een aantal I/O chips, in dit geval parallelle poorten, seriële poorten en timers. De verbinding van de CPU met de andere componenten verloopt via een aantal bussen. Een bus is een verzameling van geleiders die signalen van een zelfde aard transporteren. De draden die de gegevens van en naar het geheugen vervoeren, worden de DATABUS genoemd. De geleiders die het adres (locatienummer) vervoeren dat aangeeft waar er informatie gelezen of geschreven wordt, noemen we de ADRESBUS. 20

21 X-tal Osc. POR ADRES DECODER ADRESBUS CPU ROM (FLASH) (EPROM) (EEPROM) SRAM PAR. POORT SER. POORT TIMER COUNTER DATABUS Figuur Blokdiagram van een microprocessor systeem Omdat we moeten kunnen lezen en of schrijven naar het geheugen, zijn er ook controlesignalen nodig, die we de CONTROLEBUS noemen. Aangezien het de processor is die de controlebus stuurt, hebben alle namen van de signalen betrekking op de functie die ze vanuit de processor krijgen. Zo wordt de 'read' lijn actief als de processor wil lezen, en de 'write' lijn als de processor wil schrijven. De controlebus is niet opgenomen in figuur Het gaat over een beperkt aantal verbindingen tussen de CPU en de andere bouwstenen in het systeem. Het klassieke microprocessor systeem heeft voor embedded applications een aantal nadelen (zie volgende paragrafen) MTBF Alles gaat stuk! Niets is, helaas, voor de eeuwigheid. Een ontwerper zal trachten de levensduur van zijn design af te stemmen op verwachtingen van de klant. Een systeem bestaat meestal uit verschillende componenten die allemaal hun eigen "Failure rate" hebben. Deze FIT-rate ( FIT of Failures In Time) is de statistische waarde die voor een component aangeeft hoeveel failures of defecten de component zal hebben per miljard werkingsuren ( uur = jaar). De FIT rate van een component is een gegeven dat door de fabrikant ter beschikking kan worden gesteld voor elke component, of gegevens waaruit je de FIT rate kan berekenen.. Aan de hand van deze cijfers kan voor een bepaald systeem de MTBF worden bepaald. MTBF staat voor Mean Time Between Failure. 21

22 De MTBF is geen exact gegeven, het is een voorspelling, die voor een systeem met een aantal componenten, elk met een bepaalde FIT-rate, een gemiddelde werkingsduur wordt berekend. MTBF n 1 10 i 1 9 q i r i Waarin: n het aantal verschillende componenten q i hoeveelheid van de i de component de FIT rate van de i de component r i Hieruit blijkt dat voor een bepaalde FIT rate de betrouwbaarheid van het systeem afneemt als het aantal componenten toeneemt, iets wat je met wat boerenwijsheid ook al wel kon inschatten. In de figuur staat de FIT-rate van een PowerPC 603r processor van Freescale weergegeven in functie van de junctietemperatuur met de voedingsspanning als parameter. Figuur FIT-rate van een PowerPC 603r 22

23 2.5.2 Ontwerp van een PCB Voor een embedded processorsysteem moet er ook een PCB (Printed Circuit Board) worden ontworpen. Met de steeds hogere klokfrequenties en pincount van de processoren is dit eveneens een niet zo voor de hand liggende- en vaak tijdrovende zaak. Sommige ontwerpers zullen, niet gehinderd door enige kennis ter zake, aanvoeren dat het tekenen van een PCB louter en alleen het omzetten is van schema verbindingen naar echte bedrading. Niets is minder waar! Het tekenen van een PCB is het, met kennis van zaken, creëren van een nieuwe component met eigen elektrische eigenschappen en met een aanzienlijk aandeel in het al dan niet slagen van een project! Zelfs bij de meest ervaren ontwerper, en bij het gebruik van de meest geavanceerde CAD pakketten, zullen er waarschijnlijk een aantal designfouten in de eerste prototype PCB's van een complex systeem zitten. Dikwijls liggen deze problemen op het vlak van overspraak en wederzijdse koppelingen of signaalintegriteit. Ook op het vlak van EMC (Electro Magnetische Compatibiliteit) kunnen er een aantal problemen aan het licht komen bij de eerste metingen op de prototypes. Het systeem kan immers te stoorgevoelig zijn, of kan zelf teveel storing veroorzaken. Dit heeft als gevolg dat er een aantal aanpassingen of zelfs een redesign van de PCB moet worden gedaan. Dit is een kostelijke zaak. Je kan dus maar beter deze complexe en grote PCB's vermijden Overige nadelen In een standaard computer zitten tal van verschillende onderdelen. De fabrikant zal dit moeten voorzien in zijn stockbeheer. Het ontbreken van 1 component kan de totale productie stilleggen. Ook naar onderhoud is het aantal verschillende componenten een nadeel. 2.6 Een microcontroller systeem Wanneer we het blokschema van een microcontroller systeem (figuur 2.6.1) dat uit 1 IC bestaat, vergelijken met het blokschema van een processor systeem (figuur 2.5.1) dat is opgebouwd uit discrete componenten, dan merken we dat deze praktisch gelijkaardig zijn. 23

24 Figuur Microcontroller systeem Het grote verschil is echter dat bij een microcontroller het hele systeem op één chip is geïntegreerd, wat grote voordelen heeft tegenover een diskreet opgebouwd systeem. Omdat het hier gaat om een single-chip oplossing is de MTBF van het eindproduct meestal groter. Het ontwerp van de PCB is minder complex. Een groot deel van de verbindingen tussen de functionele onderdelen is immers op de chip uitgevoerd. Het systeem kan ook veel compacter worden gemaakt met een microcontroller dan met de discrete oplossing. Dit heeft samen met het vorige argument als gevolg dat het eindproduct tegen een lagere kostprijs op de markt gebracht kan worden. Op technisch vlak hebben de testingenieurs het ook makkelijker. Omdat de digitale bussen, waar de snelle signalen over getransporteerd worden, on-chip blijven zal het systeem veel sneller voldoen aan de gangbare EMC normen. In het 8-bit segment is de meest populaire en meest gebruikte architectuur die van de Intel Die populariteit is in belangrijke mate het gevolg van een unieke economische zet van het bedrijf. Het ontwerp van de controller (IP) is voor iedereen (mits vergoeding) toegankelijk. Op die manier kan elke fabrikant snel en goedkoop een microcontroller produceren. 24

25 Doordat deze architectuur gebruikt wordt door een groot aantal gebruikers ontwikkelen verschillende fabrikanten nog steeds controllers met nieuwe features, gebaseerd op deze architectuur (kip en ei verhaal). Er zijn ongeveer een 500-tal verschillende derivaten van een oorspronkelijke 8051 op de markt, en na 30 jaar komen er nog regelmatig bij. Men schat dat de helft van alle gebruikte microcontrollers gebaseerd zijn op deze architectuur. 2.7 Wat is er op de markt? In figuur wordt de verhouding van microcontrollers in het marktaandeel weergegeven i.f.v. het aantal bit van de CPU. Gelet op de lagere kostprijs van 8 bit controllers is hun numeriek aandeel verhoudingsgewijs nog groter. Recent zit het gebruik van 32 bit controllers in de lift. Een belangrijke oorzaak is de opkomst van de ARM microcontrollers (ARM7, ARM9, CORTEX, ). ARM heeft zelf geen silicon productie, maar verkoopt IP aan andere fabrikanten. Hierdoor komt er en groot aantal compatibele controllers op de markt. De ARMx en CORTEX families zijn speciaal ontworpen (RISC) zodat ze een laag stroomverbruik combineren met een hoge verwerkingssnelheid. Als bijkomend voordeel is er de geringe silicium oppervlakte die door de core gebruikt wordt. Hierdoor is de kostprijs van deze 32 bit controller vergelijkbaar of lager dan die van 8 bit microcontrollers. Net zoals bij de 8051 is een toolchain bruikbaar voor componenten van verschillende fabrikanten. Het komt er in de praktijk op neer dat voor een bepaalde toepassing steeds de meest geschikte controller moet gekozen worden uit het globale aanbod. Hierbij zal de ontwerper rekening moeten houden met: beschikbare tools voor de ontwikkeling (compilers, simulatoren, debuggers, enz ) bestaande software bibliotheken opgedane ervaring met bepaalde controllerreeksen beschikbaarheid van componenten economische gegevens 25

26 Figuur Microcontroller marktaandeel i.f.v. aantal bit CPU 26

27 2.8 Een voorbeeld uit elke categorie Bit controller: EM6626 Figuur bevat een onderdeel van de datasheet van een 4 bit microcontroller (producent maakt deel uit van de Swatch group!!). 27

28 Figuur Bit microcontroller Deze familie van controllers worden gebruikt voor 'low-end' toepassingen, zoals calculators, telefoons (geen GSM's of DECT toestellen ), uurwerken (in 'DIE' te verkrijgen), spelletjes, speelgoed, fietskilometertellers, thermostaat, enz Een eigenschap van deze reeks controllers is dat ze low power devices zijn. Ze kunnen werken op een zeer lage voedingsspanning van 1,2V tot 3,6V en dit bij een stroomverbruik van 1,8μA in actieve toestand! (batterijgevoede toepassingen). 28

29 Een gevolg van dit zeer laag stroomverbruik is dat ze met een lage klok frequentie werken, in dit geval 32KHz tot enkele honderden KHz. Bij 32KHz geeft dit een uitvoeringstijd van 61μS per instructie, zeker iets waar rekening moet mee gehouden worden. Een eigenschap van de meeste 4-bit controllers is dat ze slechts in mask ROM uitvoering of in OTP (One Time Programmable) ROM uitvoering beschikbaar zijn Bit controller: XC888 De groep van 8-bit controllers worden gebruikt in medium end toepassingen zoals: harddisk controle, keyboards, PLC's (vb. LOGO van SIEMENS), sensoren, stappenmotorsturingen, subsystemen (bv. display units), enz. De hier weergegeven XC888 van Infineon (vroeger SIEMENS) is een erg veelzijdige controller die een heleboel verschillende I/O mogelijkheden heeft meegekregen, vandaar zijn toepassing in voornamelijk industriële systemen (figuur ). Figuur Infineon XC888 blokschema Deze controller is geen low power type, actief en 5V) verbruikt hij 30mA stroom, maar hij beschikt over een idle mode waar hij 15mA verbruikt en een power down mode waar hij maar 10μA verbruikt. De systeemklok moet tussen 4 en 12MHz liggen (externe klok), het is dus geen statisch ontwerp. De XC888 beschikt over FLASH geheugen, maar er is ook een ROM uitvoering beschikbaar voor grote aantallen. Het FLASH geheugen is ISP (In 29

30 System Programmable). De XC888 is een controller die is afgeleid van de Intel 8051, waar heel wat nieuwe periferie-elementen werden aan toegevoegd. Het grote voordeel van deze familie is dat er reeds immense hoeveelheden software zijn geschreven die herbruikbaar is. Naast deze periferie valt ook de hardware Division/Multiplication unit op, die 32- bit/16-bit bewerkingen en 16-bit x16-bit bewerkingen kan maken los van de CPU, wat een enorme tijdswinst kan opleveren bij wiskundige bewerkingen. Bijkomend is de controller uitgerust met een CORDIC rekeneenheid (sin, cos, log). Door de controller uit te rusten met een CAN bus en communicatiepoorten met seriële mogelijkheden kan de controller eenvoudig communiceren met andere systemen. De kostprijs voor dit type controller zit rond 8 voor grote aantallen bit controller: XC167 van Infineon In figuur is het blokdiagram van de XC167 microcontroller van Infineon opgenomen. Figuur Infineon XC167 microcontroller 30

31 16-bit controllers worden gebruikt in high-end toepassingen, dit zijn meestal allemaal rekenintensieve toepassingen zoals: PID motor snelheidsregelingen (servocontrollers), PLC's (S7 reeks van SIEMENS), industriële controlesystemen, management van verbrandingsmotoren, ABS systemen, enz. Industriële systemen moeten alsmaar meer in staat zijn om te communiceren met elkaar of met een subsysteem, hier vormt de CAN bus (industrieel- en automotive communicatie netwerk) een uitstekende oplossing. Deze chip bezit: een klokgenerator met PLL en verschillende types intern geheugen zoals 128Kbytes programma Flash, programma RAM en data RAM Bit controller: De MB91F361 van Fujitsu Dit is een voorbeeld uit een reeks van controllers voor zeer rekenintensieve taken zoals: laser- en high end inktjet printers, communicatie producten (routers, bridges ), high end gaming producten, muziek instrumenten, GPS systemen, next generation dashboards Zijn kloksnelheid ligt tussen 16 en 64MHz en is onder programmacontrole instelbaar, wat nuttig is om het stroomverbruik te beperken wanneer dit nodig is. Verder valt de massale hoeveelheid intern geheugen op (512 Kbytes Flash en 16Kbytes RAM) wat nuttig is voor het stockeren van een (real time) OS, wat bij 32-bit controllers meestal het geval is. Merk ook op dat deze controller beschikt over een volledige 32-bit externe bus interface zodat hij een groot extern geheugen kan aanspreken (max. 4Gbyte). Hij is dan ook ruim behuisd, met zijn 208 pins TQFP verpakking. De externe bus interface maakt de grens tussen een microcontroller en een embedded microprocessor zeer vaag. De microcontroller heeft hier in tegenstelling met een embedded processor echter nog altijd het voordeel single-chip te kunnen werken. Het blokschema van de MB91F361 controller van Fujitsu is opgenomen in figuur

32 Figuur Blokschema van de MB91F361 controller van Fujitsu 32

33 Hoofdstuk hardware 3.1 Inleiding De eerste single chip CPU (de 4004 (MCS-4)) wordt door Intel in 1971 op de markt gebracht. Andere fabrikanten volgen. In 1974 brengt TI de eerste microcontroller op de markt (TMS1000). In1976 brengt Intel een single chip computer op de markt (de 8048 (MCS-48)) gevolgd in1980 door de microcontroller 8051 (MCS-51). De MCS-48 wordt nog steeds gebruikt voor het uitlezen van PC-klavieren. De MCS-51 (MicroComputerSystem 51) wordt als IP vrijgegeven aan andere fabrikanten die eigen derivaten op de markt brengen. Van de originele 8051 worden er in en in 1983 reeds verkocht. Volgende websites geven gedetailleerde informatie aangaande de geschiedenis van CPU s en microcontrollers: Men schat dat de helft van alle embedded systemen worden bestuurd door een controller uit de 8051 familie. De CPU (gekenmerkt door instructieset, interrupt structuur en memory map) van de 8051 microcontroller wordt een CORE genoemd. Fabrikanten die de 8051 core (kern) gebruiken voor hun eigen controllers (zoals PHILIPS, INFINEON, DALLAS, ATMEL, ANALOG DEVICES, SILICON LABORATORIES, enz.) voegen bijkomende I/O mogelijkheden toe. Het gebruik van een gemeenschappelijke core maakt dat dezelfde ontwikkel tools gebruikt kunnen worden. Bovendien laat dit ook toe reeds geschreven code te hergebruiken. Ook het feit dat de meeste ontwerpers "second-sources" willen voor hun componenten is een reden voor dit succes. Zo zijn er op het ogenblik honderden verschillende C s die allemaal 8051 compatibel zijn, maar toch verschillen door hun specifieke extra s zoals bv. bijkomende parallelle of seriële poorten, I 2 C Bus, AD/DA converters, hoeveelheid intern geheugen... Ook het tegenovergestelde doet zich voor; voor minimale toepassingen bevat de oorspronkelijke 8051 nog te veel mogelijkheden. Door een aantal parallelle poorten weg te laten, krijgt men een C met minder aansluitpinnen en mogelijkheden en een compactere uitvoering, bv. de ATMEL 89C5115 in een 28 pin SO behuizing. De ATMEL 89C5115 C bestaat uit de 8051 CPU-CORE waarbij extra periferie werd toegevoegd en andere dan weer werd 33

34 weggelaten. De kleinste 8051 microcontroller (2010) is weergegeven in figuur (pincount=10). Figuur Mini 8051 controller (C8051T606 van Silicon Labs) 3.2 De oorspronkelijke 8051 architectuur De oorspronkelijke 8051 C bestaat uit (figuur 3.2.1): Een 8-bit CPU ( Central Processing Unit ) die er voor zorgt dat de instructies worden opgehaald uit het geheugen, worden gedecodeerd en uitgevoerd. Deze CPU is geoptimaliseerd voor controletoepassingen ( bit bewerkingen). Samen met de memory map en interrupt structuur vormt dit de CORE van de controller. 4K bytes ROM, voor programma opslag. 128 bytes interne RAM, voor het opslaan van variabelen, data, enz. De naam RAM is verwarrend. Eigenlijk zijn het registers (in een register kunnen bewerkingen uitgevoerd worden, in RAM niet). Twee 16 bit timer / counter circuits (TIMER0,TIMER1) die gebruikt kunnen worden om pulsen te tellen, of tijd af te passen. Een full duplex UART (Universele Asynchrone Receiver Transmitter) is een seriële poort voor communicatie toepassingen (COM poort). On chip clock oscillator. 4 acht bit parallelle poorten. (P0,P1,P2,P3) waarvan ook twee poorten gebruikt kunnen worden als ADRES en DATA BUS om extern geheugen aan te spreken. Dit heeft als nadeel dat deze poorten dan hun functie als I/O poort verliezen. De controller kan dus ook als CPU gebruikt worden in een computersysteem. Interrupt controller met twee interrupt niveaus, die 5 interrupt bronnen kunnen verwerken 34

35 Figuur Basis 8051 architectuur 3.3 Memory map van de 8051 CPU De memory map (kaart geheugenruimte) van een CPU is letterlijk een kaart die weergeeft hoe het geheugen van de CPU bereikbaar is, en wat de specifieke functie hiervan is. Bij de MCS-51 ziet de CPU extern en intern geheugen. Het externe geheugen wordt gebruikt voor het opslaan van uitvoerbare code (code of program memory) en variabelen (external RAM). Alhoewel het de naam extern geheugen draagt, kan een deel geïntegreerd zijn in de chip. De instructies die je moet gebruiken om het extern geheugen uit te lezen blijven onveranderd, ongeacht de fysieke plaats van het geheugen. Het interne geheugen bestaat uit registers. Een register is een geheugenplaats die deel uitmaakt van de CPU. Daardoor kan de inhoud van registers door een berekening aangepast worden. Ook alle I/O gebeurt via registers. De CPU bevat twee groepen van instructies: MOVX en MOVC instructies die manipulatie van het extern geheugen toelaten Alle overige instructies die allemaal inwerken op registers 35

36 3.3.1 De inwendige geheugenruimte Figuur laat de inwendige geheugenruimte zien. Figuur Inwendige geheugenruimte 8051 De inwendige geheugenruimte bestaat uit 8 bit registers. Het belangrijkste verschil tussen een register en een RAM locatie is de mogelijkheid om data in registers te manipuleren via een berekening. De 8051 compatibele controllers hebben minstens 128 bytes algemeen bruikbare registers (General Purpose Registers of GPR s) De meeste beschikken over 256 GPR s. Daarnaast zijn er Special Function Registers (SFR s) die de CPU toegang verlenen tot de I/O mogelijkheden van de controller. Omdat er veel registers zijn krijgen ze een 8 bit volgnummer (adres) om ze te identificeren. Dat adres moet in de instructie opgegeven worden, zodat de CPU weet welk register gemanipuleerd moet worden. Zoals figuur laat zien is er een overlapping op de adressen 80h-ffh. Dit conflict wordt opgelost door de adressering die gebruikt wordt in de instructie. De adressering is de manier waarop de instructie het opgegeven adres aangeeft. In figuur is de standaard 8051 SFR invulling weergegeven. Aan de linker kant staan de 8 bit adressen van de SFR s. Aan de rechterkant staat de naam van het register, gegeven door de fabrikant, zodat de programmeur de functie van het register kan begrijpen. De figuur laat ook zien dat bepaalde registers opgesplitst worden in afzonderlijke bits die via hun bitadres door bepaalde instructies manipuleerbaar worden. 36

37 Figuur Standaard 8051 SFR kaart De 8051 is een microcontroller die gebaseerd is op een accumulator architectuur. Dit wil zeggen dat alleen in de ACC (accumulator) berekeningen kunnen uitgevoerd worden. Dat vormt een bottle neck voor rekenkundige operaties. Daarom zijn er GPR s registers met een speciaal statuut (R0-R7, beschikbaar in 4 banken zie figuur ). Deze registers laten een kleiner aantal bewerkingen toe dan de ACC, maar meer dan op alle andere registers. Tenslotte zijn er de overige registers waarop minimale berekeningen mogelijk zijn. Hierdoor vormt de accumulatorstructuur nooit echt een probleem. De figuur laat ook zien dat er in de GPR s ook een aantal bytes zijn die over individueel adresseerbare bits beschikken (registers 20h-2fh). De controller kan in totaal 256 individuele bits manipuleren (GPR s en SFR s samen). 37

38 Figuur Registerbanken in GPR s De GPR s met de adressen 80h-ffh hebben verder geen speciale mogelijkheden. In de originele 8051 en enkele kleinere derivaten zijn ze zelfs niet aanwezig. 38

39 3.3.2 De externe systeemarchitectuur In sommige van de 8051 compatibele controllers is geen (of onvoldoende) intern programmageheugen geïntegreerd, dit is bv. zo bij de C517 van Infineon of de 8031 van Intel, die helemaal geen intern programmageheugen bezitten. In deze gevallen gebruiken de controllers uit deze reeks extern aangesloten geheugenchips op dezelfde manier als een microprocessor. Op deze manier kan men extern bijkomend programmageheugen, datageheugen of bijkomende periferiechips, zoals parallelleof seriële poorten, toevoegen aan een systeem door ze te verbinden met de bussen van de microcontroller. Niet alle derivaten van de 8051 beschikken nog over en externe bus. De XC888 heeft die mogelijkheden niet meer De externe geheugenruimte De 8051 verschilt van een traditionele processor doordat hij een gescheiden geheugenruimte heeft voor data en programmacode. De maximale geheugenruimte voor programmageheugen (CODE MEMORY) is 64Kbytes en deze kan volledig extern, gedeeltelijk intern/extern (bv. 4Kbyte intern bij de 8051) of volledig on chip (intern) gesitueerd zijn. Het is mogelijk dat de volledige geheugenruimte niet opgevuld wordt. De fysische plaats van het geheugen doet geen afbreuk aan de uniforme manier waarop de CPU het geheugen aanspreekt. Speciaal is ook het ontbreken van een instructie om dit geheugen te schrijven. Het programma moet dus op voorhand in het programmageheugen geladen worden, en kan door de controller zelf niet gewijzigd worden (de XC888 is hierop een uitzondering en kan in application programming uitvoeren. Dit is niet zonder gevaar, en moet met de nodige omzichtigheid gebeuren. Zie hiervoor de UM.). Ook het externe datageheugen (EXTERNAL RAM) is maximaal 64Kbytes groot en kan deels op het IC vertoeven. In de meeste 8051 applicaties wordt dit externe geheugen niet gebruikt. Er zijn meestal immers voldoende GPR s aanwezig die voor dataopslag gebruikt kunnen worden. De externe memory map van een 8051 controller wordt in figuur weergegeven. De geheugenlocaties zijn 8 bit groot. Hun plaats in het geheugen wordt bepaald door een adres. Omdat er voor het aanspreken van beide types geheugen afzonderlijke instructies bestaan kunnen ze dezelfde adressen gebruiken. De externe adressen worden via een 16 bit adresbus doorgegeven. Dit laat unieke adressen toe (0000h-ffffh). Wanneer een deel van het geheugen on chip zit, en er worden adressen gebruikt die niet naar dat inwendig geheugen verwijzen, zal de CPU automatisch de bussen activeren en uitwendig de data lezen/schrijven (ook van toepassing op het programmageheugen). 39

40 Bij instruction fetches zal de controller instructies (code) steeds ophalen uit het code geheugen, dat zich intern of extern van de controller kan bevinden. Extern codegeheugen wordt aangesproken onder twee voorwaarden: wanneer de /EA (External Access) pin met een logisch laag niveau is verbonden of wanneer de program counter (PC) een adres aangeeft dat groter is dan de interne geheugenruimte. De bedoeling is dus dat bij ROM-less (zonder intern codegeheugen) controllers vb. C517 en 8031 de /EA-pin laag gemaakt wordt, om aan te geven dat instructies extern moeten opgehaald worden. Niet alleen voor instruction fetches kan het codegeheugen aangesproken worden, maar a.d.h.v. een MOVC instructie kan ook data (bv. een tabel met constanten, tekstcodes ) die in dit codegeheugen staat, gelezen worden. Wanneer het externe codegeheugen gelezen wordt, zal de /PSEN (Program Store Enable) lijn door de controller geactiveerd worden als lees-controlesignaal naar het geheugen toe. Merk op dat er geen voorzieningen zijn getroffen om naar het codegeheugen te schrijven vanuit de controller, de code zit immers in ROM geheugen! Codegeheugen Datageheugen FFFFh FFFFh Externe code geheugenruimte Externe data geheugenruimte Codegeheugen kan intern of extern zitten afhankelijk van de controller en de toestand van de EA-pin 1000h 0FFFh 0000h 0000h Figuur Externe memory map 8051 microcontroller 40

41 Het externe datageheugen kan wel worden gelezen en geschreven. Het moet immers geschikt zijn om variabelen te bevatten, het is dan ook uitgevoerd als RAM geheugen. Dit kan onder programmacontrole instructies: gelezen of geschreven worden met volgende MOVX en MOVX om data te lezen uit het geheugen en en om data te schrijven naar het geheugen. Wanneer het externe datageheugen wordt gelezen of geschreven zal de controller respectievelijk de /RD of de /WR lijn activeren als controle signaal. Merk op dat de controller niet in staat is om uit het datageheugen instructies op te halen, daar hij hiervoor een ander lees-controlesignaal gebruikt. In sommige gevallen (bv. bij programma ontwikkeling) is het wenselijk dat een programma kan opgehaald (en uitgevoerd) worden uit het datageheugen, want daar kan men wel een programma in downloaden, het is immers schrijfbaar (RAM). Bij de 8051 reeks kan dit (het overlappen van data- en codegeheugenruimte) gedaan worden door de beide actief lage lees-controlesignalen (/RD en /PSEN) via een AND functie te combineren tot een nieuw actief laag leessignaal dat dan naar het fysische geheugen (RAM) met een bepaald geheugenbereik gaat. De externe verbindingen van een 8051 compatibele controller worden aangegeven in de figuur Figuur Externe klemmen standaard

42 De vier I/O poorten worden hier weergegeven samen met hun alternatieve functies tussen haakjes. In een basis 8051 systeem kunnen de vier poorten als 8-bit parallelle poorten gebruikt worden. Het is belangrijk te begrijpen dat wanneer een pin gebruikt wordt met zijn alternatieve functie deze pin niet meer beschikbaar is voor standaard I/O. Wanneer bv. externe periferiechips of geheugen nodig zijn, worden poort 0 en poort 2 gebruikt met hun alternatieve functie nl. als businterface. Poort 0 wordt dan de 8-bit gemultiplexte adres/data bus en poort 2 krijgt de functie toegewezen van hoogste byte van de adresbus. Enkele pinnen van poort 3 worden controlelijnen zoals /RD (read) en /WR (write). Deze poortpinnen zijn dan verloren als I/O-pinnen en er blijven in dit geval niet veel pinnen meer over die kunnen gebruikt worden als vrij programmeerbare I/O pin.. Het probleem wordt nog groter indien we ook enkele externe interrupts willen verwerken via de interrupt ingangen van poort 3. Ook de seriële poort en de timeringangen zitten als alternatieve functie op deze poort 3. Het besluit is dan ook dat we de 8051 controllers met vier poorten liefst single-chip gebruiken en niet met een externe businterface daar we immers op deze manier de voordelen (I/O) van de controller verliezen. Figuur C517 microcontroller met extern geheugen 42

43 Een 8051 compatibele controller met businterface gebruiken wordt pas interessant wanneer we kunnen beschikken over extra I/O poorten zoals bv. het geval is bij de C517 van Infineon, die beschikt over 8 poorten, zoals aangegeven in de figuur De RST (reset) ingang moet bij power-up even hoog worden gehouden ( bij de C517 is dit het inverse signaal, dat dus laag moet gemaakt worden) om de controller zich te laten initialiseren en met de programma uitvoering te beginnen op locatie 0000h. De oscillator pinnen (XTAL1, XTAL2) worden gebruikt om een kwarts kristal aan te sluiten op de inwendige klokoscillator. Andere controlelijnen zijn: de adres latch enable (ALE) pin die gebruikt wordt om de adres/databus te demultiplexen, de program store enable (/PSEN) pin om het externe codegeheugen aan te spreken en de external access (/EA) pin die gebruikt wordt om de controller in het externe codegeheugen instructies te laten ophalen De bus architectuur De figuur geeft de busstructuur weer voor het aanspreken van externe geheugen- of periferie-elementen. We zien hier een 16 bit adresbus en een 8 bit databus, samen met vier controlesignalen. Om het aantal poortpinnen die gebruikt worden voor de adres- en databus te beperken worden de laagste byte van de adresbus en de data tijd-gemultiplexed op dezelfde bus. Het Address Latch Enable (ALE) signaal wordt gebruikt om de laagste byte van het adres te latchen en zo deze twee types informatie te demultiplexen. Op deze manier kan een stabiele 16 bit adresbus worden aangeboden aan het systeem, terwijl de adres/databus daarna wordt gebruikt voor een data transfer. De /RD en /WR lijnen controleren de datastroom van en naar de externe datageheugenruimte. De /PSEN lijn controleert de datastroom van de externe programmaruimte. In deze architectuur zijn er geen voorzieningen voor een gescheiden I/O ruimte (bv. voor andere periferiechips enz.) wat wil zeggen dat externe periferie in de geheugenruimte moet worden ondergebracht, we zeggen dat de periferie "memorymapped" is. 43

44 8051 compatibele controller P2 MSB adresbus (A8-A15) 16-bit adresbus ALE P0 LSB adres/ databus AD0-AD7 Adres latch LSB adresbus A0-A7 databus P3 RD WR PSEN Figuur Busstructuur extern geheugen De externe timing De controller systeemklok bepaalt alle timing eigenschappen van het systeem. Ze wordt opgewekt door een interne oscillator in de controller. Het frequentiebepalend element van de systeemklok kan een inwendige RC-keten zijn of een extern kwartskristal of keramische resonator. De systeemklok kan ook door een uitwendig signaal opgewekt worden (XC888: intern RC circuit default, kan overschakelen naar extern signaal via programmatuur). De XTAL1 en XTAL2 pinnen zijn de ingang en de uitgang van een inverterende versterker die kan werken als een on-chip oscillator van het Pierce type. Hiertussen sluiten we extern een kwartskristal aan waarvan de parallelresonantiefrequentie gelijk is aan de gewenste klokfrequentie. Hoe hoger de klokfrequentie wordt gekozen, hoe sneller de controller instructies zal uitvoeren, maar hoe hoger het stroomverbruik en hoe groter de EMI. De minimum frequentie is afhankelijk van de functionaliteit van het systeem, m.a.w. de controller moet snel genoeg zijn om het systeem normaal te laten werken. De minimum frequentie is ook afhankelijk van de technologie waarmee de controller intern is opgebouwd (fully static?). Het bereik van de klokfrequentie wordt in de datasheet van de controller opgegeven en heeft meestal een maximum van enkele (tientallen) MHz. Men gebruikt in heel wat 8051 compatibele systemen een klok (en dus ook een kwartskristal) van

45 MHz. Men gebruikt deze frequentie omdat ze intern in de controller kan worden afgedeeld naar een standaard bitrate (communicatiesnelheid) voor de seriële poort. Naast dit kwartskristal worden er ook nog twee capaciteiten vanuit XTAL1 en XTAL2 verbonden naar de massa, zoals wordt aangegeven in de figuur De datasheet van een parallel resonant kristal geeft de load capaciteit weer, wat de serieschakeling is van C1 en C2. De waarde van C1 en C2 ligt meestal tussen 20 en 40 pf. Het vergroten van de capaciteiten heeft als gevolg dat de start-up tijd van de oscillator stijgt tot het punt waar de oscillator niet meer start. De capaciteitswaarden verminderen heeft als gevolg dat de oscillator kan gaan oscilleren op een hogere harmonische (overtone) van de grondfrequentie. Daar dit een circuit is waar signalen worden gegenereerd van relatief hoge frequentie worden er ook enkele eisen gesteld aan de fysische layout van het circuit (EMI). Figuur Kristal oscillator De signaalbanen op de PCB (Printed Cicuit Board) die het kristal, de capaciteiten en de controller oscillatorpinnen verbinden, moeten zo kort en zo breed mogelijk zijn om parasitaire inductantie en weerstand te beperken. Het kristal en de capaciteiten moeten dus zo kort mogelijk bij de oscillatorpinnen van de controller geplaatst 45

46 worden, terwijl de signaalbanen naar de oscillator moeten afgeschermd worden van andere signalen om overspraak te vermijden. Dit doet men meestal met een massavlak of met een massa ring rond de signaalbanen. De systeemklok bepaalt de interne klokfases, states en machinecycli m.a.w. de snelheid waarmee externe bustransacties en instructies worden uitgevoerd. Bij een klassieke 8051 bestaat een machine cyclus uit 6 toestanden (states) en is 12 oscillator periodes lang. Elke state is onderverdeeld in een phase1 (P1) en een phase2 (P2). Een machinecyclus bestaat dus uit 12 oscillatorperiodes die genummerd worden van S1P1 (State1, Phase1) tot S6P2. Rekenkundige en logische bewerkingen vinden typisch plaats gedurende phase1 en register naar register transfers gedurende phase2 (figuur ). Figuur Relatie systeemklok en bustiming 46

47 De uitvoering van een één-cyclus instructie start op S1P2 (stijgende flank PSEN), wanneer de opcode wordt binnengelezen in het instructieregister. Als het een tweebyte instructie is, wordt de tweede byte gelezen tijdens S4 van dezelfde machinecyclus. Wanneer het over een één-byte instructie gaat, zal er ook tijdens S4 een byte gelezen worden (dit is de volgende opcode) maar deze wordt niet verder gebruikt. In elk geval is de uitvoering klaar op het einde van S6P2. De meeste 8051 instructies worden uitgevoerd in één machinecyclus, maar sommige doen er twee of vier cycli over. Figuur Timing lezen en schrijven 47

48 De timing en de logische gedachtegang van de controlesignalen is belangrijk om de buswerking van een 8051 controller te begrijpen. De timing diagramma s voor het lezen van een byte uit het programmageheugen en het lezen en het schrijven van een byte uit het datageheugen worden hier in figuur weergegeven en spreken voor zich. Alle buscycli starten met het aanbieden van de adresinfo op P0 en P2. Op de dalende flank van ALE wordt de info op P0 in de externe latch opgeslagen, het volledige 16 bit adres is nu stabiel tot het einde van de buscyclus. P0 kan nu veranderen van waarde en de data kan nu weergegeven of gelezen worden langs P0. Voor het ophalen van een instructiebyte uit het programmageheugen zal de stijgende flank van de /PSEN lijn de data (programmabyte) binnenlezen. In het geval het datageheugen wordt aangesproken zal de stijgende flank van het /RD signaal aangeven wanneer de data gelezen wordt, de data moet door het geheugen tegen deze tijd stabiel op de databus geplaatst zijn. Bij het schrijven naar het datageheugen zal de stijgende flank van /WR aangeven dat de data stabiel op de databus zit en dat de geheugencomponent deze mag latchen (lezen). Het ALE signaal wordt gebruikt om de adres/data info op P0 te demultiplexen, maar zelfs bij het uitvoeren van intern opgeslagen code zal dit signaal worden gegenereerd, het is dus een nuttig signaal voor debug doeleinden, dat aangeeft of de controller daadwerkelijk code uitvoert. In single-chip toepassingen kan het ALE signaal, afhankelijk van het type van controller, softwarematig worden uitgeschakeld wat nuttig is voor het beperken van EMI, ALE wordt immers anders geactiveerd met een constante frequentie van 1/6 van de oscillatorklok wat aanleiding kan geven tot elektromagnetische straling. Bij microcontrollers die niet over een externe bus beschikken is het ALE signaal niet aanwezig. 3.4 I/O systemen De 8051 gebaseerde controllers hebben naast twee interne timers meestal minstens vier parallelle poorten en één seriële poort als I/O. Zoals reeds eerder werd aangehaald heeft bijna elke pin een alternatieve functie toegewezen gekregen. Het nadeel is dat wanneer deze pinnen met hun alternatieve functie worden gebruikt, ze natuurlijk niet tegelijk als gewone I/O pinnen beschikbaar zijn. Eigenlijk kan dit wel, maar dit kan vreemde gevolgen hebben. De gebruiker moet dan wel weten wat hij doet (vb DMX - of LIN break genereren). 48

49 Na een RESET zijn de vier poorten (I/O pinnen ) allemaal geconfigureerd als Input pinnen, en zijn de alternatieve functies uitgeschakeld. Omdat de werking van de I/O sterk afhankelijk is van de gebruikte component, wijden we verder in de cursus meer tijd aan de werking van de verschillende functies. De besturing van-, maar ook het uitwisselen van gegevens met de interne I/O componenten gebeurt via de SFR registers. In totaal zijn er 128 adressen voorzien om de SFR s te bereiken. Omdat ze inwendig in de CPU zitten is het zelfs mogelijk bewerkingen uit te voeren op de registers Mapping/Paging van SFR s (XC888) Omdat de hoeveelheid I/O inwendig in de microcontroller steeds toeneemt volstaan 128 adressen soms niet meer (zie XC888 appendix C (356 SFR s)). In dat geval wordt er mapping en of paging toegepast. Dit is een techniek waarbij er gekozen kan worden tussen meerdere sets van SFR s. Dit systeem vraagt van de programmeur de nodige discipline om bij te houden wat de huidig geselecteerde pagina is. In de XC888 wordt het SYSCON0 register gebruikt om te kiezen tussen 2 sets (maps) van 128 registers (figuur ). Figuur SYSCON0 register 49

50 Dit register is altijd bereikbaar en is dus in de twee sets SFR s beschikbaar. In appendix C kan je zien dat er wel meer registers altijd bereikbaar zijn (grijze kleur). Binnen elke set van 128 SFR s is er een bijkomende mogelijkheid om, per I/O module, opnieuw paging te gebruiken. De selectie gebeurt nu echter per groepje van registers die bij een I/O module horen. Elke I/O module heeft zijn eigen selectieregister om aan te geven welke functie een register krijgt (figuur ). In figuur staat een generieke weergave van het selectieregister dat er per I/O module aanwezig is. Bij standaard gebruik volstaat het schrijven naar de Page Bits om een selectie te maken (OP bits 00). Het systeem voorziet ook een mogelijkheid om bij het gebruik van interrupts de huidige waarde van het register te bewaren, en bij het verlaten van de interruptroutine te herstellen. Hiervoor moeten de OP en STNR bits aangepast worden (OP =10 of 11). Figuur Paging per I/O module XC888 50

51 Figuur Paging van XC888 SFR s 51

52 HOOFDSTUK 4 De 8051 instructieset 4.1 Inleiding Na het inschakelen van de voedingsspanning van de microcontroller wordt automatisch een RESET signaal gegenereerd (PowerOnReset of POR). De gebruiker kan dit signaal soms ook manueel bedienen via een schakelaar. Het signaal activeert in de CPU een elektronische schakeling die alle I/O uitschakelt, en de adresteller (ProgramCounter of PC) op nul zet. Hierdoor wordt de controller in een ruststand geplaatst. Vanaf dit ogenblik start de CPU met het ophalen van de eerste programmainstructie uit het codegeheugen. Deze moet op het RESET ADDRESS 0000H staan (De reset vector is 0000h bij een 8051 compatibele controller). Aangezien op dit adres altijd ROM geheugen is geplaatst, moet het gebruikersprogramma hier reeds op voorhand worden gestockeerd. Na reset zal op deze manier het gebruikersprogramma starten. Als de CPU de eerste instructie heeft gelezen en gedecodeerd voert de CPU deze opdracht uit. Automatisch wordt de adresteller (program counter of PC) aangepast, zodat op de adresbus het adres van de volgende instructie geplaatst wordt. De CPU zal deze inlezen, met behulp van het PSEN signaal (read signaal voor programmageheugen), ze uitvoeren, en de volgende instructie ophalen,. Dit gebeurt volledig automatisch. Als een instructie de CPU de opdracht geeft om een variabele uit het geheugen op te halen, dan worden de bussen eerst gebruikt voor het ophalen van de instructie uit het programmageheugen of code memory, waarna ze door de CPU gebruikt worden om de variabele te verplaatsen. Voor de meeste instructies wordt de uitvoeringstijd vooral bepaald door het aantal BUS CYCLES (tijd nodig voor het verplaatsen van 1 byte data over de bussen) nodig om de instructie te lezen en de eventuele data te verplaatsen. Hoe korter de instructie (aantal bytes zo klein mogelijk) hoe sneller de instructie uitgevoerd kan worden. Voor het gebruik van de CPU registers zijn geen extra buscycli nodig. Het programma zal sneller lopen als er registers gebruikt worden, i.p.v. extern geheugen. Voor de CPU bestaat een programma uit een reeks van 8 bit binaire getallen die geïnterpreteerd worden als commando s en data en die aangeven hoe een taak moet worden uitgevoerd, dit noemt men machinetaal. Staat er op een geheugenlocatie geen getal voor een zinvolle instructie, dan zal de processor het getal toch als dusdanig verwerken, en onvoorspelbare acties uitvoeren. Een voorbeeld van een commando is de sequentie 02h,12h,34h in het programmageheugen. Deze getallen worden door de controller geïnterpreteerd als een sprong (02h, de operation code of opcode) naar een geheugenlocatie 1234h (de operand of data). De instructies voor een 8051 controller kunnen bestaan uit 1, 2 of 3 bytes, afhankelijk van de hoeveelheid data die nodig is in de instructie. Alle programma s geschreven in verschillende programmeertalen, moeten eerst worden omgezet naar machinetaal vooraleer ze bruikbaar zijn voor de controller. 52

53 Elke instructie die kan uitgevoerd worden door de controller heeft een unieke opcode (eerste getal). Omdat 8 bit getallen (opcodes) voor ons niet erg leesbaar zijn, worden de instructies van de CPU met woorden en afkortingen voorgesteld. Deze MNEMONICS worden zo gekozen dat ze weerspiegelen wat het gevolg van de instructie is. Het zijn deze mnemonics die we op de PC gaan ingeven met behulp van een editor. We programmeren dan in assembler instructies. De instructie die hoort bij de vorige getalsequentie is LJMP 1234h. De assembler instructie is de vorm die bruikbaar is voor de programmeur, terwijl de machinetaal door de controller wordt gebruikt. Een assembler programma (vertaalprogramma) zal de mnemonics dan omzetten in opcodes en operands, die via het communicatiepakket in ons controllersysteem belanden (met behulp van het bootloader programma dat in de ROM van de microcontroller zit). De instructieset zijn alle mogelijke instructies (op het laagste niveau) die een controller kan uitvoeren en die dus ter beschikking staan van de programmeur om een programma te schrijven. De 8051 instructieset is geoptimaliseerd voor 8-bit en single bit controletoepassingen. Zo zijn er heel wat instructies die toelaten 1-bit variabelen (Booleaanse variabelen) te manipuleren. Deze bitvariabelen kunnen bits zijn van interne poorten of van verschillende special function registers of, bits uit interne bit-aanspreekbare RAM locaties voor het gebruik als flags. Dit is nuttig voor heel wat controle- en logische functies die booleaanse bewerkingen vereisen. Dit wordt duidelijk in de volgende delen van de tekst. Assembler programma's laten totale controle toe over uitvoeringssnelheid en geheugengebruik, dit betekent dat de programmacode compacter kan gemaakt worden dan bij een hogere programmeertaal en de uitvoeringssnelheid perfect kan gecontroleerd worden. Wanneer men over weinig geheugen beschikt en de timing kritisch is kan het aangeraden zijn om in assembler te programmeren. Het grote nadeel van assembler is dat de programmeur elk detail van het programma voor zijn rekening moet nemen, inclusief geheugen allocatie voor code en data, registergebruik, en de controle over de opslag van variabelen. Hogere programmeertalen verlossen de programmeur van de details die gepaard gaan met assemblerprogrammatie. Geheugen allocatie, beveiliging van variabelen, stackgebruik en vele andere details worden afgehandeld door de compiler. Het nadeel hiervan is echter dat de programmeur de controle verliest over deze details. Gewoonlijk zal de machinecode die resulteert van een programma, dat werd gemaakt in een hogere programmeertaal, beduidend groter zijn en trager werken dan de code uit een assembler programma dat dezelfde taak uitvoert. De keuze van de taal is afhankelijk van de aard van het project. Een efficiënt programma schrijven op een succesvolle manier, in om het even welke taal vereist echter een grondige kennis van de controller en zijn periferiebouwstenen en van het totale embedded systeem. Hierdoor is het schrijven van embedded software een uitdagender en dikwijls veel complexer geheel dan het schrijven van desktop software. 53

54 Voor de bespreking van de instructieset verwijzen we naar FTP site cd_microcontrollers\8051\8051 general\8051_programmers_guide.pdf. In appendix A en B is een lijst van de beschikbare instructies opgenomen. Volgende paragrafen geven enkele richtlijnen in verband met de aard van de instructies. Hiertoe worden ze in groepen ingedeeld. In de programmers guide worden de instructies in alfabetische orde afgewerkt. 4.2 De CPU en zijn basisregisters. De CPU van de 8051 familie is een 8-bit processor die o.a. bestaat uit volgende delen: een instructiedecoder, een arithmatic section met hierin de ALU of Arithmatic Logic Unit (rekenkundige en logische eenheid), een program controller, een timingen controledeel en een array van registers (8-bit geheugenlocaties in de controller) die aanspreekbaar zijn door de programmeur. Elke programma-instructie wordt door de instructie decoder ontcijferd, en de juiste interne timing signalen worden door de timing/controle-eenheid gegenereerd voor het controleren van de interne werking van de verschillende delen van de CPU. De Timing/Controle eenheid zorgt voor de syncronisatie van de dataflow in en uit de CPU. Hij coördineert de verplaatsing van data op de interne en externe bussen van de microcontroller en hij genereert de /PSEN, /RD en /WR signalen waarvan eerder sprake. De arithmatic section zorgt ervoor dat de data op de juiste manier bewerkt wordt en bestaat uit de ALU ( Arithmatic & Logic Unit), ACCU of A werkregister, B hulpregister, en PSW (Processor Status Word). De ALU is verantwoordelijk voor het rekenkundig bewerken van bytes. Hij handelt de optelling, aftrekking, vermenigvuldiging, deling en de logische bewerkingen af zoals 'and'en en 'or'en van data. De ALU zit intern in de CPU en staat niet rechtstreeks onder controle van de programmeur. Het enige deel van de CPU waar de programmeur via programma-instructies directe controle over heeft zijn de registers, die gebruikt worden om data te stockeren en te manipuleren. De registers bij de 8051 familie bevatten enkele speciale werkregisters: een accumulatorregister (ACCU of gewoon A) dat ingangsdata bevat voor de rekenkundige bewerkingen die met de ALU worden uitgevoerd. De ACCU is ook het register dat het resultaat bevat na een rekenkundige bewerking met de ALU, bij sommige bewerkingen maakt de ALU ook gebruik van het B register (x en /), een 16 bit datapointer register (DPTR), wordt gebruikt voor het aanwijzen van data die in het externe geheugen zitten en die moeten worden gemanipuleerd, Het PSW is een register met een bijzondere functie. Het PSW (program status word) is een register dat enkel bit informatie bevat. Dit wil zeggen dat de waarde van de byte niet belangrijk is, wel de individuele toestand van de STATUS BITS (ook vlaggen of vlag bits genoemd) (paragraaf 4.2.1). een reeks general-purpose registers (registerbanken) voor opslag van data. 54

55 Een 16-bit Program Counter (PC) register bevat steeds het adres van de volgende uit te voeren instructie. Het PC register wordt beïnvloed door de spronginstructies. De program counter controleert dus de sequentie waarin de instructies worden uitgevoerd door de CPU. De PC wordt impliciet gebruikt, en is niet rechtstreeks toegankelijk De PSW Figuur Program Status Word Het PSW register bevat een aantal vlaggen die aangepast worden door het resultaat van een uitgevoerde instructie (bv. een berekening). Bovendien worden enkele van de vlaggen als getalwaarde in een volgende berekening verder gebruikt. Er zijn ook speciale instructies die de vlaggen van de PSW gaan testen. In bovenstaande figuur worden de verschillende vlaggen aangegeven. Merk op dat de bits in de PSW een uniek bit-adres hebben. Aangezien de processor over bitinstructies beschikt, kan elke bit getest, veranderd of verplaatst worden. De PSW is een SFR. Ook andere SFR s (die met I/O modules samenwerken) kunnen status bits of vlaggen bevatten, maar deze worden beïnvloed door hardware gebeurtenissen. 55

56 De betekenis van de vlaggen is als volgt: De CY bit (CarrY flag), is een bit die aangeeft of er een overflow of underflow conditie is opgetreden, tijdens een vorige bewerking. De carry-bit wordt ook gebruikt als accumulator bij Booleaanse (bit) bewerkingen. De RS0 en RS1 bits worden gebruikt om één van de vier registerbanken te selecteren zoals aangegeven in de tabel onderaan in de figuur De AC (Auxiliary Carry) wordt gebruikt bij BCD bewerkingen en geeft een overflow aan van de LS nibble naar de MS nibble. De P bit geeft de pariteit aan van de accu. P=1 bij een oneven aantal 1's in de accu. De twee bits F0 en F1 zijn general purpose flagbits voor de gebruiker (vrij te gebruiken). De OV bit geeft aan dat er een overdracht is van bit6 naar bit7 in de ACCU, dit kan belangrijk zijn bij getallen waar de hoogste bit het teken voorstelt. Figuur geeft weer welke instructies de vlaggen beïnvloeden. Om te weten welke waarde de vlaggen zullen hebben na de berekening, moet je weten wat de getallen zijn die deel uitmaken van de bewerking, maar ook hoe de vlaggen door de betreffende instructie aangepast worden (zie instructieset). Figuur Instructies die de vlaggen beïnvloeden 56

57 4.3 Adresseringsmethoden Algemeen Om de instructieset van de controller te begrijpen, moet je weten hoe de CPU variabelen in het systeem kan adresseren. De algemene vorm van een instructie bestaat uit een mnemonic en een of twee operands (met tussen vierkante haakjes een parameter (operand) die niet steeds aanwezig is of [OPTIONEEL]): MNEMONIC [BESTEMMING],[BRON] MNEMONIC: BESTEMMING: BRON: de omschrijving van wat de instructie doet. vb: MOV = verplaats ADD = tel op,... het register waarop de bewerking wordt uitgevoerd, of de bestemming van het te verplaatsen getal, soms optioneel. vb: 030H = adres register 30H A = de accumulator R0 = verkort adresseerbaar register,... het register of het getal dat aangeeft van waar de tweede operand moet komen, of wat de tweede operand is. Deze parameter is niet steeds aanwezig (optioneel). Vb: #30h = getal 30h 030h = direct adres 30h R0 = verkort adresseerbaar register, Om de adressering toe te lichten gebruiken we de MOV of verplaats instructie. Die laat toe om gegevens te verplaatsen tussen de verschillende registers en geheugens in de controller. Andere instructies gebruiken een gelijkaardige adressering. De MOV instructie bestaat in 3 vormen: MOV voor het verplaatsen van getallen in de CPU (tussen registers) MOVC voor het lezen van getallen uit FLASH geheugen naar de accu (A) MOVX voor het lezen en schrijven van getallen tussen accu (A) en XRAM 57

58 Afhankelijk van de mnemonic (mov, movc, movx) zijn volgende operands mogelijk: Bestemming: A (alle MOV instructies) Rn (enkel MOV) Direct (enkel (enkel MOVX en MOV (MOVX onder (enkel MOVX (XC888 is hierop uitzondering, zie UM. (uitzonderlijk toepassen))) DPTR (enkel MOV) C (enkel MOV) BIT (enkel MOV) Bron: A (alle MOV instructies) Rn (enkel MOV) Direct (enkel (enkel MOVX en MOV (MOVX onder (enkel MOVC en MOVX) #getal (8 of 16 bit) (enkel (enkel (enkel MOVC) C (enkel MOV) BIT (enkel MOV) NIET ALLE COMBINATIES TUSSEN BESTEMMING EN BRON ZIJN MOGELIJK. OM TE WETEN WELKE MOGELIJKHEDEN TOEGELATEN ZIJN, MOET JE DE LIJST VAN DE INSTRUCTIESET RAADPLEGEN (zie appendix A&B). Verklaring symbolen voor bronnen en bestemmingen: A: accumulator of accu (SFR reken register) Rn: werkregister huidig geselecteerde bank (n=0, 1,,7) direct: een 8 bit hex getal dat het adres is van een direct adresseerbaar register vb: 15H (waarde tussen 00H en i kan 0 of 1 zijn. Die twee registers kunnen gebruikt worden voor indirecte wil zeggen dat pointer adressering gebruikt wordt. Bij indirecte adressering bevat de pointer (R1 of R0) het adres van de te lezen/schrijven register. DPTR: de Data PionTeR is het enige register dat door de CPU als een 16 bit register wordt gebruikt. Het bestaat uit twee 8 bit registers, die afzonderlijk ook gebruikt kunnen worden (DPH en DPL). Door sommige instructies worden ze als een geheel gezien. De DPTR is het enige register dat met één instructie aangepast of geladen kan worden als 16 bit register. 58

59 @DPTR: de DPTR is het enige register dat gebruikt kan worden voor indirecte adressering met een 16 bit adres, wat ook de enige manier is om gegevens uit het external data- of code memory op te halen. Dit is een omslachtige werkwijze, aangezien eerst de datapointer geladen moet worden met het adres van een variabele, alvorens via de indirecte adressering de variabele gelezen of geschreven kan worden. Als bron (MOVX) of bestemming (MOVC en MOVX) in de CPU kan alleen de accu gebruikt idem voorgaande, maar bij de waarde in de DPTR wordt, voor de duur van de instructie, de waarde van de accu opgeteld. De DPTR blijft na de instructie zijn originele waarde behouden (enkel voor code memory te PC staat voor Program Counter of programmateller. Dit 16 bit register wordt door de CPU gebruikt om bij te houden op welk adres de volgende opcode gelezen moet worden. Deze adressering werkt enkel met code memory. #getal: Wordt het # teken gebruikt, voor een getal, dan wordt het als een numerische waarde gezien, in het andere geval zal de assembler het getal als een adres zien (directe adressering). Het getal is normaal 8 bit, alleen voor het laden van de DPTR, wordt een 16 bit getal toegelaten. C: carry vlag in de PSW. De instructie zal slechts 1 bit manipuleren i.p.v een byte. BIT: elke bit die via bitadressering bereikbaar is Voorbeelden MOV A,#03FH ;plaats in de accu het getal 3FH Het getal dat in de accu moet komen staat expliciet in de instructie. We spreken in dat geval van immediate adressering. Het kardinaal teken (#) geeft aan dat het getal dat er na komt als een getal (numerieke waarde) en niet als een adres moet gezien worden. Getallen mogen in verschillende notaties ingegeven worden: 030H het getal 30 HEXADECIMAAL (16 tallig talstelsel) 030 =030D het getal 30 in het decimale talstelsel. Het vertaalprogramma (ASSEMBLER) zal dit getal wel eerst omzetten naar hexadecimaal, alvorens het in de instructie te plaatsen. 030 of 030D wordt dan 01EH. De omrekening zie je enkel in de opcode, ze is niet merkbaar in de broncode (naam.asm file), en ook niet in de listing (naam.lst). 59

60 B = binair talstelsel. Dezelfde redenering is van toepassing zoals bij de decimale getallen. Het getal wordt 21H. Sommige assemblers gebruiken de notatie 0x21 voor een hexadecimaal getal, 0b voor de binaire notatie. Je merkt op dat er voor elk getal een extra 0 wordt ingegeven. De 0 heeft geen numerische betekenis, en is enkel nodig om de assembler een foutloze omzetting te laten uitvoeren. De assembler herkent getallen alleen wanneer ze met een cijfer tussen 0-9 beginnen. Voor hexadecimale getallen die beginnen met de letters A-F is die extra 0 noodzakelijk. Uit gewoonte plaatsen we de 0 er overal bij. MOV A,03FH ;neemt een kopie van de inhoud van het ;register met adres 3FH naar de accumulator Alle adressen tussen 00H en FFH zijn toegelaten. De registers bevinden zich in de controller. Voor de onderste 128 registers is er geen verwarring mogelijk omdat zij slechts één keer in de controller aanwezig zijn. Voor de adressen 80H-FFH zijn er per adres twee registers aanwezig (figuur ). Omdat het adres van het bronregister expliciet in de instructie is opgenomen spreken we van directe adressering. Dit type instructie zal de SFR registers adresseren. Merk op dat bij de XC888 hetzelfde adres verschillende SFR s kan betekenen, afhankelijk van de mapping en paging (zie paragraaf 3.4.1). Voor de mogelijke talstelsels die gebruikt mogen worden bij de ingave van het adres verwijzen we naar de immediate adressering. Figuur Adressering registers 8051 Omdat er veel SFR adressen zijn, en hun functie I/O georiënteerd is, is het gebruik van een naam die informatie geeft over de functie van het SFR handiger in gebruik. In de voorbeeld programma s kan je zien hoe de numerische waarden door namen vervangen kunnen worden door het EQU directief te gebruiken, of door een bestand 60

61 op te nemen (include( )) in jou programma waarin de namen gelijkgesteld worden aan de betreffende waarde (EQU, BIT, DATA directieven). Bitadressen voor de registers 20h-2fh Figuur registers tussen 00h en 7fh MOV A,Rn ;zet in de accumulator de inhoud van ;een verkort adresseerbaar register. 61

62 In de figuur kan je zien dat er 8 registers zijn waarop de verkorte adressering van toepassing is: R0 t.e.m. R7. Deze 8 registers horen bij elkaar in een registerbank. De verkorte adressering geeft kortere (en dus ook snellere) opcodes dan andere vormen van directe adressering. In de controller zijn er 4 registerbanken aanwezig. De verkorte adressering is slechts van toepassing op één bank. In de PSW zijn er twee bits die bepalen welke bank dat is. De PSW is opgenomen in figuur Figuur PSW Bovendien zijn er instructies die alleen gebruikt kunnen worden met de verkort adresseerbare registers (R0-R7). Samen met de accumulator en het PSW register vormen deze registers de meest gebruikte registers in een programma. Merk op dat de registers zowel via hun 8 bit adres (4x8 registers altijd bereikbaar ongeacht de selectie via de adressen 00h-1fh) als de Rx naam (R0-R7 van de geselecteerde bank) bereikbaar zijn MOV A,@Ri ;in Ri (met i=0 of 1), staat een adres dat verwijst ;naar het eigenlijke register dat we wensen te lezen. Dit type van instructies wordt vooral gebruikt voor het adresseren van tabellen. Het wordt indirecte adressering genoemd omdat het adres van het te lezen/schrijven register niet expliciet in de instructie voorkomt. Wel wordt de plaats aangegeven waar 62

63 dat adres te vinden is. Er zijn zo maar twee mogelijke plaatsen: R1 of R0 van de huidig geselecteerde registerbank. De vier types van adressering (en combinaties hiervan) die werden besproken geven bijna alle mogelijke manieren om gegevens tussen registers te verplaatsen. Om dit te illustreren hebben we MOVE instructies gebruikt. Ook bij de andere instructies zijn dezelfde adresseringsmethoden mogelijk. Bij het maken van een programma kan je best met de instructielijst controleren of de instructie die je wenst te gebruiken wel bestaat. In de volgende drie voorbeelden geven we aan hoe het mogelijk is gegevens van en naar het externe geheugen te verplaatsen. Hier kan enkel indirecte adressering gebruikt worden. Omdat het adres nu 16 bit groot is, kan je R0 of R1 niet meer gebruiken. Die zijn immers maar 8 bit groot. Daarom zijn er in de controller 2 SFR s beschikbaar (DPH en DPL) die samen een 16 bit register vormen (de DPTR). De DPTR bestaat uit de registers DPL en DPH. Ze zijn zowel afzonderlijk als twee 8 bit SFR registers bruikbaar of als een 16 bit SFR. Sommige instructies gebruiken enkel de 16 bit samenvoeging. Die kan je herkennen door dat in de mnemonic de afkorting DPTR gebruikt wordt. Om ze als 8 bit registers aan te spreken kan je al die instructies gebruiken die van toepassing zijn op SFR s (directe adressering). MOVX A,@DPTR ;lezen van het externe RAM geheugen. ;schrijven naar het externe RAM geheugen. In beide gevallen bevat de DPTR het adres van de externe RAM locatie die gelezen/geschreven wordt. Het lezen of schrijven naar externe RAM kan enkel via de accumulator gebeuren. MOVC A,@A+DPTR ;lezen van het code of programma ;geheugen. Het externe programmageheugen kan enkel gelezen worden via de accumulator. Vermits het een ROM geheugen is, heeft het geen zin er naar te schrijven. Er zijn dan ook geen hardware mogelijkheden om dat te doen. De XC888 wijkt hier af van de standaard 8051 omdat hij een extra instructie heeft die schrijven naar het FLASH geheugen toelaat. Voor bijkomende uitleg verwijzen we naar de XC800_Arch_UM manual op de FTP site of LET OP: bij sommige controllers zijn er meerdere datapointers beschikbaar. Een controleregister laat toe om te bepalen hoe de pointers gebruikt kunnen worden. Bij de XC888 zijn er twee datapointers beschikbaar. Je kan via een SFR selecteren welke van de twee er gebruikt wordt (figuur ). De twee DPTR s gebruiken dezelfde geheugenlocaties, zodat je in de SFR lijst er maar 1 kan terugvinden (figuur ). Het is dus aan de programmeur om bij te houden welke DPTR je voor wat gebruikt. In de meeste gevallen volstaat het gebruik 63

64 van 1 DPTR. In dat geval hoef je het extra controleregister (extended operation register of EO) niet te gebruiken. Figuur Selectie van de DPTR0 of DPTR1 Figuur DPTR in de SFR s Als je aandachtig de instructieset doorneemt kom je twee instructies tegen die afwijken van bovenstaande uitleg: MOVX A,@Ri Deze instructies werden origineel bedoeld om te gebruiken met off chip XRAM geheugen. De 8051 controller laat dan toe om het P2 register te gebruiken als een page register. P2 kan bij extern geheugen niet meer gebruikt worden omdat de poortpinnen de hoogste 8 bit van de adresbus naar buiten brengen. Wanneer je echter de 2 bovenstaande instructies gebruikt wordt de inhoud van het P2 register op de adresbus geplaatst. Op die manier kan je het externe RAM geheugen verdelen in 256 pagina s van elk 256 bytes. Vermits op de Ri registers meer bewerkingen 64

65 mogelijk zijn dan op de DPTR laat dit een flexibele adressering toe. Wanneer het XRAM geheugen on chip zit kan deze techniek niet gebruikt worden. In dat geval worden er immers geen externe bussen gebruikt en is P2 een vrij bruikbare I/O poort. De XC888 heeft daarom een SFR dat de paging functie overneemt van P2 (figuur ). Figuur XC888 XADDRH SFR register Voorbeeldprogramma s algemene opmerkingen en eerste voorbeeld: Merk op dat we in de voorbeeld programma s kleine letters gebruiken. De assembler is niet hoofdletter gevoelig! Een programma wordt ingegeven in een IDE (Integrated Design Environment) en als een naam.asm bestand opgeslagen. De IDE bevat een compiler (assembler) die de code omzet naar uitvoerbare opcodes voor de controller (een naam.hex bestand) en een bestand waarin de eventuele syntax fouten staan weergegeven (een naam.lst). Uiteindelijk wordt de code overgebracht naar de controller via een bootloader (naam.hex bestand wordt door een ROM programma in de controller ingelezen en in het FLASH geheugen geladen). Er bestaan verschillende freeware IDE s voor 8051 compatibele microcontrollers. Het bootloader programma is controller specifiek, en kan je meestal downloaden op de site van de fabrikant. Voor de XC888 ( ) is dat het programma FLOAD of MEMTOOL, voor andere 8051 compatibelen moet je naar de site van de betrokken fabrikant. De $ lijnen zijn IDE afhankelijk en komen niet noodzakelijk overeen met de gebruikte IDE in het laboratorium. Daar is het mogelijk dat, ter vervanging van ALLE $ (inclusief het END directief) lijnen uit de voorbeeldprogramma s onderaan het programma volgende lijn opgenomen wordt: #include c:\naam.inc (naam is later te bepalen en afhankelijk van de werkomgeving). In de les wordt hierover bijkomende uitleg gegeven (kan zijn dat ook c of een andere programmeertaal gebruikt wordt). 65

66 ; Dit programma stuurt de waarde 05ah naar de LED s op de XC888 kaart. org 0000h ;start adres van het programma (zie uitleg labo) ; De poorten van de XC888 staan na reset als input geschakeld. Willen we de LED s ; aansturen moeten de poorten als output geschakeld worden. Dat doe je door naar ; het register 0b1h (P3_DIR) het getal 0ffh te schrijven. Het register is na reset ; toegankelijk zonder mapping of paging te gebruiken. mov p3_dir,#0ffh ;schakel poort 3 als output mov p3_data,#05ah ;schrijf het getal 05ah naar de poort 3 (LED s) ljmp 0000h ;sprong naar het startadres van het programma #include c:\xcez1.inc ;deze file zegt tegen de assembler welke SFR s er ;in de XC888 controller aanwezig zijn, en ook ;welk adres die hebben. Hierdoor kunnen we de ;namen van de SFR s gebruiken zoals die ;voorkomen in het databoek. Tussen de wordt de ;naam en het pad opgegeven van de include file. In ;dit geval staat het bestand in de root van de C ;drive op de PC. De vetgedrukte delen in het programma zijn geen instructies maar directieven voor de assembler. Een directief is een aanwijzing die zegt hoe het vertalen moet gebeuren. LET OP: Het END directief (laatste lijn in de xcez1.inc file, en hier dus niet te zien) zegt enkel tegen de assembler dat hij moet stoppen met vertalen. Omdat het geen instructie is, wordt het directief ook niet vertaald en via de opcodes doorgegeven naar de controller. Je zal op een andere manier de controller moeten zinvol bezighouden. Hij stopt immers nooit met het uitvoeren van instructies. In dit programma is daarom de: LJMP 16bit_address instructie, of Long JuMP instructie gebruikt die de controller zegt dat hij naar het adres 0000h moet springen. In de voorbeeld programma s die verder in de tekst zijn opgenomen laten we de directieven soms weg. Je moet ze wel altijd opnemen in je programma! Volgend directief gaan we ook veel gebruiken: 66

67 naam EQU getal Het EQU directief laat toe om aan een naam een getal toe te kennen. tellerbyte equ 032h ;tellerbyte=032h Overal waar we in ons programma het getal 32h willen gebruiken kunnen we nu ook de naam tellerbyte plaatsen. Hierdoor is het mogelijk om een programma leesbaar te maken. De equ kan zowel voor 8 bit als voor 16 bit getallen gebruikt worden. LET OP!! Het EQU directief zorgt er voor dat de assembler in het programma de naam vervangt door het bijhorende getal. Het directief zegt niet wat de betekenis van het getal is. Het kan dus evengoed een adres voorstellen. De uiteindelijke betekenis wordt bepaald door de instructie die de naam gebruikt: mov mov a,tellerbyte ;zet in de accumulator de inhoud van register 32h a,#tellerbyte ;zet in de accumulator het getal 32h naam DATA getal naam BIT getal Data en BIT zijn directieven met een gelijkaardige werking als het EQU directief. Het enige verschil is dat de assembler zal nagaan of de naam enkel gebruikt wordt in een instructie waarbij de naam een register (data) is of een bitvariabele (bit). Bij het equ directief is er geen enkele controle. Voorbeeldprogramma EQU: start equ 0000h ;de naam start wordt door de asm vervangen door ;het getal 0000h output equ 0ffh ;output=0ffh ledinfo equ 05ah ;getal dat we naar de LED s willen sturen org start ;start adres van het programma ; De poorten van de XC888 staan na reset als input geschakeld. Willen we de LED s ; aansturen moeten de poorten als output geschakeld worden. Dat doe je door naar ; het register 0b1h (P3_DIR) het getal 0ffh te schrijven. Het register is na reset ; toegankelijk zonder mapping of paging te gebruiken. mov p3_dir,#output ;schakel poort 3 als output mov p3_data,#ledinfo ;schrijf het getal 05ah naar de poort 3 ;(LED s) ljmp start ;sprong naar het startadres van het 67

68 ;programma #include c:\xcez1.inc Alle registers of bits die in het databoek een naam hebben, mogen met die naam in een programma gebruikt worden. Het is niet nodig (toegelaten) om ze met een equ directief te definiëren omdat in de include file reeds werd gedaan. Let op: sommige bits kunnen niet rechtstreeks geadresseerd worden, omdat de hardware in de controller dit niet toelaat. Je krijgt hiervoor geen foutmelding!! 4.4 Wiskundige instructies Inleiding Deze instructies voeren een berekening uit op één of twee variabelen. Een variabele kan maar aangepast worden wanneer hij in een register staat. De tweede variabele kan de inhoud van een register zijn, maar ook een getal (constante) dat in de instructie wordt meegegeven. De 8051 CPU core heeft een ACCUMULATOR STRUCTUUR. De ACCU of A register heeft een speciale functie. Enkele belangrijke berekeningen kunnen enkel in de accumulator gebeuren (+, -, x, /, en sommige bitmanipulaties). Merk op dat de CPU slechts de vier hoofdbewerkingen kan uitvoeren, aangevuld met enkele logische bewerkingen (staan niet vermeld tussen de haakjes, omdat die op bijna alle registers uitgevoerd kunnen worden: AND, OR, XOR, INC, DEC,..). Het is niet onmogelijk om een sinus of een log te berekenen, je kan immers alle bewerkingen reduceren tot de vier hoofdbewerkingen. Alle berekeningen gebeuren op 8 bit getallen (vandaar dat de 8051 een 8 bit CPU is). De PSW is een belangrijk register bij het uitvoeren van de 4 hoofdbewerkingen. Het geeft informatie over de uitkomst van de berekening. Bij sommige bewerkingen (+ en -) kan de uitkomst 9 bit groot zijn. Die negende bit wordt in de PSW tijdelijk opgeslagen, zodat hij in kettingberekeningen verder verwerkt kan worden. Maar ook bij delen door 0 wordt in de PSW een indicatie gegeven (OV bit) De CPU kan enkel met gewone binaire getallen rekenen. Omwille van de compactere schrijfwijze noteren we deze getallen meestal in een hexadecimale schrijfwijze. Wensen we andere binaire voorstellingen van getallen te verwerken (BCD, two's complement,...), dan zullen we ons programma zo moeten schrijven dat er eventuele correcties gebeuren op de uitkomst van de berekening. Zo is B (09H) B (01H) = B (0AH) voor de CPU. Wij verwachten in onze decimale wereld 10D als uitkomst, dit is B als BCD voorstelling. Een correctie is dus noodzakelijk wanneer we decimale resultaten verwachten. Omdat die correcties niet steeds even eenvoudig zijn, zullen veel programmeurs er de voorkeur aan geven om alle getallen eerst naar een gewone binaire vorm om te 68

69 rekenen, ze inwendig te verrekenen, en alvorens ze als output naar buiten te sturen, opnieuw om te rekenen naar het gewenste talstelsel (hex of decimaal). Overzicht talstelsels: Een decimaal getal kan per karakter 10 toestanden weergeven: Een getal bestaat uit meerdere van die karakters: Hierbij is: Een binair getal bestaat uit een aantal bits. Een getal dat bestaat uit één bit kan met één cijfer worden weergegeven en kan maar twee waarden aannemen: 0 of 1. Bestaat het getal uit meerdere cijfers, dan kunnen grotere getallen verkregen worden: Meestal wordt het achtervoegsel B gebruikt. Het is belangrijk dat er duidelijke afspraken gemaakt worden over het talstelsel waar in gewerkt wordt. Inwendig in een computer bestaan er enkel binaire getallen. Ook al produceert een winkelkassa een bedrag in het decimaal talstelsel, inwendig wordt alles binair verwerkt. Vermits de controller enkel in binair kan rekenen zal het ingegeven getal eerst van decimaal naar binair omgezet moeten worden. Alle totalen worden berekend, waarna de uitkomst opnieuw naar een decimaal getal omgezet wordt. 18=10010B Voor grotere getallen wordt het aantal eentjes en nullen aanzienlijk, waardoor het moeilijk wordt om verbaal getallen door te geven: 511= B 65535= B Om dit probleem op te lossen worden getallen in groepjes van 4 bits weergegeven: 511= B 65535= B Om minder karakters te moeten gebruiken, wordt het hexadecimale systeem gebruikt. Zo kan men per groep van 4 bits één hexadecimaal getal gebruiken. Een hexadecimaal getal kan per karakter 16 toestanden weergeven, de toestanden 0 tot en met 15 worden hier weergegeven door de karakters: A B C D E F 69

70 Een getal bestaat uit meerdere van die karakters: 1B3H= 1*100H + b*10h + 3*1H Hierbij is 100H=10H*10H ; 10H=FH+1H De compacte schrijfwijze is dan ook de belangrijkste reden waarom het hexadecimale talstelsel veelvuldig gebruikt wordt. Het achtervoegsel H wordt gebruikt om aan te geven dat het over een hex getal gaat. Bij decimale getallen wordt geen achtervoegsel gebruikt. Omdat wij graag weten over hoeveel eenheden het werkelijk gaat, rekenen we het hex getal soms om naar een decimaal getal. Hierbij is: Zo is: 511= B = 1FFH 65535= B = FFFFH Decimaal Binair Hexadecimaal BCD B 0H B B 1H B B 2H B B 3H B B 4H B B 5H B B 6H B B 7H B B 8H B B 9H B B AH B B BH B B CH B B DH B B EH B B FH B Een BCD (Binary Coded Decimal) getal is een binaire voorstelling van een decimaal getal waarbij elke digit van het decimaal getal voorgesteld wordt door zijn eigen 4bit binaire sequentie, de codes 1010B tot 1111B (hexadecimaal de letters A-F) worden hier dus niet gebruikt. Voor decimale getallen die bestaan uit één karakter (bij de cijfers 0-9) is de binaire voorstelling en BCD voorstelling gelijk. Zowel bij decimale als BCD getallen zijn de letters A-F uiteraard niet toegelaten. 70

71 In de vorige tabel zijn ook de BCD voorstellingen opgenomen. Merk op dat er voor elk decimale karakter 4 bits gebruikt worden, en dat de coderingen boven 1001 niet voorkomen. De BCD voorstelling wordt soms gebruikt om decimale getallen inwendig in de computer voor te stellen. Zo is: 511= B (in BCD) 65535= B (in BCD) Een BCD voorstelling van een getal ziet er hetzelfde uit als een gewoon binair getal, alleen stelt ze een totaal andere numerische waarde voor. Inwendig in de computer worden alle getallen binair voorgesteld. Hexadecimale en decimale voorstellingsvormen worden (door ons) uitwendig gebruikt. Wil de computer juiste berekeningen kunnen uitvoeren, is het belangrijk dat we bij het schrijven van het programma rekening houden met het gebruikte talstelsel. Indien niet uitdrukkelijk vermeld gebruiken we steeds HEX getallen ADD(C) De ADD of tel op instructie laat toe om de som te maken tussen twee 8 bit getallen waarvan er minstens een in de accu moet staan. De uitkomst van de berekening komt steeds in de accu te staan. Omdat de som van twee 8 bit getallen een 9 bit uitkomst kan opleveren, wordt de carry gebruikt als negende bit. Er zijn vier mogelijke manieren om de instructie te gebruiken: ADD A,Rn ADD A,direct ADD A,@Ri ADD A,#getal tweede operand is R0-R7 van de huidig geselecteerde registerbank tweede operand is een direct adresseerbaar register met een adres 00H-FFH het adres van het register dat de tweede operand bevat, staat in R0 of R1 van de huidig geselecteerde registerbank de tweede operand is een 8 bit getal dat in de instructie staat De ADDC of ADD with Carry instructie is identiek aan de ADD instructie, behalve dat ook nog de waarde van de carry, zoals die was vlak voor de instructie, mee opgeteld wordt. Hierdoor is het mogelijk om getallen met elkaar op te tellen die groter zijn dan 8 bit. De Carry vlag is een bit in het PSW register die aangepast wordt na het uitvoeren van o.a. een add of addc instructie. Voorbeeld van een 8 bit optelling 71

72 (dit voorbeeld is geschreven op de READS51 IDE) main equ 00000h ;start adres programma reg1l equ 020h ;cpu registers die we gaan reg1h equ 021h ;gebruiken reg2l equ 022h reg2h equ 023h org main ;assembler zeggen waar programma ;start mov reg1l,#020h ;getal 20h in reg1l laden mov a,#057h ;getal 57h in accu laden add a,reg1l ;tel register op bij accu mov reg2l,a ;uitkomst naar reg2l lus: ljmp lus ;blijf hier wachten (einde van programma) #include c:\xcez1.inc Merk op dat als de som van de inhoud van de accu en reg1l groter wordt dan ffh, de carry (CY of c vlag) op 1 komt te staan. In het andere geval blijft (wordt) de carry 0. Dit programma is vrij zinloos omdat er geen output gegenereerd wordt. Voorbeeld van een 16 bit optelling main equ 00000h ;start adres programma reg1l equ 020h ;cpu registers die we gaan reg1h equ 021h ;gebruiken reg2l equ 022h reg2h equ 023h uitl equ 024h uith equ 025h org main ;assembler zeggen waar programma ;start mov reg1l,#0f0h ;getal f0h in reg1l laden mov reg1h,#035h ;getal 35h in reg1h laden mov reg2l,#060h ;getal 60h in reg2l laden mov reg2h,#015h ;getal 15h in reg2h laden ; we gaan de 16 bit optelling uitvoeren van 35f0h h mov a,reg2l ;eerst som lage registers add a,reg1l ;houden geen rekening met ;carry uit vorige berekeningen mov uitl,a ;uitkomst bewaren 72

73 mov a,reg2h ;hoge deel verwerken addc a,reg1h ;nu moet de carry uit de vorige ;berekening wel gebruikt worden mov uith,a ;uitkomst naar uith lus: ljmp lus ;einde programma #include c:\xcez1.inc In het programma worden alleen 8 bit getallen gebruikt, alhoewel het over een 16 bit berekening gaat. De programmeur moet weten hoe hij de deelgetallen moet bewerken om uiteindelijk tot een juiste uitkomst te komen. Die 16 bit uitkomst staat in 2 acht bit registers. Ook hier zal de programmeur bij de verdere verwerking rekening moeten houden met de waarde en de plaats van de deelgetallen SUBB De SUBstract with Borrow instructie laat toe om het verschil te maken tussen het getal in de accumulator en een tweede operand. De adressering is identiek aan die van de ADD instructie. De carry heeft een andere betekenis dan bij de optelling, de carry krijgt de functie van borrow. De carry wordt nu op 1 gezet (na het uitvoeren van de subb instructie), als de inhoud van de accumulator kleiner was dan de tweede operand. Om de berekening te kunnen uitvoeren, moest de CPU gaan lenen. Dit wordt aangegeven door de carry op 1 te zetten. De instructie zal altijd de waarde van de carry, zoals die was vlak voor de uitvoering van de instructie, als extra aftrekken van het resultaat. Dit is enkel zinvol als we berekeningen van meer dan 8 bit uitvoeren. Het is daarom soms nodig om de carry op 0 te zetten alvorens een verschil te berekenen. Voorbeeld van een 8 bit verschil main equ 00000h ;start adres programma reg1l equ 020h ;cpu registers die we gaan reg1h equ 021h ;gebruiken reg2l equ 022h reg2h equ 023h org main ;assembler zeggen waar programma ;start mov reg1l,#020h ;getal 20h in reg1l laden mov a,#057h ;getal 57h in accu laden clr c ;carry op nul zetten subb a,reg1l ;verminder accu met inhoud reg1l 73

74 ; omdat er niet geleend moet worden bij de berekening zal de ; carry nu op 0 staan mov reg2l,a ;uitkomst naar reg2l (=37h) ljmp main ;blijf dit doen De registers reg1h en reg2h worden in het programma niet gebruikt. Ze werden wel met het equ directief een waarde toegekend, wat eigenlijk overbodig is. Indien we 001h-001h zouden berekenen, dan is het resultaat afhankelijk van de Carry voor de aanvang van de berekening (de clr c instructie in programma zet c=0). Stel c=1 (we laten de clr c instructie weg): dan is de uitkomst: 001h-001h-c=0ffh en de Carry staat opnieuw op 1. De CPU voerde volgende berekening uit: 001h-001h-1 kan niet worden berekend omdat de uitkomst negatief is. Daarom gaat de CPU lenen ( geeft dit aan door c op 1 te zetten) en maakt volgende berekening: 100h+001h-001h-1=0ffh als uitkomst, en de Carry op 1 omdat er 100h geleend is. Stel c=0 (hier zijn we zeker van als we de clr c instructie toevoegen): Dan is de uitkomst 001h-001h-0=000h en de Carry staat nu op 0 (lenen was niet nodig) Voorbeeld van een 16 bit verschil main equ 00000h ;start adres programma reg1l equ 020h ;cpu registers die we gaan reg1h equ 021h ;gebruiken reg2l equ 022h reg2h equ 023h uitl equ 024h uith equ 025h org main ;assembler zeggen waar programma ;start mov reg1l,#010h ;getal 10h in reg1l laden mov reg1h,#035h ;getal 35h in reg1h laden mov reg2l,#060h ;getal 60h in reg2l laden mov reg2h,#015h ;getal 15h in reg2h laden ; we gaan het 16 bit verschil berekenen van 3510h h mov a,reg1l ;eerst verschil lage registers 74

75 clr c ;wensen een vroegere carry niet ;te gebruiken subb a,reg2l ;bereken 010h-060h-0 (c=0) mov uitl,a ;uitkomst bewaren ; omdat 010h 060h een negatief getal zou geven zal de cpu gaan lenen waardoor ; het verschil van 110h-060h berekend wordt. Het gaan lenen wordt aangegeven ; door de carry te zetten. ; In een volgende berekening moet de carry verrekend worden. mov a,reg1h ;hoge deel verwerken subb a,reg2h ;nu moet de carry uit de vorige ;berekening wel gebruikt worden mov uith,a ;uitkomst naar uith ; omdat de uitkomst van 3510h-1560h een positief getal is, zal de carry nu op 0 ; staan. Stel dat de uitkomst negatief zou zijn dan zal de carry op 1 staan. ; De uitkomst klopt dan slechts gedeeltelijk zoals volgend voorbeeld aangeeft: ; 1234h 1235h = ffff en c=1 ; Eigenlijk is de uitkomst negatief. Microcontrollers kennen alleen positieve gehele ; getallen. Er zal dus een foutdetectie nodig zijn (tenzij je op voorhand de mogelijke ; resultaten beperkt). lus: ljmp lus ;eindeloze lus (einde programma) INC/DEC De INCrement of DECrement instructies verhogen, of verlagen de waarde in het betreffende register met 1. Er worden geen vlaggen aangepast. Wanneer een register de waarde 0ffh bevat en de inc instructie wordt uitgevoerd, komt de waarde op 000h, zonder dat de c vlag aangepast wordt. Wanneer de waarde in een register op 000h staat en de dec instructie wordt gebruikt, komt de waarde op 0ffh, zonder dat de c vlag aangepast wordt. Voorbeeld inc en dec instructies inc R0 ;register R0 wordt met een verhoogd inc a ;accumulator wordt met een verhoogd inc 23H ;register 23H wordt met een verhoogd mov R0,#023h ;het getal 23H wordt in R0 geladen ;de inhoud van het register, waarvan ;het adres in R0 staat wordt met een ;verhoogd (inhoud register 23h +1) dec R0 ;register R0 wordt met een verminderd 75

76 dec a ;accumulator wordt met een verminderd dec 23H ;register 23H wordt met een verminderd mov R0,#023h ;het getal 23H wordt in R0 geladen ;de inhoud van het register, waarvan ;het adres in R0 staat wordt met een ;verminderd (inhoud register 23h-1) INC DPTR Deze instructie is de enige 16 bit bewerking die door de core uitgevoerd kan worden. Ze verhoogt de waarde van het 16 bit register DPTR (dat bestaat uit twee 8 bit registers), met 1. Ook hier worden er geen vlaggen aangepast. Deze instructie wordt vooral gebruikt als de DPTR als pointer gebruikt wordt. Wanneer de waarde in DPH en DPL 0ffh is, dan zal na de inc dptr instructie de waarde op 000h en 000h komen, zonder dat de c vlag aangepast wordt MUL AB Met deze instructie wordt de inhoud van de accumulator vermenigvuldigd met de waarde van het B register. Het B register is een SFR die enkel bij de MUL en de DIV instructies een speciale functie heeft. Omdat de uitkomst groter is dan 8 bit (max 16 bit), worden A en B gebruikt voor het resultaat. Het B register bevat de 8 hoogste bits van het resultaat, de accumulator bevat de 8 laagste bits. Voorbeeld mul instructie mov a,#023h ;getal 23H in de accumulator mov b,#04ah ;getal 4aH in het b register mul ab ;vermenigvuldig na het programma staat er in de accumulator 1eh en het b register bevat 0ah, wat als uitkomst geeft 0a1eh. Indien a en b een maximale waarde van 0ffh zouden bevatten, is de uitkomst van de vermenigvuldiging fe01h, wat nog steeds een 16 bit getal is. Er kan dus nooit een overflow optreden. Is het de bedoeling om grotere getallen met elkaar te vermenigvuldigen, dan komt er wel wat rekenwerk aan te pas. In volgend voorbeeld stellen de letters een 8 bit register voor (vb x en y) de notatie xy is dan het product van de inhoud van de registers x en y, en dus een 16 bit getal (8bit vermenigvuldigen met 8 bit geeft een 16 bit uitkomst). De notatie x_y wil zeggen dat we de twee registers als één 16 bit getal 76

77 bekijken. In het voorbeeld vermenigvuldigen we twee 16 bit getallen met elkaar. De 0 in het voorbeeld is een byte met als inhoud 000h Er zijn dus 4 acht bit registers nodig om de twee 16 bit getallen op te slaan die we met elkaar willen vermenigvuldigen. De vermenigvuldiging van de twee 16 bit getallen wordt vervangen door vier vermenigvuldigingen van 8 bit, met telkens een 16 bit uitkomst (vy, uy, vx en ux). Door de 16 bit tussenresultaten 0, 8 of 16 bit op te schuiven (doen we met de 0 byte toe te voegen) houden we rekening met de numerieke waarde van elk deelgetal. Die tussenresultaten worden bij elkaar opgeteld om uiteindelijk een 32 bit resultaat te geven. Onderstaand voorbeeld toont dit met 2 decimale getallen: DIV AB Bij de deling wordt de inhoud van de accu door de inhoud van het B register gedeeld. Bij een deling door 0 wordt de overflow flag geset. De uitkomst van de deling wordt in de accumulator bewaard, in het B register staat de rest van de deling. Voorbeeld: mov a,#023h ;getal 23H in de accumulator mov b,#04ah ;getal 4aH in het b register div ab ;delen (a door b) na het programma staat er in de accu 0H en het b register bevat 23H mov a,#04ah ;getal 4aH in de accumulator mov b,#023h ;getal 23H in het b register div ab ;delen na het programma staat er in de accu 2H en het b register bevat 4H 77

78 4.4.8 DA A Zoals reeds vroeger werd aangehaald, kan de processor enkel rekenen met binaire getallen. In een vorige paragraaf hebben we gezien dat we gemakkelijkheids halve de hex_notatie gebruiken en dat dit slechts een andere vorm is om binaire getallen weer te geven. Soms is het wenselijk om met andere talstelsels te rekenen. De meest voorkomende zijn dan de two's complement en de BCD getallen. De CPU weet niet welk type van variabelen we gebruiken, hij gaat er van uit dat het steeds gewone binaire getallen zijn. Staan de getallen in een andere voorstelling (bv. BCD), dan worden foutieve uitkomsten bekomen. De processor zal voor binaire getallen in zowel de two s complement, als voor de BCD voorstelling vlaggen aanpassen na een berekening (genereren), zodat aangepaste (zelf te schrijven) software de nodige correcties kan doorvoeren. Voor de BCD voorstelling is er zelfs een instructie voorzien, die de correctie doorvoert. Let wel, de vlaggen en de correctie instructie werken slechts in welbepaalde gevallen. De instructie kan in geen enkel geval gebruikt worden om een omzetting tussen talstelsels door te voeren. Aangezien je heel uitzonderlijk two's complement getallen zal verwerken met deze core, gaan we daar niet verder op in. Voor de BCD voorstelling gebeurt dit wel meer. De correctie instructie is de Decimal Adjust Accumulator. Ze werkt enkel vlak na de optelling van twee 8 bit getallen, die voor de berekening reeds in de BCD notatie stonden. Voorbeeld: mov a,#015h ;zet de BCD voorstelling van het getal 15 in de accu ;Je zou kunnen denken dat de instructie zonder de H gebruikt moet worden: ;mov a,#15 ;Stel dat we dit zouden doen, dan zal de assembler het getal eerst omrekenen naar ;het hex talstelsel, waardoor volgende instructie uitgevoerd wordt: ;mov a,#0fh ;wat natuurlijk niet het gewenste BCD getal 15 = is. mov R0,#026H ;zet het getal 26H in R0 add a,r0 ;maak de optelling ;na de optelling staat er in de accumulator 15H + 26H = 3bH da a ;voer de correctie uit ;nu staat er in de accumulator 41H wat wel de juiste BCD som is. 78

79 4.5 Logische instructies Inleiding Bij de wiskundige instructies wordt de inhoud van een register, of een operand als een 8 bit getal gezien. De bits binnen de byte horen bij elkaar, en vormen een geheel. Bij de logische operaties is dit niet het geval. Elke bit wordt als een afzonderlijke variabele gezien, en bij een logische bewerking tussen twee bytes worden de berekeningen uitgevoerd op de overeenkomstige bits binnen de bytes. Er zijn dus 8 resultaten na de bewerking. De accumulator heeft nog altijd een bevoorrechte rol, alhoewel ook andere registers gebruikt kunnen worden voor het uitvoeren van sommige instructies ANL/ORL/XRL Met de ANd Logical instructie worden de overeenkomstige bits van de variabelen geand. OR Logical en exclusive or Logical werken op een vergelijkbare manier. Voorbeelden orl,anl,xrl mov a,# b ;we laden een binair getal in a anl a,# b ;voeren de and bewerking ;uit met een constante Na de bewerking zal in de accu b staan. De ANL instructie kan gebruikt worden om een deel van een register op nul te zetten, zonder dat de andere bits wijzigen (in het voorbeeld de laagste 4 bits). mov a,# b ;we laden een binair getal in a orl a,# b ;voeren de or bewerking ;uit met een constante Na de bewerking zal in de accu b staan. De ORL instructie wordt soms gebruikt om een deel van een register op 1 te zetten, zonder de andere bits aan te passen (in het voorbeeld de hoogste 4 bits). mov a,# b ;we laden een binair getal in a xrl a,# b ;voeren de or bewerking ;uit met een constante Na de bewerking zal in de accu b staan. De XRL instructie wordt soms gebruikt om bits te inverteren door een exclusive OR toe te passen met een constante waar in op de te inverteren bitposities een 1 staat. De bits die men niet wil 79

80 veranderen worden op 0 gezet. Ook voor het programmeren van een compare functie kan deze instructie samen met een JZ instructie als volgt worden gebruikt: xrl a,# b ;we gaan de inhoud van a vergelijken met 3 jz label ;spring naar label als gelijk aan Specifieke accumulator instructies CLR A met deze instructie worden alle bits in de accu op 0 gezet CPL A ComPLement de accu maakt een ones complement van de waarde in de accu Voorbeelden mov cpl a,# b a ;de accu bevat nu b, wat het complement is van b. clr a ;de accu bevat nu b, ongeacht de vorige waarde. Rotate instructies schuiven de bits in de accumulator. De tweede letter in de instructie geeft de richting aan waarin de bits opgeschoven worden: Left of Right. Het is ook mogelijk om de carry als negende bit mee door te schuiven. Er wordt dan aan de instructie een C toegevoegd. In het voorbeeld wordt grafisch weergegeven wat de instructie doet. Voorbeelden RL, RR, RLC en RRC mov a, b ;zet in de accu b clr c ;zet de carry vlag op 0 RL A ;A= b CY=0 RR A ;A= b CY=0 80

81 RR A ;A= b CY=0 RLC A ;A= b CY=1 RLC A ;A= b CY=1 RRC A ;A= b CY=1 SWAP A Deze instructie verwisselt in de accu de hoge nibble en de lage nibble van plaats. Voorbeeld SWAP A mov a,# b swap a na de instructie staat er in de accumulator: a= b 81

82 4.6 Verplaats instructies Deze instructies verplaatsen 8 bit getallen in het systeem. Hierbij komen alle registers en het external memory in aanmerking. Het external code memory kan echter niet geschreven worden. Hiertoe ontbreekt het aan instructies, en controle lijnen. De MOV instructies werden reeds als voorbeeld behandeld. We beperken ons hier tot de 3 buitenbeentjes: PUSH, POP, XCH De exchange instructie De exchange instructie verwisseld de inhoud van de twee registers. De xchd werkt slechts op de laagste 4 bit in de betreffende registers (d staat voor digit en een digit is 4 bits groot (4bits=nibble)). Een voor beeld is terug te vinden in de uitgebreide instructieset De systeemstack, stackpointer en de PUSH / POP instructies De systeemstack en stackpointer (call instructies) De stack ( ook wel stapelgeheugen) gebruikt een aantal GPR s die elkaar in adres moeten opvolgen (GPR s tussen 00h en ffh kunnen hiervoor gebruikt worden). De plaats en het aantal worden door de programmeur bepaald (gereserveerd door ze zelf nergens te gebruiken!). Reserveren we er te veel, dan blijven er een deel niet gebruikt. Reserveren we er te weinig, dan zal het systeem vastlopen omdat we variabelen die buiten de gereserveerde zone zijn opgeslagen overschrijven. Het benodigde aantal is afhankelijk van het programma dat we door de controller laten uitvoeren. Sommige controllers hebben een stack van 6 locaties diep, andere gebruiken een minimale stack van 128 bytes. Voor de XC888 volstaan meestal 20H bytes (blijkt uit ervaring, neem er 40h als je xcez routines gebruikt). Eens het programma klaar is moet men, in principe, nagaan of de stack voldoende opslagruimte biedt voor het uit te voeren programma. Data-elementen die in een bepaalde volgorde op stack worden geplaatst moeten er in de omgekeerde volgorde weer worden afgehaald. De stack heeft een LIFO werking (Last In First Out). De gegevens die door de CPU in de stack bewaard worden zijn de terugkeeradressen bij: een subroutine-oproep via een (L)CALL instructie een interrupt-routine oproep via interrupt verwerking. Daarnaast kan ook de programmeur beroep doen op de stack om tijdelijk gegevens op te slaan (zie PUSH en POP instructies in volgende paragraaf). 82

83 Bij de stack hoort een Stack Pointer (SP), wat een SFR is. Het SP register geeft de laatst gebruikte plaats aan in de stack. Het bevat m.a.w. een adres, vandaar de naam (stack)pointer. De pointer wijst naar de eerste vrije locatie waar de controller een terugkeeradres kan bewaren bij een CALL of INTERRUPT, of het programma gegevens kan opslaan met push en pop instructies. Na RESET staat de SP op 07h (default waarde). De SP wordt automatisch geïncrementeerd, voordat data wordt gestockeerd op de plaats waar de SP naar wijst ( pre-increment bij PUSH, CALL instructies en een interrupt), de SP wordt gedecrementeerd nadat de data werd gelezen ( post-decrement bij RET,RETI en POP instructies). Dit mechanisme verloopt trouwens volledig automatisch! Als programmeur moet u hiervoor niets ondernemen. De stack kan zich overal in GPR s bevinden, en moet dus niet starten op adres 08H. De programmeur kan dit veranderen door de SP te initialiseren met een andere waarde a.d.h.v. een MOV SP,# xx instructie, waar xx staat voor het adres waar de stack moet starten (eerste gebruikte register heeft adres xx+1). Dit automatische mechanisme bij een subroutine-call wordt aangegeven in figuur Voor bijkomende uitleg i.v.m. de (L)CALL instructie verwijzen we naar paragraaf in dit hoofdstuk. Als vertreksituatie nemen we aan dat de SP nog op de resetwaarde 07h staat en dat de controller instructies uitvoert in een hoofdroutine en zo bij de 'CALL subroutine' instructie komt. De controller zal een routine op het adres 'subroutine' moeten gaan uitvoeren, maar eerst zal de SP met één worden verhoogd en zo wijzen (1) naar de volgende vrije locatie 08h op de stack. Dan zal de controller de low byte van het adres van de instructie na de CALL subroutine (YY) op stack plaatsen (2). De volgende actie is de SP weer met één verhogen tot locatie 09h (3) en ook de high byte (XX) van het adres op stack plaatsen (4). De PC kan nu worden geladen met het adres 'subroutine' (5) zodat de controller op dit adres de volgende instructie gaat ophalen (sprong naar subroutine). Bij het beëindigen van de subroutine zal de RETurn instructie als gevolg hebben dat de high byte van de PC zal geladen worden met de inhoud van de geheugenlocatie waar de SP naar wijst (7) en dat de SP daarna met één wordt verminderd. Daarna wordt op het adres waar de SP naar wijst de byte opgehaald die in de low byte van de PC wordt geplaatst (8) waarna de SP weer met één wordt verminderd. De SP staat nu op de waarde die hij had voor het uitvoeren van CALL subroutine. 83

84 Doordat de PC nu is geladen met het terugkeeradres (XXYY) dat op stack werd geplaatst bij de CALL, zal de volgende instructie op dit adres worden opgehaald, de controller is m.a.w. terug naar de hoofdroutine gesprongen. Dit mechanisme verloopt volledig automatisch bij een CALL en RET instructie en de programmeur moet hiervoor geen acties ondernemen. Adres van de instructies 16-bits XXYY Externe controllergeheugen met instructies instructie n instructie n+1 instructie n+2 instructie n+3 call subroutine instructie n+5 instructie n Stack-pointer register (wijst naar intern geheugen in de controller) SP+1 SP+1 SP 8-bit SP na reset Interne controllergeheugen YY XX 07h 08h 09h 0Ah 0Bh 2 opslaan LSB opslaan 4 MSB 5 PC = subroutine 9 Jump to XXYY Program counter 16-bit PChigh PClow subroutine 6 Jump to subroutine return 7 8 PChigh =XX SP-1 PClow =YY SP-1 Figuur Voorbeeld van stack-werking bij een (L)CALL en RETurn instructie Push en POP instructies 84

85 De programmeur kan ook zelf data op de stack plaatsen, en data van stack halen, door gebruik te maken van resp. PUSH en POP instructies. Door deze instructies te gebruiken kunnen registers tijdelijk bewaard worden, zonder dat hiervoor (behoudens voor de stack) registers gereserveerd moeten worden. PUSH register Deze instructie laat toe de inhoud van een direct adresseerbaar register op de stack te bewaren. Hierdoor kan het tijdelijk vrijgemaakt worden voor een berekening. Dit is vooral voor de A, B en PSW registers handig, maar ook voor andere systeemregisters (syscon0, DPh en DPL, ). De SP wordt impliciet gebruikt als adresregister voor indirecte adressering. Telkens de inhoud van een register naar de stack geschreven wordt (PUSH register), zal de SP eerst automatisch met 1 verhoogd worden, waardoor hij naar de volgende vrije locatie wijst. Dan wordt de waarde in het register in de stack zone geschreven. Het register kan nu voor iets anders gebruikt worden. POP register Bij het lezen van een byte uit de stack naar een register (POP register) gebeurt het omgekeerde (eerst lezen waarde van de stack naar het aangeduide register, dan wordt de SP-1). De stack werkt als een LIFO (Last In/ First Out) memory. Er wordt niet onthouden wat er waar zit, er is enkel de SP die aangeeft waar de laatste variabele op de stack opgeslagen is. De gebruiker moet zelf instaan voor het juiste gebruik van het LIFO geheugen. Figuur geeft een grafische voorstelling van de stack ruimte. Na initialisatie wijst de SP naar de eerste locatie van de stack-1. In de figuur wordt er van uit gegaan dat de registers 86h t.e.m. 90h vrij zijn (door ze niet te gebruiken als opslagruimte voor variabelen in het programma). Merk op dat register 85h wel gebruikt kan worden. De SP wordt geladen met deze waarde, maar zal eerst verhoogd worden alvorens naar de stack te schrijven. De beschikbare stack ruimte wordt bepaald door het aantal opeenvolgende registers die we niet gebruiken in het programma. De werking voor PUSH en POP is dus analoog aan de werking bij interrupts en (L)CALL instructies. De PUSH en POP instructies gebruiken wel maar 1 byte stack ruimte, i.p.v. 2 voor de interrupt en (L)CALL. Vermits je in een interruptroutine of subroutine de PUSH en POP instructies kan gebruikt (soms moet gebruiken) zullen terugkeer adressen en opgeslagen data elkaar afwisselen. De programmeur is verantwoordelijk voor de correcte werking van dit systeem. Een aanzienlijk deel van de vastgelopen programma s zondigen tegen het gebruik van de stack. Er zijn enkele vuistregels die een juiste werking garanderen: haal niets van de stack zonder het er eerst op te zetten zet niets op de stack zonder her erna weer af te halen 85

86 respecteer het LIFO systeem (volgorde PUSH en POP) gebruik altijd een RET instructie om een subroutine te verlaten gebruik nooit een sprong instructie om een subroutine op te starten een interruptroutine wordt altijd afgesloten met een RETI Indirect adresseerbare registers GPR Direct adresseerbare registers SFR (I/O) ffh ffh 90h Stack ruimte 86h 85h Eerste byte gebruikt als stack Wordt niet gebruikt als stack 80h 7fh 85h 81h=SP 80h 00h Figuur Grafische voorstelling stack ruimte. De stack kan enkel via indirecte adressering gebruikt worden (donker grijze registers). Push en pop zijn pre_increment en post_decrement indirecte adressering instructies. Voorbeelden push en pop Stel: a=001h r0=002h 86

87 register 30h=003h register 31h=004h geselecteerde registerbank=0 (rs1=rs0=0 in de PSW) mov sp,#020h ; de sp wordt met 20h geladen. De eerste locatie die gebruikt zal worden is 21h ; indien we de adressen 21h t.e.m. 24h nergens anders gebruiken, dan kan de stack ; 4 bytes groot worden. push 30h ; de sp wordt met 1 verhoogd (sp=sp+1) waardoor de inhoud 21h wordt ; de inhoud van register 30h (003h) wordt naar adres 21h weggeschreven push 31h ; de sp wordt met 1 verhoogd (sp=sp+1) waardoor de inhoud 22h wordt ; de inhoud van register 31h (004h) wordt naar adres 22h weggeschreven push acc ; De push instructie heeft als operand het adres van het register. In de ; regxc888.inc en xcez0.inc files is hiervoor de naam acc gebruikt. De letter a ; wordt gebruikt in sommige mnemonics, en geeft aan dat er een speciale ; opcode is die op de accu inwerkt, zonder dat de vermelding van het adres ; nodig is. ; de sp wordt met 1 verhoogd (sp=sp+1) waardoor de inhoud 23h wordt ; de inhoud van de accu (001h) wordt naar adres 23h weggeschreven push 000h ; De push instructie heeft als operand het adres van het register. R0 is een ; een onderdeel van de mnemonic, en geeft aan dat er een speciale opcode is ; die op dat register inwerkt, zonder dat de vermelding van een 8 bit adres ; nodig is. Als registerbank 0 geselecteerd is kunnen we het register met ; de naam R0 bereiken via adres 000h. ; de sp wordt met 1 verhoogd (sp=sp+1) waardoor de inhoud 24h wordt ; de inhoud van de r0 (002h) wordt naar adres 24h weggeschreven In figuur zie je de toestand van de stack en sp na het uitvoeren van het programma. 87

88 Indirect adresseerbare registers GPR Direct adresseerbare registers SFR (I/O) ffh ffh 80h 7fh 24h 81h=SP 80h 24h 23h 22h 21h 20h 02h 01h 04h 03h 00h Figuur Stack en stackpointer na de 4 push instructies Als we nu de registers 30h, 31h, a en r0 gebruiken in het programma zal de originele inhoud overschreven worden. We kunnen ze terug laden met hun originele waarde door die van de stack te lezen. De stack werkt als LIFO (last in, first out). De eerste pop instructie zal de waarde uit register 24h lezen, waarna de sp met 1 verminderd wordt. De gelezen waarde komt in het register waarvan het adres in de pop instructie wordt opgegeven. pop 30h zal de waarde 02h van de stack lezen en in register 30h opslaan. Willen we de registers met hun originele waarde herstellen, dan moet in de omgekeerde volgorde de stack leeg gemaakt worden: pop pop 000h acc 88

89 pop pop 31h 30h De stack is een tijdelijk opslagmedium. Het is noodzakelijk dat de programmeur er voor zorgt dat stack steeds naar een lege toestand terugkeert. Je zou kunnen denken dat het herschrijven van de SP met zijn startwaarde gebruikt kan worden om de stack te flush-en. Niets is minder waar. De stack wordt immers ook door de CPU gebruikt bij het verwerken van interrupts en subroutines (zie vorige paragraaf). Indien enkel de PUSH en de POP instructies de stack zouden gebruiken, dan is het eenvoudig om de benodigde ruimte voor de stack te bepalen. Je hoeft maar het maximaal aantal PUSH-instructies te tellen, dat niet door een POP instructie wordt gevolgd. De CPU gebruikt echter ook de stack, zonder dat de gebruiker expliciet het bevel hiertoe geeft. De CPU zal de PC naar de stack schrijven telkens het programma op een plaats onderbroken wordt, waar later de draad weer opgenomen moet worden (dit is het geval bij de (L)CALL instructies en bij interrupt verwerking). Aangezien de PC 16 bit groot is, worden telkens twee bytes gebruikt. Gelukkig kan de programmeur weten wanneer de CPU de stack heeft gebruikt, zodat de eigen informatie niet verloren gaat. Omdat de stack niet meer is dan een gereserveerde geheugenruimte, met bijhorende adrespointer (SP), zijn er heel wat mogelijkheden om het systeem overhoop te halen: de registers die als stack ruimte dienen, worden elders nog gebruikt er worden meer gegevens op de stack geplaatst dan er registers voorbehouden zijn (stack overflow) er worden meer gegevens van de stack gelezen dan er weggeschreven werden (stack underflow) de gegevens worden in een foutieve volgorde uit de stack gelezen er wordt informatie die door de CPU op de stack werd geschreven veranderd de stackpointer wordt veranderd tussen twee stack operaties De stackpointer wordt door de CPU na RESET automatisch met de waarde 07H geladen. Omdat dit startadres van de stack in de tweede registerbank zit, en we de registerbanken in de meeste toepassingen gebruiken, wordt de SP meestal door een gebruikersprogramma met een andere waarde geladen. Voorbeeld gebruik stack mov sp,#080h ;de stackpointer wordt met 80h geladen push acc ;de inhoud van de accumulator wordt ;naar het adres 81h geschreven push b ;het b register wordt op de stack gezet op ;adres 82h 89

90 pop b ;het b register wordt geladen met de ;informatie van adres 82h ;de sp staat na de instructie op 81h pop acc ;de accumulator wordt geladen met ;de informatie van adres 81h ;de sp staat na de instructie op ;80h Merk op dat het adres 80h niet werd gebruikt. Ga na wat het volgende (deel)programma doet! mov sp,#030h push acc push b pop pop acc b 4.7 Bit manipulaties Inleiding De 8051 (MCS51) controller is speciaal ontworpen voor embedded en industriële toepassingen. Dit type van applicaties gebruikt veel bit-variabelen. Pompen, ventielen, motoren, lampen,..., kunnen gezien worden als bit variabelen, omdat voor elke uitgang slechts 2 toestanden voorkomen: aan/uit. Einderit schakelaars, niveau detectie, bedieningsknoppen,... zijn ook bit variabelen. Voor dit type in- en uitgangen, wensen we per variabele maar 1 aansluiting te gebruiken. Een poort bestaat uit 8 bit ( 8 aansluitingen) en wordt gebruikt om 8 variabelen in te lezen/aan te sturen. Het is dan heel handig, als je elke pin van een poort als individuele variabele kan aansturen/lezen/testen. De CPU core laat niet enkel toe dat de belangrijkste SFR's bitsgewijs aangesproken kunnen worden, maar een deel van de gewone registers ( registers 20h t.e.m. 2fh) kunnen op die manier gebruikt worden (figuur ). De 8051 kan logische bewerkingen uitvoeren op bit-variabelen, ze verplaatsen en testen, zodat het programmaverloop afhankelijk kan zijn van de toestand van 1 bit. Voor de bit instructies werkt de carry als bit accumulator. De bits, behalve de carry in bepaalde instructies, worden aangesproken met een 8 bit adres. Er zijn dus 256 individueel adresseerbare bits in de CPU registers. 128 bits zijn terug te vinden in de GPR's (General Purpose Registers)(figuur ), de overige 128 zijn 90

91 voorbehouden voor de SFR's, waarvan het adres eindigt op een 0 of een 8. Niet alle bit adressen in de SFR's zijn geïmplementeerd (aanwezig). Figuur Bitvariabelen in GPR s Berekeningen op bit variabelen In de figuur staan de instructies vermeld die bewerkingen uitvoeren op bit variabelen. De letter C in de mnemonic verwijst naar de carry vlag in de PSW. Die heeft voor bit variabelen dezelfde functie als de accu voor bytevariabelen. Het woordje bit in de mnemonic moet vervangen worden door het adres van de betrokken bit. De adressen van de bits in het GPR geheugen (figuur ) zijn 000h t.e.m. 07fh. De bits in het SFR gebied hebben adressen van 080h t.e.m. 0ffh. Je kan ook hier met een EQU directief het adres vervangen door een naam. Gebruik je het BIT directief i.p.v. EQU, dan zal de assembler nagaan dat de naam enkel voorkomt in een bit instructie. Net zoals de accu impliciet gebruikt wordt als in de mnemonic de letter a staat, maar het effectieve adres gebruikt wordt als je de naam acc gebruikt, kan dat ook voor C en cy in het geval van de carry. 91

92 Figuur Bewerkingen op bit variabelen Voorbeelden van bewerkingen op bitvariabelen clr c ;zet de carry vlag op 0 clr cy ;zet de carry op 0 maar gebruikt andere ;opcode (cy=adres van carry bit) clr psw.7 ;zet de carry op 0 ; psw.7 is het adres van de zevende bit in het psw register. Deze notatie mag enkel ; gebruikt worden als het register bit adresseerbaar is!! setb c ;zal de Carry op 1 zetten setb p3_data.0 ;zal de nulde bit van p3_data op 1 zetten ; p3_dir kan op deze manier niet aangepast worden. Het adres van het SFR eindigt ; niet op 0 of 8 (adres p3_dir=0b1h) en is niet bit adresseerbaar. In figuur is een logische schakeling afgebeeld. De uitgang is afhankelijk van de waarde van vier ingangen en de verbanden ertussen. P3_data.0 P3_data.1 P3_data.2 P3_data.3 t1 t2 t3 P4_data.0 Figuur Vier inputs sturen 1 output 92

93 De figuur kan je omzetten in volgend programma (na initialisatie poorten): t1 equ 20h.0 ;bit t1 is nulde bit adres 20h mov c,p3_data.0 ;c vlag is accumulator bij bit variabelen anl c,p3_data.1 ;c vlag bevat nu waarde t1 mov t1,c ;tussenresultaat opslaan mov c,p3_data.2 ;volgende inputs verwerken tot t2 anl c,p3_data.3 ;carry bevat tussenresultaat t2 orl c,t1 ;carry bevat nu tussenresultaat t3 cpl c ;waarde in carry inverteren mov p4_data.0,c ;waarde carry naar buiten sturen De mogelijkheid om de bits te testen en hiermee het programmaverloop te wijzigen wordt in de volgende paragraaf besproken. 4.8 Programma- en machinecontrole Inleiding Deze instructies laten toe om het programmaverloop te wijzigen, al of niet afhankelijk van de toestand van een (bit)variabele. Hierdoor is het niet alleen mogelijk om het programma een andere weg te laten volgen, afhankelijk van het resultaat van een berekening of variabele, maar ook om bepaalde delen programma vanuit verschillende plaatsen op te roepen. In eerste instantie moeten we duidelijk het verschil aantonen tussen instructies die het programmaverloop definitief wijzigen (jump instructies) en instructies die een procedure (subroutine of functie) oproepen (call instructies). De jump instructies voeren een, al dan niet voorwaardelijke, sprong uit naar het adres dat in de instructie is opgenomen. De programmeur wil niet terugkeren naar het adres dat door de sprong verlaten werd (figuur ). Bij een voorwaardelijke sprong zullen we het programma verloop afhankelijk willen maken van de toestand van een variabele. Uit de flowcharts in figuur kan je afleiden dat het gebruik van onvoorwaardelijke sprongen het programma wanordelijk en moeilijk leesbaar kan maken. Een goede programmeur zal trachten de flow van het programma zo lineair mogelijk te houden. Dit kan door het gebruik van voorwaardelijke sprongen of subroutines (figuur ). Een subroutine is een apart stukje programma dat op een bepaald adres in het geheugen staat, en afgesloten wordt met een RET (return) instructie. Een subroutine kan van op verschillende plaatsen in het programma opgeroepen worden, en zal er voor zorgen dat er teruggekeerd wordt naar de juiste plaats (return address). 93

94 Test yes no Conditioneel (na test) onvoorwaardelijk (geen test) Figuur Uitvoering van een spronginstructie Return address 1 LCALL Subroutine LCALL RET Return address 2 Figuur Uitvoering van een call instructie 94

95 4.8.2 Jump instructies De 8051 beschikt over 3 absolute jump instructies (1 werkt relatief, zie 4.8.3). Het enige verschil is het sprongbereik (het aantal geheugenplaatsen de instructie kan bereiken). LJMP of Long JuMP is een spronginstructie die 16 bit opcode gebruikt om het adres van de bestemming te bevatten. Daardoor is het sprongbereik 64K (volledige geheugen 8051). Gebruik van de instructie: ljmp adres Het adres mag vervangen worden door een label. Hierdoor moet de gebruiker niet het absolute adres kennen van de instructie waarnaar gesprongen wordt Voorbeeld van een ljmp lus: ljmp lus ;lus is het adres van de instructie na het label Een label mag maar 1 keer opgenomen worden in het label-veld (vooraan de lijn). Het mag een willekeurig aantal keer gebruikt worden als bestemming. Het label heeft als numerische waarde het 16 bit adres van de instructie die er achter staat. Het label kan ook in berekeningen gebruikt worden als een constante met die waarde. AJMP is een instructie waarbij er slechts een 11 bit adres in de opcode wordt geplaatst. De hoogste 5 bit zullen dezelfde zijn als van het adres waar de sprong instructie staat. Door de beperking in het aantal adres bits, kan de sprong alleen uitgevoerd worden binnen eenzelfde blok van 2K Relatieve sprong instructies De relatieve sprong plaatst in de opcode een 8 bit, two's complement offset, ten opzichte van de programcounter met het adres van de instructie die volgt op de relatieve sprong, en de plaats naar waar gesprongen moet worden. Dit heeft voor gevolg, dat er slechts maximaal 127 locaties voorwaarts, of 128 locaties terug gesprongen kan worden. Het sprongbereik is beperkt, maar door de instructies deskundig te kiezen geeft dit meestal geen probleem. De relatieve sprong instructies kunnen al of niet voorwaardelijk zijn. Bij de conditional jump (voorwaardelijke sprong), is het al of niet springen afhankelijk van de waarde van een (bit/byte) variabele. Bij de niet voorwaardelijke sprong is dit niet het geval, de sprong wordt steeds gemaakt. Als bij een voorwaardelijke sprong, de sprong niet gemaakt wordt, dan voert de CPU de instructie uit die vlak na de sprong instructie staat. 95

96 SJMP is een relatieve sprong instructie die onvoorwaardelijk wordt uitgevoerd. In de instructieset staat achter de mnemonic het woordje rel. Dat wordt vervangen door een label. De assembler berekend de two s complement offset en vult die in in de opcode. Voorbeeld sjmp instructie lus: sjmp lus Relatieve voorwaardelijke sprong instructies Voorwaardelijke instructies voeren eerst een test of een bewerking uit. Het resultaat hiervan zal bepalen of de sprong al of niet wordt uitgevoerd. Wordt de sprong niet gemaakt, dan zal de instructie uitgevoerd worden die na de sprong instructie in het geheugen staat. Hier volgt een overzicht van deze instructies: JC plaats spring als de carry op 1 staat JNC plaats spring als de carry Niet op 1 staat JB address_bit, plaats spring als de bit op address_bit=1 JNB address_bit, plaats spring als de bit op address_bit=0 JBC address_bit,plaats spring als de bit op address_bit=1 en clear de bit JZ plaats spring als de inhoud van de accu=0 JNZ plaats spring als de inhoud van de accu 0 Er bestaat in de 8051 geen vlag die aangeeft of het resultaat van een berekening al of niet nul is. Bij andere controllers wordt hiervoor een zero vlag gebruikt (Z). Bij de 8051 test de instructie of de inhoud van de accu al of niet 0 is, en voert dan de sprong uit. CJNE is een instructie die toelaat om de accu of een Rn register te testen (compare), en afhankelijk van het resultaat een sprong uit te voeren (JNE=jump if not equal). Volgende combinaties zijn toegelaten: CJNE a,direct,plaats vergelijkt de inhoud van de accu met de inhoud van een direct adresseerbaar register. Indien ze niet gelijk zijn wordt de sprong gemaakt. CJNE a,#data,plaats vergelijkt de inhoud van de accu met een constant getal (#data). Indien ze niet gelijk zijn wordt de sprong gemaakt. CJNE Rn,#data,plaats vergelijkt de inhoud van Rn (n=0 t.e.m. 7) met een constant getal (#data). Indien ze niet gelijk zijn wordt de sprong gemaakt. 96

97 vergelijkt de inhoud van het register waarvan het adres in Ri (i=0 of 1) staat met een constant getal (#data). Indien ze niet gelijk zijn wordt de sprong gemaakt. Extra mogelijkheid CNJE instructie De CJNE instructie zal de carry aanpassen. De waarde van de carry wordt bekomen door de compare uit te voeren als een verschilberekening. Stel: a=001h We voerende volgende instructie uit: cjne a,#001h,lus Dan zal de processor de compare uitvoeren als een verschilberekening en de carry een bijpassende waarde geven. In dit geval wordt dat a-001h=001h-001h=000h en c=0. Als de accu groter, of gelijk is aan de waarde waarmee we vergelijken, zal de carry=0 Stel: a=000h We voerende volgende instructie uit: cjne a,#001h,lus Dan zal de processor de compare uitvoeren als een verschilberekening en de carry een bijpassende waarde geven. In dit geval wordt dat a-001h=000h-001h=0ffh en c=1. Als de accu kleiner is dan de waarde waarmee we vergelijken, zal de carry=1 Volgend programma lijkt op het eerste zicht zinloos: cjne a,#getal,lus lus:.. ;dit is de lijn die volgt op de cjne instructie Door achter het label lus de carry vlag te testen, kan het programma testen of de waarde in de accu is dan getal, of < dan getal. DJNZ is een instructie die eerst de variabele met een verminderd (Decrement), en indien het resultaat niet nul is springt naar een opgegeven bestemming (Jump if Not Zero). Volgende combinaties zijn toegelaten: 97

98 DJNZ Rn,plaats verminder Rn (n=0 t.e.m. 7) met 1, en indien Rn 0 maak een sprong naar plaats DJNZ direct,plaats verminder een direct adresseerbaar register met 1, en de inhoud ervan 0 maak een sprong naar plaats Voorbeelden van spronginstructies mov a,#0ffh ;in accu ffh laden nog: add a,#001h ;eentje bij optellen ljmp nog ;blijf dit steeds herhalen her: mov a,#000h ;in accu 00h laden nog: add a,#001h ;eentje bij optellen jnc nog ;het programma wordt nu 256 keer doorlopen ljmp her ;na 256 optellingen wordt alles opnieuw opgestart mov a,#001h ;getal 01h in de accu zetten nog: djnz a,nog ;verminder de accu met 1, indien niet nul naar nog, ;anders volgende instructie ljmp start ;terug naar label start mov a,#000h ;getal 0h in de accu zetten nog: djnz a,nog ;verminder de accu met 1, indien niet nul naar nog ;anders volgende instructie ljmp start ;terug naar label start mov a,#025h ;25h in de accumulator zetten cjne a,#025h,nog ;als accu niet gelijk aan 25 naar nog, anders ;volgende instructie De (L)CALL instructie CALL instructies hebben tot doel om SUBROUTINES te kunnen oproepen. Een subroutine is een stuk programma dat we op verschillende plaatsen in het hoofdprogramma willen uitvoeren (figuur ) (zonder de instructies telkens 98

99 opnieuw in te typen). Het is dus wel de bedoeling om terug te keren naar het adres van waar de subroutine opgeroepen werd. Het return adres wordt door de CPU op de stack geplaatst, en bij een RETURN (RET instructie) van de stack gehaald, en in de PC geplaatst. Return address 1 LCALL Subroutine LCALL RET Return address 2 Figuur Oproepen van subroutines Net als bij de JUMP kennen we de LONG en de ABSOLUTE CALL instructies. In de instructieset staan ze vermeld als de LCALL (Long CALL) met een bereik van 64kbyte, en ACALL (Absolute CALL) met een bereik van 2kbte. Meestal wordt altijd de LCALL instructie gebruikt. Relatieve CALL instructies kent de CPU niet. De CALL instructies zijn steeds onvoorwaardelijk. Er is een verschil tussen een HARDWARE CALL of SOFTWARE CALL (figuur ). De software CALL is een instructie die expliciet opgenomen wordt in het programma. Het aangeroepen programma is dan ook een subroutine. 99

100 Bij de hardware CALL wordt er geen instructie uitgevoerd, maar zal de CPU hardwarematig het programmaverloop aanpassen. Dit gebeurt enkel bij het opstarten van een interrupt routine. Je kan een interruptroutine zien als een subroutine die op een hardwarematige manier opgestart wordt. In elk geval, moet na het uitvoeren van de routine de controle terug overgedragen worden aan het hoofdprogramma (RETI instructie). Een hardware CALL noemen we verder in de tekst een INTERRUPT. LCALL Return address 1 HW1 Interrupt routine Subroutine RETI Return address 2 LCALL RET HW2 Figuur Software and hardware call Bij alle CALL instructies wordt de stack gebruikt om het terugkeeradres te bewaren. De lengte van de stack wordt dus niet enkel bepaald door het aantal PUSH en POP instructies, maar ook door het aantal GENESTE CALLS EN HET AANTAL INTERRUPTS. Een subroutine of een interruptroutine moeten afgesloten worden met een instructie die het return adres van de stack haalt, en daar naar toe springt. Hiervoor worden de RETURN of RET instructies gebruikt. De RET instructie staat op het einde van 100

101 een gewone subroutine, de RETI (RETurn from Interrupt) instructie wordt gebruikt op het einde van een interruptroutine. De RETI instructie zal ingrijpen op de interrupt hardware van de CPU (zie 6.2). Interruptroutines worden door hardware opgestart, en het is dan ook onmogelijk om ten opzichte van het hoofdprogramma te weten wanneer ze uitgevoerd gaan worden. Je weet niet welke registers op dat ogenblik in gebruik zijn, en door de interruptroutine gebruikt mogen worden. Gelukkig beschikken we over de PUSH en POP instructies, om tijdelijk registers vrij te maken. Omdat de meeste bewerkingen op alle registers uitgevoerd kunnen worden, en omdat er een massa registers beschikbaar zijn, is het meestal slechts nodig om de accu, PSW en eventueel de DPTR op de stack te bewaren. Hierdoor kan het aantal bytes stack beperkt blijven. Dit is een van de grote verschillen tussen een gewone CPU en een controller core. Bij een gewone CPU zullen er minder registers zijn waardoor de stack heel groot moet kunnen worden (8086 = 64K), en vlot gebruikt kan worden. Helaas gebruiken hogere programmeertalen de stack om parameters door te geven tussen subroutine en hoofdprogramma. Dit is bij een controller uiterst moeilijk, omdat de stack een beperkte grootte heeft, en de access naar het extern geheugen moeilijk verloopt (stack is steeds inwendig in de controller) De NOP instructie De NOP instructie wordt door de CPU uit het geheugen gelezen, zodat ze een bepaalde tijd duurt. Bij de uitvoering van de instructie gebeurt er niets. De instructie lijkt dan ook overbodig. Er zijn echter bepaalde situaties, waar het handig is om over een instructie te beschikken die alleen CPU tijd in beslag neemt (opwekken van een korte puls, gebruik van de MDU, vertragingsroutines,...). 4.9 Uitvoeringstijd van een instructie De uitvoeringstijd van een instructie is afhankelijk van volgende parameters: de snelheid van de systeemklok het aantal bytes waaruit de instructie bestaat de inwendige bouw van de CPU de snelheid waarmee het geheugen gelezen kan worden De eerste drie parameters maken dat er tabellen bestaan, die voor elke instructie vermelden hoeveel klokcycli ze in beslag nemen (appendix A, kolom cycles. Let op: 1 cycle is in dit geval 12 klokcycli (standaard 8051)). 101

102 Omdat processoren steeds sneller worden, en bepaalde types geheugen relatief trager zijn, worden verschillende systemen gebruikt om beide op elkaar af te stemmen. Meestal wordt de CPU kunstmatig trager gemaakt, door tijdens het lezen uit het geheugen klokpulsen te wachten (wait cycles). Dit is weinig efficiënt. Sommige fabrikanten gebruiken dan ook accelerator technieken. De meest gebruikte techniek is de bitbreedte van het geheugen verhogen (figuur 4.9.1). Op die manier worden er per leesbeurt meerdere bytes gelezen. Dit kan relatief traag gebeuren door hardware, die dan de gelezen info byte per byte snel doorgeeft aan de CPU. Hiervoor wordt een dubbele buffer gebruikt. 8 bit bus 8 bit CPU (8 bit databus) x ns/byte Slow CPU each fetch for x ns/byte 8 bit memory 2x ns/byte Memory accelerator 16 bit buffer 16 bit buffer 8 bit bus 8 bit CPU (8 bit databus) x ns/byte 16 bit memory 2x ns/16 bit Read 2 2x ns/16 bits (one read from memory) Provide 2x ns/8bits (2 reads from CPU) Figuur Memory acceleration unit 102

103 Dit systeem werkt echter niet wanneer de benodigde info niet in de buffer zit. Dit is o.a. het geval bij spronginstructies, maar ook bij instructies waarvan de opcode niet in zijn geheel in de buffer beschikbaar is. Dit maakt dat de uitvoeringstijd van een programma niet meer deterministisch is, maar afhankelijk van de plaats in het geheugen (alineëring), het resultaat van tests bij spronginstructies enz. De XC888 gebruikt een accelerator voor zijn programmageheugen. In de ROM zitten twee subroutines die door de programmeur opgeroepen kunnen worden. Deze routines laten toe de accelerator in- (lcall dfffh) en uit- (lcall dffch) te schakelen. Bij het uitschakelen zal de uitvoeringstijd uit de kolom van 1 wait cycle van toepassing zijn (appendix B), in het andere geval de tijden uit de kolom par (parallel read, appendix B). Uitvoeringstijden zijn van belang bij tijdsvertragingen en interrupt routines. Interrupt routines moeten in de tijd beperkt blijven, en mogen soms niet langer duren dan een welbepaalde tijd. Gebruik in dat geval de worst case uitvoeringstijden uit de kolom par voor het berekenen van de uitvoeringstijd. Soms is er een software delay nodig om hardware de tijd te geven die nodig is om een event uit te voeren (een LED laten knipperen tegen enkele MHz is niet zinvol, door een tijdsvertraging wordt het knipperen langzamer en kan je het waarnemen). De wachttijden zijn meestal niet erg kritisch. Reken met de best case tijden om een idee te hebben van de tijdsvertraging (kan wel langer duren). Zijn exacte tijdsafpassingen nodig, dan zal je hardware timers moeten gebruiken. 103

104 Hoofdstuk 5 Toepassingen 5.1 Inleiding Een microcontroller kan gebruikt worden voor tal van toepassingen. Helaas bestaat er maar weinig kant en klare software die gebruikt kan worden. Zowel voor het aansturen van de hardware, als voor berekeningen is de programmeur aangewezen op zichzelf. Je kan op het WWW voorbeeldprogramma s vinden, maar hoe betrouwbaar deze software is, blijft de vraag. Dikwijls zijn application note s van fabrikanten net niet die oplossing die gezocht wordt. In dit hoofdstuk wordt meer uitleg gegeven over een aantal manieren om courante problemen op te lossen. 5.2 I/O driver xcez1.inc Inleiding Het XC888 bord dat gebruikt wordt in het laboratorium werd speciaal voor educatieve doeleinden ontworpen. Om de student in staat te stellen snel toepassingen te kunnen schrijven, is er een driver voorzien (xcez1.inc (dit was de beschikbare versie bij de eerste uitgave van de cursus. De algemene naam is xcezx.inc, waarbij de x het versie nummer is. Dit zal natuurlijk veranderen naarmate de driver aangepast wordt)). Die maakt de software interfacing van de standaard I/O op het bord eenvoudig. De student kan met een minimale kennis van de (complexe) hardware snel tot resultaten komen. Een programma heeft maar zin als er gegevens met de omgeving uitgewisseld kunnen worden. In de labo_opstelling (XC888 SBC bord) zijn er volgende I/O mogelijkheden voorzien (LET OP! niet alle mogelijkheden zullen op alle kaarten zullen bestukt zijn. Raadpleeg uw docent): 8 schakelaars op poort 4 4 schakelaars op p2.0 p2.3 (functietoetsen onder LCD scherm) 8 LED s op poort 3 (uitschakelbaar via jumper 9) een potentiometer op p2.4 (via jumper 7) een temperatuursensor (LM335 (10mV/Kelvin)) op p2.5 (via jumper 8) een LCD scherm van 4 lijnen 20 karakters met achtergrond verlichting een uitgang voor een zoemer (buzzer) tal van communicatiemogelijkheden (IIC, LIN, CAN, RS232, RS485, USB) bijkomende I/O aansluitingen voor ADC, PWM en timers De I/O kan niet zomaar gebruikt worden. Minimaal is er een initialisatie nodig. De initialisatie bestaat uit een aantal instructies die instellen hoe de I/O gebruikt gaat worden. Zo kan een poort als input, maar ook als output gebruikt worden. Zijn de 104

105 schakelaars aangesloten, dan zal de input mode geselecteerd worden. Bij de LED s is dat de output mode. Voor sommige vormen van I/O (vb. LCD scherm) verloopt de aansturing vrij complex. Er is niet alleen de initialisatie van de I/O, maar de gegevens die het LCD scherm nodig heeft komen niet onmiddellijk overeen met een intuïtief gebruik. Bij het LCD scherm word bovendien een serieel naar parallel omvormer gebruikt om het aantal I/O pinnen die nodig zijn, voor de aansturing ervan, te beperken. Een driver is een verzameling van subroutines die door de gebruiker aangeroepen kunnen worden, en die de aansturing van de I/O vereenvoudigen. Voor het XC888 bord bestaat er een driver die de courante I/O kan aansturen (andere specifieke drivers voor bepaalde complexe functies zijn op de FTP-site beschikbaar). Een driver moet mee opgenomen worden in de source code van het programma. Dat doe je door de driver onderaan het programma mee te includen: $include(c:\xcez1.inc) De *.inc bestanden zijn geschreven in assembler. Je kan ze openen met de IDE (maar ook elke andere editor/tekstverwerker (kladblok)). De commentaar in de code geeft toelichtingen hoe je de subroutines moet gebruiken. Bovenaan het bestand is een algemene beschrijving van de mogelijkheden opgenomen. Voor specifieke informatie moet je de header boven de effectieve subroutine lezen. Voor de I/O functies is er een init**** subroutine voorzien. Zo zal de initlcd subroutine de LCD klaar zetten voor gebruik. Dan pas kan je effectief informatie met de I/O module uitwisselen. Belangrijk is ook om na te gaan hoe parameters doorgegeven kunnen worden tussen de driverroutines en jou programma LED s en dipswitch De LED s zijn aangesloten op poort 3. In de figuur staan de registers afgebeeld die gebruikt worden voor het aansturen van de poorten. Per poort zijn er meerdere registers (tot 7). Nochtans zijn hiervoor per poort maar 2 adressen beschikbaar. De selectie van het te gebruiken register verloopt via het selecteren van een page (pagina). Dat gebeurt door een schrijfoperatie van het port_page register. Na reset staat dit op 000h, waardoor de registers van page 0 onmiddellijk beschikbaar zijn. 105

106 . Port_page = SFR B2H 106

107 Figuur SFR s poorten Het Px_data register wordt gebruikt om de gegevens te lezen van de poortpinnen, als de poort als input is geïnitialiseerd (default). Wordt de poort als output gebruikt, dan wordt dit register geschreven om de uitgangen aan te sturen (figuur ). 107

108 Figuur Px_data register De poort als input of als output schakelen gebeurt via het Px_dir register (figuur ). Figuur Px_dir register 108

109 Principieel zou volgende code moeten volstaan om de LED s aan te sturen en de schakelaars in te lezen: Voorbeeld initialisatie LED s en schakelaars (onvolledig) mov p4_dir,#000h ;poort 4 als input schakelen mov p3_dir,#0ffh ;poort 3 als output schakelen ; als voorbeeld lezen we de schakelaars, en schrijven de data naar de LED s mov p3_data,p4_data Dit programma vertoont een aantal onvolkomenheden: de initialisatie van poort 4 als input is overbodig. De controller schakelt na reset alle poorten als input poort 4 wordt met de massa verbonden als de schakelaars sluiten (figuur ), anders is de poort zwevend (geen gekend niveau) port 3 stuurt de LED s met een actief laag niveau (een 0 geeft licht, een 1 niet) (figuur ) Willen we de schakelaars correct inlezen, moeten de pinnen van poort 4 op logisch niveau 1 komen wanneer de schakelaars niet gesloten zijn. Dit kan bekomen worden door de inwendige pull_up weerstanden in te schakelen. Dat kan via de registers Px_puden en Px_pudsel (figuur en figuur ) Figuur Schakelaars poort 4 109

110 Figuur Poort 3 en de LED s Figuur Px_puden 110

111 Figuur Px_pudsel Voorbeeld initialisatie LED s en schakelaars (volledig) mov port_page,#001h ;selecteer poort page 1 mov p4_pudsel,#0ffh ;selecteer pull_up device mov p4_puden,#0ffh ;selectie inschakelen mov port_page,#000h ;selectie poort pagina 0 mov p4_dir,#000h ;poort 4 als input schakelen mov p3_dir,#0ffh ;poort 3 als output schakelen ; De initialisatie is klaar. We kunnen de poorten gebruiken zoals het hoort ; als voorbeeld lezen we de schakelaars, en schrijven de data naar de LED s mov p3_data,p4_data Testprogramma kopieer schakelaars naar de LED s org 00000h mov port_page,#001h ;selecteer poort page 1 mov p4_pudsel,#0ffh ;selecteer pull_up device mov p4_puden,#0ffh ;selectie inschakelen mov port_page,#000h ;selectie poort pagina 0 mov p4_dir,#000h ;poort 4 als input schakelen mov p3_dir,#0ffh ;poort 3 als output schakelen ; De initialisatie is klaar. We kunnen de poorten gebruiken zoals het hoort ; als voorbeeld lezen we de schakelaars, en schrijven de data naar de LED s 111

112 lus: mov p3_data,p4_data ljmp lus ;blijf dit herhalen Je kan ook gebruik maken van de bit-instructies om de schakelaars af te vragen. Zowel poort 4 (dip switch) als poort 2 (functie schakelaars) zijn bit adresseerbaar. Testprogramma met xcez1.inc driver org 00000h ;start adres programma mov sp,#07fh ;stack initialiseren lcall initdipswitch ;zet poort 4 klaarvoor gebruik lcall initleds ;zet poort 3 klaar voor gebruik lus: mov p3_data,p4_data ;kopieer schakelaars nar LED s ljmp lus ;blijf herhalen #include c:\xcez1.inc De voordelen van het gebruik van de driver is dat het programma compacter en leesbaarder wordt. De routines uit de driver beïnvloeden ook geen registers, en zorgen er voor dat de initialisatie perfect verloopt ongeacht de waarde in de port_page en syscon0 registers. Die worden na het uitvoeren van de routines opnieuw in hun originele waarde hersteld. Je kan de driver openen in de IDE en de code bekijken. Het is aangeraden een eigen programma zo veel mogelijk op te bouwen uit functies (subroutines). Hierdoor neemt de leesbaarheid toe, en kan je code ook in andere toepassingen hergebruiken. Hierbij is de documentatie van de routines uiterst belangrijk (zie xcez1.inc driver). De registers p3_data en p4_data zijn bit adresseerbaar. Je kan de schakelaars en de LED s dan ook individueel opvragen en beïnvloeden Functie toetsen De functietoetsen bevinden zich onder het LCD scherm (figuur ). De elektrische aansluitingen zijn opgenomen in figuur

113 Figuur Functieschakelaars S2, S3, S4 en S5 Figuur Schema functietoetsen Voor de initialisatie van deze 4 klemmen is er in de xcez1.inc driver de functie initftoetsen. Het registers p2_data is bit adresseerbaar. Je kan de schakelaars dan ook individueel opvragen (De 4 hoogste bits bevatten een onbekend resultaat!). De schakelaars staan onder het LCD scherm, zodat de onderste display lijn gebruikt kan worden om de betekenis van de schakelaars weer te geven. 113

114 Van schakelaar tot keyboard, algemeenheden Een groot aantal embedded producten (bijna allemaal) hebben een keyboard interface als input voor de gebruiker of moeten een aantal schakelaars lezen. Een keyboard kan zowel gebruikt worden voor het ingeven van numerische data als voor het selecteren van een werkingsmode van het toestel. Er bestaan voor het lezen van keyboards kant en klare oplossingen in chipvorm, maar een software aanpak voor keyboardscanning of het lezen van schakelaars heeft het voordeel dat de kostprijs van het product kleiner wordt en dit in ruil voor een kleine CPU overhead. De meeste keyboards bestaan uit een matrix van aansluitdraden waar op elk kruispunt een drukschakelaar is mee verbonden. De controller kan dan zeer eenvoudig bepalen welke schakelaar er is ingedrukt De keyboard hardware basics. Bij een keyboard wordt meestal een drukschakelaar gebruikt, waarvan het sluiten eenvoudig kan worden gedetecteerd door volgend circuit. De pull-up weerstand zorgt ervoor dat er een logisch '1' signaal aan de uitgang staat wanneer de schakelaar open staat, en een logische '0' wanneer de schakelaar is gesloten. De pull-up weerstand zit bij de 8051 familie principieel reeds intern in de pindriver, maar meestal plaatst men extern toch nog een laagohmige pull-up weerstand (enkele KΩ) uit betrouwbaarheidsoverwegingen. +5V Schakelaar open Contactdender Schakelaar open Naar de controlleringang +5V GND Schakelaar dicht Schakelaar ingedrukt t Figuur Schakelaar met bounce pull-up weerstand en contactdender Helaas zijn schakelaars niet ideaal en genereren ze geen gedefinieerde '1' of '0' wanneer ze worden ingedrukt of losgelaten. Alhoewel een contact snel en stevig lijkt te sluiten, is dit voor de snelle controller een zeer trage gebeurtenis. Wanneer het contact wordt gesloten 'botst' het nog enkele keren als een bal. Dit botsen noemt men contactdender of bounce. De contactdender zorgt voor meerdere pulsen op de controller-ingang en deze dender duurt typisch tussen de 5 en 30ms (zie fig ) Wanneer meerdere schakelaars nodig zijn in een systeem kan men elke schakelaar op deze manier verbinden met een poortpin van de controller. 114

115 Voor een groot aantal schakelaars zijn er al snel niet genoeg poortpinnen beschikbaar. De meest efficiënte manier om schakelaars te verbinden met een controller is in de vorm van een tweedimensionale matrix zoals aangegeven in de figuur Dit levert winst op van poortpinnen vanaf 6 schakelaars. Scanlijnen (rijen) Keyboard matrix "0" 1 1 POORT X 1 1 AT89S Leeslijnen (kolommen) Figuur Schakelaars verbonden in matrixvorm. Het aantal schakelaars nodig in de matrix is natuurlijk afhankelijk van de toepassing. Elke rij wordt aangestuurd door een poortbit (output), terwijl elke kolom wordt omhoog getrokken door de (interne) pull-up van de poortpin (input), waarmee hij is verbonden. Uiteraard kan ook met elke kolom extern nog een extra pull-up weerstand worden verbonden. Keyboard scanning is het proces waarbij de controller op regelmatige tijdstippen naar de keyboard matrix kijkt om te zien of er een toets is gedrukt. Als er een toets werd ingedrukt is het aan de keyboard scanningsoftware om de dender weg te filteren en te bepalen welke toets er werd ingedrukt. Uiteraard hoeft het niet altijd te gaan om een keyboard dat op deze manier wordt verbonden, wanneer in een systeem een groot aantal contacten moet worden gelezen zoals bv. einderit schakelaars, contacten van relais, naderingsschakelaars enz., kan dit ook op deze manier Een matrix (keyboard) scanning algoritme. Een matrix kan op verschillende manieren worden gelezen, een eenvoudig algoritme wordt hier aangegeven. 115

116 In de vertrektoestand worden alle rijen (outputpinnen) op een logische '0' gezet. Wanneer er geen toets is gedrukt zullen alle kolommen (inputpinnen) als logisch '1' gelezen worden. Het indrukken van een toets (sluiten van een contact) heeft als gevolg dat één van de kolommen laag gemaakt wordt. Om te zien of een toets is ingedrukt moet de controller dus alleen kijken of er een inputpin (kolom) laag staat. Wanneer de controller gedetecteerd heeft dat er een toets is ingedrukt, moet hij nog bepalen welke toets het is. De controller stuurt een '0' op slechts één van de rijpinnen (outputpinnen). Als er een '0' wordt teruggevonden op de ingangspinnen (kolommen) dan weet de controller dat de ingedrukte toets zich bevindt op de met een '0' aangestuurde rij. Als alle ingangen hoog blijven bevindt de ingedrukte toets zich niet op de geselecteerde rij en de controller maakt dan de volgende rij logisch '0' en het proces herhaalt zich. Wanneer de rij is bepaald kan de controller nagaan welke van de kolommen (inputpinnen) er '0' is, dit geeft de kolom aan van de ingedrukte toets. De tijd die de controller nodig heeft om deze handelingen uit te voeren is zeer klein (enkele μs) vergeleken met de minimale tijd dat een schakelaar wordt ingedrukt (enkele honderden ms), er wordt dan ook verondersteld dat de schakelaar gesloten blijft tijdens dit proces. Om de contactdender weg te filteren zal de controller het keyboard scannen met een bepaald tijdsinterval, typisch tussen de 20 ms en de 100ms, wat de debounce periode wordt genoemd. Een toets is pas echt ingedrukt wanneer hij tweemaal na elkaar ingedrukt wordt terug gevonden, anders kan het gaan om een stoorsignaal of om de contactdender. Soms is het nodig te reageren op een toets die wordt ingedrukt of die wordt losgelaten, en niet op een ingedrukt gehouden schakelaar. Een dalende flank van een ingedrukte toets heeft men na opeenvolgend een niet ingedrukte en twee ingedrukte toestanden, en een stijgende flank van een losgelaten toets heeft men na opeenvolgend een ingedrukte en twee niet ingedrukte toestanden. De rij- en kolominformatie van de toets kan dan worden omgezet naar een scancode die dan in een buffer kan worden geplaatst. Buffering is handig omdat het voorkomt dat er toetsinfo verloren gaat wanneer de toepassing niet direct de toetsinfo kan verwerken. De buffergrootte is weer afhankelijk van de toepassing. Een 'keyflag' kan aangeven aan de toepassing dat er nog toetsinfo in de buffer aanwezig is. Het is ook mogelijk dat er geen buffer gebruikt wordt, en het scannen van het klavier gebeurt door een opgeroepen subroutine, die een code doorgeeft, in functie van het al of niet ingedrukt zijn van een toets (vb: ffh, niets ingedrukt en de codes 00h-18h voor een ingedrukte schakelaar). 116

117 Het scannen met een bepaald tijdsinterval kan worden opgestart door een periodische timerinterrupt die meestal in elk systeem wel aanwezig is als systeem- 'time-tick'. Het aansturen van een matrix van schakelaars kan een hardware probleem geven bij controllers die niet beschikken over een open-drain pindriver. Indien er immers twee toetsen worden ingedrukt op dezelfde kolom zal een rijpin die '0' is kunnen verbonden worden met een rijpin die op '1' gestuurd is. Dit geeft bij de 8051 familie geen probleem, maar bij een aantal controllers met een actieve (push-pull) uitgangstrap zal dit het defect van een pin veroorzaken. Dit probleem kan opgevangen worden door ofwel Schottkey diodes te gebruiken (laten alleen toe dat er stroom in de poort vloeit), of door de poort in de input mode te plaatsen voor een uitgang 1 (de pull-up weerstand zorgt voor het hoge signaal) en als output=0 voor het uitsturen van een

118 5.2.4 LCD scherm Omdat die minimale (LED s en schakelaars) I/O soms onvoldoende is, gebruiken we een LCD scherm voor bijkomende output. Het scherm bestaat uit 4 lijnen van elk 20 karakters (figuur ). Figuur LCD scherm De figuur laat zien dat elke display locatie een uniek adres heeft in het DDRAM geheugen van het display. Figuur DDRAM adressen van de scherm posities De gebruiker kan aan de hand van deze adressen bepalen waar hij op het scherm een boodschap wil laten zien. De boodschap zelf bestaat uit symbolen die aangeduid worden via een ASCII code. Die omvatten zowel symbolen als controle karakters (figuur ) 118

119 Figuur Standaard karakterset LCD display. De letter A wordt weergegeven door de code ofwel 41h. De codes 0000xxxx kunnen gebruikt worden voor zelf aangemaakte karakters. De codes 0001xxxx zijn niet geïmplementeerd, en de codes >7fh worden door het beeldscherm als Japanse karakters weergegeven. Voor ons zijn die niet bruikbaar en beschouwen we als niet geïmplementeerd. De driver zal deze getalwaarden gebruiken om de cursor op een adres van het scherm te plaatsen. 119

120 Om het aantal aansluitklemmen van de controller, voor het aansturen van het scherm te beperken, wordt het display aangestuurd via een port expander op een IIC (I 2 C) bus. De aansturing verloopt dan met slechts 2 klemmen van de controller (figuur ), SDA en SCL. Figuur Schema aansturing LCD scherm Je kan in het schema ook zien dat de portexpander (PCF8574) op klem P6 de achtergrondverlichting van het display aanstuurt, en via klem P7 een extra I/O klem op JP6 (onderaan het XC888 SBC bord). De xcez1.inc driver laat toe om het LCD scherm te gebruiken zonder dat je op de hoogte moet zijn van de exacte werking ervan. Zelfs de manier waarop het aangesloten is op de controller is niet van belang. Voor je een driver mag gebruiken MOET je hem openen en lezen hoe je de subroutines mag/kan gebruiken. 120

121 Voorbeelden gebruik LCD display, backlight en buzzer: org 0000h ;start adres programma mov sp,#07fh ;stackpointer klaar zetten lcall initlcd ;zet I2C verbinding en zorgt ;voor initialisatie LCD scherm Na de initialisatie zie je op het scherm een knipperende cursor. Wanneer je nu naar het scherm ASCII codes stuurt (1fh<accu<80h), dan verschijnen de bijhorende symbolen op het scherm. lcdoutchar is een routine die als input in de accu een ASCII code vraagt. mov a,#041h ;zet in de accu de ASCII code van A lcall lcdoutchar ;drukt op het scherm het symbool A Na het afdrukken van het symbool zal de cursor automatisch 1 positie naar rechts opschuiven. Je hoeft de ASCII codes niet uit het hoofd te kennen. De assembler aanvaardt volgende notatie: mov a,# A ;zet in de accu de ASCII code van het ;symbool A Let wel op: de accu is maar 8 bit groot. Je kan er slechts de ASCII code van 1 symbool in kwijt. Het woord zoon afdrukken moet in 4 keer gebeuren: mov a,# z ;zet in accu ASCII code z lcall lcdoutchar ;druk af mov a,# o ;zet in accu ASCII code o lcall lcdoutchar ;druk af lcall lcdoutchar ;druk af (lcdoutchar past de accu niet ;aan, je hoeft de o niet nog eens in ;de accu te plaatsen). mov a,# n ;zet in accu ASCII code n lcall lcdoutchar ;druk af De routine lcdoutchar stuurt ook bevelen naar het LCD scherm: 00dh =cursor in de home positie 00ch =form feed =scherm leeg maken en cursor op locatie 000h 00ah =cursor op tweede lijn plaatsen 001h =cursor on blink 002h =cursor on, no blink 003h =cursor off 080h-0ffh =cursor plaatsen op adres (waarde in accu-80h) Andere codes zijn ongeldig! Stel dat je de cursor op de vierde plaats van de derde lijn wil positioneren, dan zoek je eerst het adres van die locatie in figuur

122 Figuur Adressen posities op LCD scherm In dit geval is dat adres 17h. Volgens de driver moet je hierbij 80h optellen =97h (de 80h(msb=1) wordt er bij geteld om waarden te bekomen buiten de standaard ASCII codes). mov a,#097h ;zet bewerkte adres in de accu lcall lcdoutchar ;zal de cursor naar locatie ;97h-80h=17h verplaatsen Voor het afdrukken van een getal zijn er drie routines: lcdoutnib: drukt de 4 laagste bits van de accu af als een getal tussen 0 en F lcdoutbyte: drukt de 8 bits van de accu af als een getal tussen 00 en FF lcddispdptr: drukt de 16 bits in de DPTR af als een getal tussen 0000 en FFFF mov a,#01ch ;zet in de accu het getal 1ch lcall lcdoutnib ;drukt op het scherm C af lcall lcdoutbyte ;drukt op het scherm 1C af mov dptr,#1234h lcall lcddispdptr ;drukt op het scherm 1234 af Voor het afdrukken van grotere getallen kunnen combinaties van vorige routines gebruikt worden. Voor het afdrukken van een tekst string wordt de routine lcdoutmsga gebruikt. Deze routine krijgt als parameter het startadres van de string mee, via de dptr. We drukken nu opnieuw het woord zoon af: mov dptr,#boodschap ;laden in de dptr adres boodschap lcall lcdoutmsga ;afdrukken maar De boodschap zelf staat achteraan het programma. De controller kan het verschil niet zien tussen uitvoerbare code en constanten. We moeten er daarom voor zorgen dat de boodschap buiten het normale programmaverloop staat. De meest aangewezen plaats hiervoor is achter de subroutines. boodschap: db zoon,000h Dit is de syntax waarmee een string van constanten in het geheugen geplaatst wordt: 122

123 boodschap: het label vooraan de lijn, wordt door de assembler gelijk gesteld aan het adres waar het eerste karakter van de string in het geheugen staat (net zoals een label bij een subroutine). db directief dat tegen de assembler zegt dat al wat er volgt geen instructies zijn, maar constanten zoon alles wat tussen staat wordt vervangen door de bijhorende ASCII code. Per karakter wordt er 1 geheugenplaats gebruikt,000h ;de constante 000h wordt in de laatste geheugenplaats opgeslagen. De driver weet dat deze NULL ASCII code het einde van de string betekend. Omdat de string enkel uit ASCII codes bestaat, mogen ook de codes die bevelen vormen er tussen geplaatst worden. test: db 003h,080h, jantje,00ah, Piet,094h, Suzy,000h Bovenstaande string zal: 003h cursor uitschakelen 080h cursor eerste karakter eerste lijn plaatsen (80h-80h=00h) jantje jantje afdrukken 00ah cursor op eerste karakter van de tweede lijn plaatsen (0ah=cr) Piet Piet afdrukken 094h cursor op eerste karakter van derde lijn plaatsen (94h-80h=14h) Suzy Suzy afdrukken 000h einde van de string, stoppen met afdrukken en terugkeren naar aanroepende programma In/uit schakelen backlight/buzzer Het in- en uitschakelen van de achtergrondverlichting gebeurt met volgende subroutines: lcdlighton backlight aan lcdlightoff backlight uit lcdbuzon buzzer aan lcdbuzof buzzer uit Je kan deze routines maar oproepen nadat de initlcd routine is uitgevoerd! Alle bovenstaande subroutines zijn maar toegankelijk wanneer je onderaan het programma de driver mee opneemt: #include c:\xcez1.inc ;driver mee opnemen in programma Wanneer het LCD scherm gebruikt wordt, is automatisch de I 2 C bus mee ingesteld. 123

124 5.2.5 I2C bus Om de XC888 SBC zo veel mogelijk periferie te geven, en zo weinig mogelijk pinnen van de controller op te geven, werd geopteerd om 2 klemmen van de XC888 te gebruiken als een I 2 C (IIC) bus. P0.7 wordt gebruikt als SDA (serial data) en p0.3 als SCL (serial clock). De controller heeft geen hardware ondersteuning voor een IIC bus en het IIC protocol, zodat alle communicatie via software emulatie moet gebeuren. In figuur Kan je zien hoe verschillende componenten op de bus worden aangesloten. Figuur IIC of I2C bus Figuur laat de elektrische interface zien. De bus is een wired-or (ook wel open collector genoemd) systeem. Weerstanden zorgen voor het hoog niveau, de componenten maken de bus actief laag met een schakelelement. Figuur Elektrische aansluitingen IIC bus Het communicatie protocol gaat er van uit dat de bus in rust op 1 staat. Er wordt door de master een startconditie op de bus geplaatst bij de aanvang van een dataoverdracht. 124

125 Na de startconditie moet het 7 bit adres van de slave worden verstuurd, samen met een bit die aangeeft of er gelezen/geschreven wordt van/naar de slave. De slave zal antwoorden met een negende ACK bit als het adres ontvangen werd. Daarna is de communicatie afhankelijk van de R/W bit. In elk geval wordt er na elke byte dataoverdracht door de ontvangen een negende ACK of NACK bit verzonden. De klok wordt altijd door de master opgewekt. De communicatie wordt afgesloten met een stopconditie. Vooraleer je met een IC kan communiceren, moet je in de betrokken datasheet nagaan hoe het IC data verwacht, en/of doorstuurt. In figuur Is dat weergegeven voor de LM75 (of DS75) temperatuursensor. Figuur IIC protocol LM75 De xcez0.inc driver bevat de elementaire routines voor het aansturen van de IIC bus: initiic klaar zetten iic interface iicstart genereren van een startconditie op iic poort iicstop genereren stop conditie op iic poort iicinbyteack lezen van 1 byte met verzenden ack (accu=output) iicinbytenack lezen van 1 byte met verzenden nack (accu=output) iicoutbyte schrijven van 1 byte (accu=input, c=output=waarde ack bit slave) Alle bovenstaande subroutines zijn maar toegankelijk wanneer je onderaan het programma de driver mee opneemt: #include c:\xcez1.inc ;driver mee opnemen in programma Voorbeeldprogramma 1 uitlezen LM75 ; Dit programma leest een LM75 uit over de IIC bus op het XC888 SBC. ; De 8 MSB bit resultaat worden weergegeven op de LED's ; De LM75 heeft volgend adres: x org 00000h ;start adres programma mov sp,#07fh ;klaar zetten van de stack lcall initiic ;iic interface klaar zetten lcall initleds ;LED s klaar zetten voor gebruik 125

126 lus: lcall iicstart ;start conditie op de iic bus mov a,# b ;adres in accu, 8ste bit geeft aan lezen lcall iicoutbyte ;wordt naar buiten gestuurd ; De routine geeft de ACK/NACK van de LM75 door in de carry. Als we dat willen ; kunnen we nagaan of de carry wel op 0 staat. Alleen dan is het IC aanwezig. jc fout lcall iicinbyteack ;lees een byte binnen en antwoord met ack cpl a ;de LED's geven licht bij een 0. Door te ;complementeren zien we licht voor 1 mov p3_data,a ;de gelezen waarde wordt op de LED'gezet lcall iicinbytenack ;volgende byte lezen en NACK sturen ;moet volgens het protocol van de LM75 ;gelezen data wordt niet verwerkt lcall iicstop ;sluit communicatie af ; De sensor mag maar alle 0.1s uitgelezen worden. Daarom voeren we een wachtlus uit. ; Die is ook beschikbaar in de xcez driver mov a,#10 lcall delaya0k05s ;duurt accu*0,05s (nu 10*0,05s=0,5s) ljmp lus ;blijf herhalen fout: ljmp fout ;sensor is er niet, dus geen verdere actie #include c:\xcez1.inc Voorbeeldprogramma 2 uitlezen LM75 ; Dit programma leest een LM75 uit ove de IIC bus op het XC888 SBC. ; De 16 bit resultaat worden weergegeven op de LCD ; De LM75 heeft volgend adres: x org 00000h ;start adres programma mov sp,#07fh ;klaar zetten van de stack lcall initlcd ;LCD klaar zetten voor gebruik (dus ook IIC interface) mov a,#003h ;cursor uitschakelen (code 003h) lcall lcdoutchar ;naar LCD sturen lcall lcdlighton ;achtergrond verlichting inschakelen lus: mov a,#080h ;cursor op eerste plaats eerste lijn zetten lcall lcdoutchar ;naar scherm versturen lcall iicstart ;start conditie op de iic bus mov a,# b ;adres in accu, 8ste bit geeft aan lezen lcall iicoutbyte ;wordt naar buiten gestuurd ; De routine geeft de ACK/NACK van de LM75 door in de carry. Als we dat willen ; kunnen we nagaan of de carry wel op 0 staat. Alleen dan is het IC aanwezig. jc fout 126

127 lcall iicinbyteack ;lees een byte binnen en antwoord met ack mov b,a ;even opslaan lcall iicinbytenack ;volgende byte lezen en NACK sturen push acc ;even opslaan lcall iicstop ;sluit communicatie af ; De beide uitgelezen waarden kunnen pas naar ht LCD scherm verzonden worden als de ; communicatie met de LM75 afgerond is. Het LCD scherm wordt immers ook via de IIC bus ; aangesproken, waardoor de communicatie met de LM75 onderbroken zou worden. ; De IIC bus is dus nu terug vrij, waardoor we de LCD kunnen aanspreken. mov a,b ;eerste opgeslagen byte afdrukken lcall lcdoutbyte ;weg er mee pop acc ;tweede opgeslagen byte afdrukken lcall lcdoutbyte ; De sensor mag maar alle 0.1s uitgelezen worden. Daarom voeren we een wachtlus uit. ; Die is ook beschikbaar in de xcez driver mov a,#10 lcall delaya0k05s ljmp lus ;blijf herhalen fout: mov dptr,#tekst ;laten op LCD zien dat er iets mis is lcall lcdoutmsga ljmp lus ;opnieuw proberen tekst: db #include 080h, er is iets mis met,00ah, de lm75,000h c:\xcez1.inc ADC De Analog to Digital Converter (ADC) is een onderdeel van de controller dat gebruikt wordt om analoge ingangssignalen te meten. De ADC heeft een resolutie van 10 bit (1024 schaaldelen). De meting gebeurt tussen 0V en een referentiespanning. Het XC888 SBC bord laat toe om die referentie te kiezen (figuur ). De digitale waarde wordt bekomen door volgende formules toe te passen: De maximale uitgangscode is 3ffh, en wordt bereikt bij een ingangsspanning van Vref-1LSB. 1LSB is de waarde waarmee de ingangsspanning moet wijzigen alvorens de digitale uitlezing met 1LSB zal veranderen. 127

128 Voor een Vref van 5v is 1LSB=0, V. Omdat de potentiometer (figuur ) aangesloten is tussen 0 en 5V, gebruiken we de 5V als referentie (JP10 in positie 2-3). Figuur Instellen van de ADC referentie Figuur Potentiometer en temperatuursensor op XC888 SBC De XC888 ADC is vrij complex in gebruik. Wanneer je de driver gebruikt hoef je daar niets vanaf te weten. Volgende routines zijn beschikbaar: initadc klaar zetten ADC voor minimaal gebruik adclm335 uitlezen lm35 (a-b) bevat resultaat adcpotmeter uitlezen van de potmeter (a-b) bevat resultaat Initadc zet de ADC klaar voor gebruik in een vereenvoudigde mode, die enkel het bemonsteren van de pinnen p2.4, p2.5, p2.6 en p2.7 mogelijk maakt. De routines adclm335 en adcpotmeter meten de spanning die door beide elementen aan de controller worden aangelegd. In figuur staat weergegeven welke informatie in accu en b register beschikbaar zijn. 128

129 De accu bevat de 8 hoogste bits van de omvorming. Het b register bevat volgende info: Figuur Inhoud accu en b register na xcez meetroutines 129

130 Voorbeeldprogramma inlezen potentiometer org 00000h ;start adres programma mov sp,#07fh ;klaar zetten van de stack lcall initlcd ;LCD klaar zetten voor gebruik (ook IIC interface) mov a,#003h ;cursor uitschakelen (code 003h) lcall lcdoutchar ;naar LCD sturen lcall lcdlighton ;achtergrondverlichting aan lcall initadc ;adc klaar zetten voor gebruik lus: mov a,#080h ;cursor op eerste plaats eerste lijn zetten lcall lcdoutchar ;naar scherm versturen lcall adcpotmeter ;meet spanning potmeter lcall lcdoutbyte ;druk 8 hoogste bits af mov a,b ;laagste bits in accu lcall lcdoutbyte ;afdrukken mov a,#00ah ;tweede lijn scherm nemen lcall lcdoutchar lcall adcpotmeter ;opnieuw meting uitvoeren ; we gaan de 10 bit uitkomst afzonderen en rechts afgelijnd afdrukken ; Ga op papier na wat hier allemaal gebeurt!!!! push acc ;straks nog nodig anl a,# b ;hoogste 2 bits bewaren rl a rl a ;hoogste bits worden laagste lcall lcdoutbyte ;afdrukken pop acc ;accu herstellen anl a,# b ;laagste 6 bits bewaren anl b,# b ;hoogste 2 bits bewaren add a,b ;bij elkaar voegen rl a ;alles op juiste plaats zetten rl a lcall lcdoutbyte ljmp lus #include c:\xcez1.inc SIO De XC888 beschikt over 2 seriële poorten van het type UART. Op een PC wordt dit type communicatiepoort een COM poort genoemd. Omdat de meeste PC s niet meer zijn uitgerust met een COM poort, maar met USB porten, is het XC888 SBC bord uitgerust met een UART naar USB omvormer (figuur ). 130

131 Figuur UART naar USB omvormer op XC888 SBC Wanneer op de PC de juiste driver is geïnstalleerd, komt op de PC een COM poort beschikbaar wanneer het USB slot verbonden is met het XC888 SBC bord. Die COM (FT232RL chip) poort is verbonden met de UART van de XC888 (via de klemmen p1.1(rxd) en p1.0(txd)). De SIO routines van de driver kunnen dan gebruikt worden om via de UART gegevens uit te wisselen met de PC. In onze voorbeelden gaan we er van uit dat een programma zoals TERA TERM beschikbaar is. Teraterm emuleert op de PC een terminal. Dat is een apparaat dat inkomende ASCII codes laat zien als symbolen op het scherm, en alle toetsaanslagen vertaalt naar ASCII codes en doorstuurt naar de COM poort (via USB naar de FT232RL chip, en zo naar de XC888 UART). Een ASCII code tabel kan je terugvinden in appendix E. Merk op dat de controlekarakters ( ASCII code<020h) afwijken van diegene die in de LCD driver gebruikt worden. Bovendien zal de terminal emulatiesoftware (vb. Tera term) ze niet allemaal verwerken. Volgende subroutines zijn beschikbaar in de driver: initsio klaar zetten seriële poort 9600 baud siooutchar afdrukken ascii code (accu=input) siooutbyte afdrukken getal in accu siooutnib afdrukken 4 laagste bits accu siooutmsga afdrukken ascii tot 000h code sioinchar inlezen van 1 ascii code in de accu sioinbufa inlezen van ascii buffer vanaf adres strtbuf, max 20h karakters! sioinbyte inlezen van een byte zonder echo 131

132 Waarbij strtbuf de waarde 054h heeft. Deze waarde kan in de driver aangepast worden!! Merk op de out routines identieke werking hebben (op de cursorrouting na!!) in vergelijking met die van de LCD subroutines. LET OP!!! De XC888 zal na reset een inwendige RC oscillator gebruiken. Die is beperkt in nauwkeurigheid. Wanneer het systeem gebruikt wordt bij grote temperatuurschommelingen, of wanneer de component buiten tolerantie valt, is het mogelijk dat de baud rate onvoldoende nauwkeurig ingesteld wordt. Om dit te vermijden kan je overschakelen op de externe kristal oscillator. Hiervoor kan je de routine XCsw2xtal gebruiken. Voorbeeldprogramma SIO/UART org 00000h ;startadres programma mov sp,#07fh ;stackpointer klaar zetten voor gebruik lcall initsio ;seriële poort klaar zetten. ;bij de initialisatie van de seriële poort worden volgende settings gebruikt: ; baud (communicatiesnelheid van 9600 bit/seconde) ;- xonxoff flow control protocol ;- 1 start-, 8 data-, en 1 stop bit ;Volgende code zal de cursor vooraan de volgende lijn op het scherm plaatsen. mov a,#00dh ;ascii code voor nieuwe lijn lcall siooutchar ;naar buiten sturen mov a,#00ah ;ascii code cursor vooraan de lijn lcall siooutchar ;naar buiten sturen ;Volgende code zal een toetsaanslag inlezen (blijft wachten op het indrukken van de ;toets op het klavier van de PC). Is de toets de letter a, dan gaan we verder in het ;programma, anders lezen we opnieuw een toets in lus: lcall sioinchar ;blijf wachten op indrukken toets cjne a,# a,lus ;indien niet a herhaal inlezen ;de ingedrukte toets was a dus gaan we verder in het programma ; De volgende routine leest een string ASCII codes binnen, en drukt ze af op het ; scherm van de PC. De ingave wordt afgesloten door op de enter toets te drukken. ; De ingelezen ASCII codes staan in de GPR s vanaf het adres strtbuf (54h default). ; Je kan dat adres, en het aantal karakters dat maximaal ingelezen kan worden, ; aanpassen door in de driver de strtbuf en endbuf aan te passen. 132

133 lus2: lcall sioinbufa ;leest in en blijft wachten op enter mov r0,#strtbuf ;start adres van de buffer laden mov ;lees eerste waarde uit buffer cjne a,# a,lus2 ;indien eerste karakter niet a, ;opnieuw inlezen ; indien het eerste karakter in de ingelezen buffer a is, gaat het programma verder. lus3: ljmp lus3 ;afsluiten programma LET OP!! De routine inbufa gebruikt dus GPR registers. Op dit ogenblik mag daar geen data in zitten die je nog nodig hebt! Die word immers overschreven en gaat verloren! Wiskundige berekeningen De XC888 is uitgerust met 2 hardware rekeneenheden: de CORDIC en de MDU. De subroutines in de driver xcez maken geen gebruik van de CORDIC of de MDU, zodat die ter beschikking blijven wanneer snelheid belangrijk is (interruptroutines). Voor de CORDIC is er op de FTP site een aparte driver beschikbaar. De MDU is zo eenvoudig in gebruik dat er geen driver nodig is. Afhankelijk van de grootte van de getallen waarop berekeningen uitgevoerd moeten worden, zullen er registers gebruikt worden om parameters door te geven. Voor 8 bit bewerkingen wordt de accu gebruikt als input en output. Waar er meerdere bytes nodig zijn zullen de Rn (n = 0-7). Voor elke subroutine staat er in de driver uitvoerig beschreven welke registers waarvoor gebruikt worden. LET OP!! De wiskundige routines gebruiken GPR s om de berekeningen uit te voeren. Om te vermijden dat de gebruiker hiermee rekening moet houden, worden ze tijdelijk op de stack bewaard, en na de berekeningen hersteld. Dit kan enkel wanneer de stack dit deel van de GPR s NIET gebruikt. Zodra de stack geheugenlocaties boven 7fh gebruikt is alles OK! Dit zijn de subroutines die in de xcez driver beschikbaar zijn: mul16 vermenigvuldigen 2 16 bit getallen mul32 vermenigvuldigen 2 32 bit getallen div16 delen 2 16 bit getallen div32 delen 2 32 bit getallen add16 optellen 2 16 bit getallen add32 optellen 2 32 bit getallen sub16 verschil 2 16 bit getallen sub32 verschil 2 32 bit getallen hexbcd8 omvormen 8 bit hex naar bcd 133

134 hexbcd16 omvormen 16 bit hex naar bcd bcdhex8 omvormen 8 bit bcd naar hex bcdhex16 omvormen 16 bit bcd naar hex Voorbeeldprogramma wiskundige routines In het voorbeeld programma delen we het getal 9a8bh door 1f2eh. We gaan er van uit dat beide getallen in registers (20h-23h) zitten volgens figuur De figuur laat ook zien in welke registers de getallen moeten staan zodat de DIV16 routine ze gebruikt. De figuur geeft ook weer waar de uitkomst terug te vinden is. Input Output Berekening R1 R0 R1 R0 24h 9ah 8bh rest rest 23h 9ah 22h 8bh R3 R2 DIV16 R3 R2 21h 1fh 1fh 2eh quotient quotient 20h 1fh 2eh CY 1 indien /0 Figuur Getallen voor en na de berekening De input en de output van de routine kan je terugvinden in de header boven de subroutine: ; ; div16 is de routine die twee 16 bit getallen zal delen (deeltal/deler). ; input: r1,r0 = deeltal (r1=msb) ; r3,r2 = deler (r3=msb) ; output: r3,r2 = quotient (r3=msb) ; r1,r0 = rest (r1=msb) ; carry=1 bij deling door 0 ; Volgende code laadt de getallen in de juiste registers en roept de subroutine op: mov r1,023h ;data in de inputregisters laden mov r0,022h mov r3,021h 134

135 mov r2,020h lcall div16 ;berekening oproepen Nu zitten de getallen van de uitkomst in de R3, R2, R1, R0 registers zoals weergegeven in figuur De carry zal op 1 staan als we gedeeld hebben door 0. LET OP!! De originele inhoud van de R-registers is overschreven. Je kan altijd één van de 4 registerbanken vrijhouden voor wiskundige bewerkingen. Vergeet dan niet om in de PSW de RS0 en RS1op de juiste waarde de brengen Diverse Onder diverse vinden we volgende subroutines terug: delaya0k05s tijdsvertraging (waarde in accu)*0,05s delay1ms tijdsvertraging 1 milliseconde delay10us tijdsvertraging 10 microseconde XCsw2xtal overschakelen rc naar kristal (written by Pauwels D.) De delay1ms en delay10us hoef je enkel maar op te roepen om de beoogde vertraging te bekomen. De delaya0k05s routine gebruikt het getal in de accu om te bepalen hoe dikwijs 0k05s (0,05s) afgepast moeten worden. Volgende code zal 5 seconden duren: LET OP!! mov a,#100 ;getal 10 in de accu lcall delaya0k05s ;duurt nu 100x0,05s=5s De waarde van de accu kan nooit groter zijn dan 255. Dit geeft een maximale tijdsvertraging van 12,75 seconden. Wordt in de accu de waarde 000h geladen, dan komt dat overeen met 256x0,05s=12,8s. Belangrijk!! Software tijdsvertragingen zijn niet erg nauwkeurig. Dit heeft vooral te maken met het feit dat alle instructies uitvoeringstijd vragen. Je moet voor het bepalen van een delaytijd dus ook rekening houden met de uitvoeringstijd van de instructies die geen deel uitmaken van de delay routine. Bij de XC888 komt daar nog bovenop dat de uitvoeringssnelheid van de code afhankelijk is van hoe ze door de processor uit het geheugen wordt gehaald. Zowat alle recente CPU s gebruiken één of meerdere acceleratiesystemen om hogere uitvoeringssnelheden te bekomen, met een niet deterministisch (op gebied van uitvoeringssnelheid) gedrag. Voor het afpassen van nauwkeurige tijden worden hardware timers gebruikt. 135

136 De routine XCsw2xtal laat toe om over te schakelen van de inwendige RC oscillator naar het uitwendige kristal. Hierdoor zal de frequentie van de systeemklok veel stabieler worden. Dit is vooral belangrijk bij nauwkeurige tijdsafpassingen of seriële communicatie. 5.3 Tips en trucs Inleiding In dit deel van de cursus willen we enkel tips en trucs aanbrengen. Het zijn veel gebruikte technieken voor standaard problemen. De oefeningen in het labo maken hier gebruik van Software tijdsvertraging Een microcontroller voert relatief snel instructies uit. De XC888 controller uit het labo loopt op 24MHz. De CPU heeft 2 klokpulsen nodig om een elementaire operatie uit te voeren. Een elementaire operatie is het verplaatsen van 1 byte data tussen het geheugen en de CPU. De CPU voert de ene elementaire operatie na de andere uit (een elementaire operatie wordt een CYCLE of cyclus genoemd). Op die manier worden instructies gelezen en uitgevoerd. Sommige instructies kunnen in één cycle gelezen en uitgevoerd worden, andere in 2 of 4. De XC888 controller voegt voor het lezen van een byte uit het inwendige FLASH geheugen een wait cycle toe. Hierdoor is de uitvoeringstijd van een instructie afhankelijk van de fetch tijd en de uitvoeringstijd. Door het ingebouwde versnellingsmechanisme is de uitvoeringstijd ook nog afhankelijk van de locatie waar de instructie in het geheugen zit (zie appendix B voor de uitvoeringstijd van de instructies). Voorbeeldprogramma looplicht met software tijdsvertraging Volgend programma laat een looplicht zien op de LED s van poort 3. org 00000h ;start adres programma mov sp,#07fh ;klaar zetten van de stack lcall initleds ;poort 3 klaar zetten voor gebruik LED s lcall initdipswitch ;poort 4 klaar voor gebruik schakelaars mov a,# b ;getal dat naar P3 gaat (LED s actief laag!) lus: rl a ;(4) we schuiven het getal op zodat een ;looplicht bekomen wordt 136

137 mov p3_data,a ;(6) laten zien ljmp lus ;(10) opnieuw schuiven, laten zien ;enz. #include c:\xcez1.inc ;noodzakelijke driver inladen Hoeveel tijd is er nodig om de lus één keer uit te voeren? In de instructie lijst staan het aantal klokpulsen waarin elke instructie uitgevoerd wordt. In bovenstaand programma zijn ze in vet opgenomen in de commentaar (we hebben de worst case tijd genomen uit appendix B, kolom 1ws). Voor de instructies in de lus zijn er =20 klokpulsen nodig (24MHz klokpulsen of 42ns per klokpuls) ofwel 0,833 µs. Het programma wordt ongeveer per seconde uitgevoerd. Het lijkt alsof alle LED s tegelijk licht geven. Om het programma te vertragen gebruiken we de djnz instructie. Hiermee kunnen we op een compacte en eenvoudige manier via een programmalus veel instructies uitvoeren. mov r0,#0ffh ;(6) register laden met 255 Loop: djnz r0,loop ;(8) verminder r0 met 1 en indien ;niet nul spring naar loop anders ;verder gaan De djnz instructie duurt 8*42ns=336ns en wordt 255 keer doorlopen zodat er 85µs nodig zijn. De mov instructie duur 6*42ns=252ns. De totale looptijd is dan 85,25µs. Na de uitvoering is het register r0=000h. Stel dat we volgend programma uitvoeren, hoe lang zal dit duren? mov r0,#000h loop: djnz r0,loop Als r0=000h dan is r0-1= 000h-1= 0ffh. De lus wordt dan ook 256 keer doorlopen. Wensen we de vertragingstijd verder op te voeren kunnen we meerdere lussen genest in elkaar gebruiken. Volgend voorbeeld geeft een vertraging van ongeveer 1 seconde: mov r1,#000h ;(6) aantal keer buitenste lus mov r0,#000h ;(6) aantal keer binnenste lus loop: djnz r0,loop ;(8) binnenste lus djnz r1,loop ;(8) buitenste lus De duurtijd van dit programma is: ( ( )) Merk op dat het niet zo eenvoudig is om er voor te zorgen dat een tijdsvertraging vb. exact µs (1s) tijdsvertraging geeft. We zullen software vertragingen dan ook maar gebruiken om ongeveer (10% juist) tijden af te passen. 137

138 Om de tijdsvertraging afhankelijk te maken van de schakelaars op het bord kunnen we bvb. het volgende programma gebruiken: mov r1,#000h ;aantal keer buitenste lus loop1: mov r0,p4_data ;aantal keer binnenste lus ;p4=schakelaars loop: djnz r0,loop ;binnenste lus djnz r1,loop1 ;buitenste lus (r0 moet herladen ;worden want is nu 000h) De looptijd wordt gegeven door volgende formule: ( ( )) ( ( )) De programmeur kan een oneindig aantal variaties op bovenstaande programma s bedenken. Je moet wel na(rekenen)meten wat de uiteindelijke vertraging zal zijn. In de xcez0.inc driver zit er een tijdsvertraging, waarvan de uitvoeringstijd afhankelijk is van de getalwaarde in de accu. De routine delaya0k05 duurt 0,05s als de accu=1, en 12,75s als de accu=255. Is de accu=000h dan zal de tijdsvertraging 12,8 seconden bedragen. LET OP!! Inwendig in de controller zijn er mechanismen voorzien die de uitvoering van code versnellen. Hierdoor klopt de berekende tijd niet steeds met de reële uitvoeringstijd. De controller heeft op tijdsgebied een niet deterministisch gedrag. Je zal een tijdsvertraging moeten nameten met de oscilloscoop!! Er bestaat ook de mogelijkheid om het versnellingsmechanisme uit te schakelen (lcall dffch) en opnieuw in te schakelen (lcall dfffh). De opgeroepen routines zitten in de boot ROM van de controller. Er wordt nergens informatie vrijgegeven over de gebruikte hardware om dit systeem te bedienen Aanmaken en uitlezen van tabellen Er zijn veel toepassingen waar tabellen gebruikt worden. Volgend programma laat toe om een willekeurig looplicht te laten zien op de LED s. Voorbeeldprogramma: looplicht met tabel (tellen aantal bytes in tabel) ;declaratie startadres start equ 00000h ;startadres programma 138

139 org start ;start adres van het programma mov sp,#07fh ;stackpointer laden lcall initleds ;poort 3 klaar zetten voor gebruik lcall initdipswitch ;schakelaars klaar zetten voor gebruik lus: mov dptr,#tabel ;startadres tabel in dptr mov r7,#004h ;aantal bytes in de tabel loop: clr a ;accu op 0 zetten movc a,@a+dptr ;waarde uit tabel halen mov p3_data,a ;laten zien mov a,p4_data ;schakelaars naar accu lezen lcall delaya0k05s ;tijdsvertraging oproepen inc dptr ;adres tabel in dptr+1 djnz r7,loop ;herhaal tot r4=000h ljmp lus ;opnieuw opstarten tabel: db b ;eerste waarde in tabel db b ;tweede op een adres hoger db b ;nog een adres hoger db b ;vierde byte #include c:\xcez1.inc tabel is een label die als waarde het startadres krijgt van de tabel in het geheugen, dus de geheugenlocatie waar de byte b staat. Het toekennen van die adreswaarde gebeurt door de assembler die het programma omzet. Het db directief staat voor DEFINE BYTE. Hiermee wordt een constante mee opgenomen in het programma. De volgende uitvoering van het programma laat zien hoe we de assembler de lengte van de tabel kunnen laten berekenen. ;declaratie startadres start equ 00000h ;startadres programma org start ;start adres van het programma mov sp,#07fh ;stackpointer laden lcall initleds ;poort 3 klaar zetten voor gebruik lcall initdipswitch ;schakelaars klaar zetten voor gebruik lus: mov dptr,#tabel ;startadres tabel in dptr mov r7,#(tabel1-tabel) ;aantal bytes in de tabel ; Op het ogenblik dat de assembler het programma omzet zijn de adressen tabel en ; tabel1 gekend. Door het verschil van de adressen te berekenen, is het aantal bytes ; in de tabel gekend. loop: clr a ;accu op 0 zetten 139

140 movc ;waarde uit tabel halen mov p3_data,a ;laten zien mov a,p4_data ;schakelaars naar accu lezen lcall delaya0k05s ;tijdsvertraging oproepen inc dptr ;adres tabel in dptr+1 djnz r7,loop ;herhaal tot r4=000h ljmp lus ;opnieuw opstarten tabel: db b ;eerste waarde in tabel db b ;tweede op een adres hoger db b ;nog een adres hoger db b ;vierde byte tabel1: ;dit is een dummy label die door de ;assembler de waarde krijgt van het eerste vrije adres na de tabel. Het verschil van ;beide getallen geeft de lengte van de tabel. #include c:\xcez1.inc LET OP!! Niet alle assemblers laten dit toe. Het is best mogelijk dat deze oplossing niet toepasbaar is in het labo. Voorbeeldprogramma: looplicht met tabel (verboden code) De volgende variant van het programma gebruikt geen teller om het einde van de tabel te detecteren, maar een verboden code. Dat is een constante die geen deel uitmaakt van de eigenlijke data in de tabel, maar aangeeft dat het de laatste entry van de tabel is. ;declaratie startadres start equ 00000h ;startadres programma org start ;start adres van het programma mov sp,#07fh ;stackpointer laden lcall initleds ;poort 3 klaar zetten voor gebruik lcall initdipswitch ;schakelaars klaar zetten voor gebruik lus: mov dptr,#tabel ;startadres tabel in dptr mov r7,#004h ;aantal bytes in de tabel loop: clr a ;accu op 0 zetten movc a,@a+dptr ;waarde uit tabel halen cjne a,#0ffh,loop1 ;niet 0ffh in accu dan loop1 ljmp lus ;anders opnieuw starten loop1: mov p3_data,a ;laten zien mov a,p4_data ;schakelaars naar accu lezen lcall delaya0k05s ;tijdsvertraging oproepen inc dptr ;adres tabel in dptr+1 ljmp loop ;opnieuw opstarten 140

141 tabel: db b ;eerste waarde in tabel db b ;tweede op een adres hoger db b ;nog een adres hoger db b ;vierde byte db b ;verboden code (willen we niet laten zien) #include c:\xcez1.inc In dit programma kunnen we de tabel verlengen zonder de code aan te passen. Let op!! De waarde 0ffh mag alleen op het einde van de tabel voorkomen. Voorbeeldprogramma: afdrukken tekst uit tabel (PC of LCD) Een tabel kan ook gebruikt worden om aan tekst boodschap in het geheugen op te slaan. Volgend programma geeft hier een voorbeeld van (op de PC loopt hyperterminal of tera term of een ander terminal emulatie programma): start equ 00000h ;startadres programma org start mov sp,#07fh ;stack pointer klaar zetten voor gebruik lcall initsio ;seriële poort initialiseren lcall initlcd ;LCD scherm klaar zetten mov dptr,#msg1 ;adres eerste boodschap lcall siooutmsga ;naar scherm PC lcall lcdoutmsga ;en ook naar het LCD scherm loop: mov a,#100 ;5 seconden wachten lcall delaya0k05s ;100*0,05s delay mov dptr,#msg2 ;adres tweede boodschap lcall siooutmsga ;naar scherm PC lcall lcdoutmsga ;en ook naar LCD loop1: ljmp loop1 ;stoppen controller msg1: db ff, mij kan je bovenaan links lezen,000h msg2: db cr,lf, ik sta 1 lijn lager (na 5s),000h #include c:\xcez1.inc De ff in msg1 is een constante die in de driver de waarde 00ch krijgt (ASCII code voor form feed). siooutmsga en lcdoutmsga zijn subroutines uit de xcez driver die een ASCII string afdrukken op respectievelijk het scherm van de PC (sio) en het LCD scherm. Het startadres van de string moet in de dptr staan. Het laatste karakter van de string 141

142 moet 000h zijn. Wat tussen staat wordt door de assembler omgezet in zijn ASCII codes. In figuur kan je zien wat er op het scherm van de PC, en op het LCD verschijnt. LET OP!! Het LCD scherm en het scherm van de PC reageren anders op bepaalde ASCII codes. De PC volgt de codes uit appendix E, de LCD alleen diegene die beschreven staan in de header van de lcdoutchar routine in de xcez driver. LET OP!! De PC zal automatisch de volgende lijn nemen wanneer een lijn werd volgeschreven. Het LCD scherm doet dat niet. Het scherm vult zijn DDRAM en overschrijft die dan telkens opnieuw. mij kan je bovenaan links lezen ik sta 1 lijn lager (na 5s) Figuur Data op scherm PC en LCD Om variabelen af te drukken zijn er andere monitorroutines beschikbaar. 5.4 Een tabel gebruiken om te vertalen voor linearisering In bepaalde gevallen is er geen, of een onduidelijk wiskundig verband tussen twee getallen. Het ene kan dus niet of zeer moeilijk via een berekening omgezet worden naar het andere. Een voorbeeld hiervan is het verband tussen de temperatuur en de spanning van een thermokoppel. De eenvoudigste manier om de omzetting te doen is via een tabel. In die tabel nemen we voor elke mogelijke spanning van het thermokoppel de overeenkomstige temperatuur op. Een praktisch voorbeeld is het omzetten van een brandstofniveau (h in cm) in een brandstof hoeveelheid (liter). In figuur is een tekening opgenomen van een brandstoftank, met in bijhorende tabel de hoeveelheid brandstof in de tank, in functie van het gemeten brandstofniveau. Die gegevens kunnen opgenomen worden in een 142

143 tabel in het geheugen van de controller. Stel dat we de tabel opnemen in de adressen die vermeld staan in de eerste kolom van figuur Volgende code zal dan de omzetting doen van de gemeten hoogte (cm) naar de beschikbare hoeveelheid: mov dptr,#1000h ;start adres tabel in de dptr mov a,[gemeten hoogte brandstof] movc ;doe de vertaling Stel h=100cm, dan is [gemeten hoogte brandstof]=64h. a+dptr=64h+1000h OP het adres 1064h staat in het geheugen de hoeveelheid beschikbare brandstof. Die waarde wordt in de accu geladen. 255cm Brandstoftank Adres in geheugen 1000h 1001h 1002h 1003h 1004h 1064h niveau h Liter in tank h vloeistof 0cm 10c8h ffh Figuur Brandstoftank Een ander voorbeeld is het omzetten van een binair getal naar een uitlezing op een 7-segment display. De hardware die we gebruiken is fictief. Poort 3 wordt gebruikt voor het aansturen van een 7-segment display (figuur 5.4.2). De laagste 4 schakelaars van poort 4 worden gebruikt om schakelaars in te lezen (p4.3=msb en p4.0=lsb). De waarde van de schakelaars wordt omgezet naar een uitlezing op de 7-segment display. 143

144 org 00000h ;startadres programma mov sp,#07fh ;stackpointer laden mov port_page,#001h ;selecteer poort page 1 mov p4_pudsel,#0ffh ;selecteer pull_up device mov p4_puden,#0ffh ;selectie inschakelen mov port_page,#000h ;selectie poort pagina 0 mov p4_dir,#000h ;poort 4 als input schakelen mov p3_dir,#0ffh ;poort 3 als output schakelen mov dptr,#tabel ;startadres tabel laden loop: mov a,p4_data ;lees de schakelaars anl a,#00fh ;hoogste 4 bits op 0 movc a,@a+dptr ;vertalen via tabel mov p3_data,a ;naar 7 segment uitlezing ljmp loop ;herhaal ;hier staan de binaire patronen die nodig zijn om de cijfers 0-9 en de letters a-f weer ;te geven op het 7-segment display. Let op!! Het display wordt actief laag ;aangestuurd: een 0 doet de LED licht geven, een 1 schakelt de LED uit. tabel: db b ;binair patroon voor 0 db b ;1 db b ;2 db b ;3 db b ;4 db b ;5 db b ;6 db b ;7 db b ;8 db b ;9 db b ;A db b ;b db b ;C db b ;d db b ;E db b ;f #include c:\xcez1.inc Merk op dat er geen wiskundig verband bestaat tussen de display code voor het 7- segment display en het binaire getal dat via poort 4 ingelezen wordt. De dptr wijst steeds naar het adres van de eerste entry in de tabel. De waarde in de accu, afkomstig van p4, vormt een offsetwaarde van 000h tot 00fh, afhankelijk van de 4 schakelaars. De movc a,@a+dptr instructie leest naar de accu wat er op het adres staat gevormd door de som van dptr en a. Na de instructie zal de dptr niet van waarde veranderd zijn, de accu werd overschreven met het getal dat uit het geheugen gelezen is. Deze instructie (movc a,@a+dptr) werkt enkel via een tabel in het code memory. 144

145 F E A G D B C DP A=p3.0 B=p3.1 C=p3.2 D=p3.3 E=p3.4 F=p3.5 G=p3.6 DP=p3.7 V DD A B C D E F G p3.0 p3.1 p3.2 p3.3 p3.4 p3.5 p3.6 DP p Figuur segment aansturing 5.5 HEX, BCD, BIN inlezen en uitschrijven Alle communicatie tussen de PC en de controller gebeurt in ASCII code. Voor elk karakter dat op het scherm komt, of via het klavier verzonden wordt, wordt een 8 bit code gebruikt. Het symbool dat met die code overeenkomt kan je opzoeken in de ASCII code tabel in appendix E. Voor de verdere bespreking gebruiken we de driver routines sioinchar en siooutchar. Sioinchar wacht op een ASCII code. Komt die toe op de seriële poort, dan wordt ze in de accu geplaatst en wordt de routine afgesloten. Wordt het getal in binaire vorm ingegeven, dan wordt per bit één 8-bit ASCII code doorgegeven: 030h voor 0 en 031h voor

146 Wordt het getal ingegeven in verkorte notatie, dan zijn de mogelijke ASCII codes 030h t.e.m. 039h voor de cijfers 0 t.e.m. 9 en 041h t.e.m. 046h voor de letters A t.e.m. F of 061h t.e.m. 066h voor de letters a t.e.m. f. Siooutchar zal voor dezelfde ASCII codes bijhorende symbolen op het scherm plaatsen. Moet een getal binair op het scherm afgedrukt worden, dan zullen we zoveel ASCII codes naar het scherm moeten sturen als er bits in het getal zitten. Bij het decimaal uitschrijven mogen we enkel de ASCII codes voor de cijfers gebruiken. Per symbool geven we eigenlijk 4 bits weer. Bij de weergave van hex getallen mogen ook de letters a-f gebruikt worden. Ook hier staat elk symbool voor 4 bits. Bij het weergeven van een getal zal het programma moeten nagaan wat de waarde van elke individuele bit is (of groepje van 4 bits) om de passende ASCII code te bepalen alvorens die naar het scherm te sturen. Bij het inlezen gebeurt het omgekeerde. Bij het binair inlezen krijgen we 1 ASCII code per bit. Vb: Ingave via klavier: geeft volgende reeks ASCII codes: 031h,030h,030h,031h,030h,030h,031h,031h. Per ASCII code kan maar 1 bit gebruikt worden bij de wedersamenstelling van het getal. Ingave via klavier: a7 geeft volgende twee ASCII codes:061h en 037h. Elke ASCII code is nu 4 bits waard. Volgend programma drukt de inhoud van p4 binair en hex af op het scherm van de PC org 00000h ;start adres programma mov sp,#07fh ;stackpointer in orde zetten lcall initsio ;seriële poort klaar zetten voor gebruik lcall initdipswitch ;schakelaars klaar zetten voor gebruik mov a,#ff ;eerst scherm leeg maken ; de ff is een constante die in de driver de waarde 00ch krijgt (ASCII code voor form ; feed. lcall siooutchar ;naar scherm sturen loop: mov a,p4_data ;lees poort 4 lcall schrbin ;binair op scherm zetten mov a,#blank lcall siooutchar ;blank tussen de twee getallen mov a,p4_data ;poort 4 inlezen lcall schrhex ;hex uitschrijven mov a,#cr ;cursor vooraan lijn lcall siooutchar ;naar scherm schrijven ljmp loop ;lus sluiten 146

147 ; schrbin is een subroutine die de inhoud van de accu op het ; scherm weergeeft als een binair getal. De routine gebruikt de ; accu, psw en r7. schrbin: mov r7,#008h ;loopcounter (lusteller) schrbin1: rlc a ;bit naar carry schuiven push acc ;accu effe bewaren mov a,#030h ;ascii code 0 in accu addc a,#000h ;a=030h+000h+cy ; de accu zal 030h bevatten als carry=0 en 031h als carry=1 ; 030h is ASCII code van 0 en 031h is de ASCII code van 1 lcall siooutchar ;naar scherm PC verzenden pop acc ;accu herstellen djnz r7,schrbin1 ;herhaal tot einde 8 bits ret ; schrhex zal de inhoud van de accu in hexadecimale vorm op het ; scherm plaatsen. De routine gebruikt de accu en psw. schrhex: push acc ;effe bewaren op de stack anl a,#0f0h ;hoogste 4 bits afzonderen swap a ;bits onderaan plaatsen cjne a,#00ah,schrhex1 ;acc<00ah? schrhex1: jc schrhex2 ;ja, dan springen add a,#007h ;neen, dan 007h bij optellen schrhex2: add a,#030h ;altijd 030h bij optellen ; wil je weten hoe dit werkt? Neem stukje papier en reken na ; voor alle mogelijke getallen in de accu. lcall siooutchar ;naar het scherm sturen pop acc ;laagste 4 bits verwerken anl a,#00fh ;hoogste 4 bits afzonderen cjne a,#00ah,schrhex1 ;acc<00ah? schrhex1: jc schrhex2 ;ja, dan springen add a,#007h ;neen, dan 007h bij optellen schrhex2: add a,#030h ;altijd 030h bij optellen ; wil je weten hoe dit werkt? Neem stukje papier en reken na ; voor alle mogelijke getallen in de accu. lcall siooutchar ;naar het scherm sturen ret #include c:\xcez1.inc 147

148 Onderstaand programma leest een getal binair in via het klavier van de PC en laat het zien op poort 3. Bij de laatste ingave kan op de volgende lijn een nieuw getal ingegeven worden. start equ 00000h ;start adres programma org start mov sp,#07fh ;stackpointer laden mov a,#ff ;scherm leeg maken lcall siooutchar ;weg er mee loop: lcall inbin ;binair inlezen byte mov p3_data,a ;naar LED s sturen mov a,#lf ;volgende lijn nemen op scherm lcall siooutchar mov a,#cr ;cursor moet vooraan de lijn lcall siooutchar ljmp loop ; inbin leest een byte binnen als een reeks van 8 binaire ; getallen. De routine stuurt een echo naar het scherm. Het ; ingelezen getal wordt via de accu doorgegeven. De routine ; gebruikt geen registers. inbin: push b ;wordt gebruikt als lusteller push psw ;de vlaggen gaan anders verloren mov b,#008h ;iets gaan we 8 keer doen inbin1: push acc ;gaan we gebruiken als werkreg. lcall sioinchar ;wachten op eerste ingave lcall siooutchar ;echo naar het scherm van de Pc rrc a ;laagste bit afzonderen ;030h is ASCII code van een 0 en 031h is ASCII code van 1 pop acc ;werk accu laden rlc a ;afgezonderde bit inschuiven djnz b,inbin1 ;herhaal 8 keer pop psw ;vlaggen herstellen pop b ;b herstellen ret #include c:\xcez1.inc 5.6 Omrekening HEX naar BCD Bij de omzetting van een hex getal naar een bcd getal gaan we kijken hoeveel keer 10D, 100D, 1000D, in het getal gaan. Dit doen we door een deling uit te voeren. 148

149 Bij de eerste deling delen we het getal door 10D (00ah). Het quotiënt van die deling is het aantal keer dat 10D in het getal gaat. De rest is wat kleiner is dan 10D, dit zijn dus de eenheden. Het quotiënt kunnen we opnieuw delen door 10d (00ah). Het nieuwe quotiënt geeft aan hoeveel honderdtallen er in het getal zitten. De nieuwe rest geeft het aantal tientallen. We delen evenveel keer als er decimale karakters nodig zijn om het getal weer te geven. Stel het hex getal is 0fch. Een deling door 00ah geeft als quotiënt 019h. De rest is 002h. Er zitten 19h (25d) tientallen in het getal en 2 eenheden. De rest van de deling zit altijd tussen 000h en 009h. Het vorige quotiënt delen we opnieuw door 00ah. 019h/00ah geeft als nieuw quotiënt 002h en als rest 005h. Er zitten 2 honderdtallen in het getal en 5 tientallen. Bij de omzetting van een 8 bit hex getal kan het grootste decimale resultaat 255d zijn. In principe delen we drie keer. Eigenlijk is dat niet nodig omdat het quotiënt van de tweede deling nooit groter kan zijn dan 2, zodat verder delen niet zinvol is. Omdat we in een programma lussen zullen gebruiken voor de omzetting is het meestal eenvoudiger om nog eens te delen. 002h/00ah geeft als quotiënt 000h en als rest 002h. dit zijn dan de honderdtallen. In volgend programma voeren we de omzetting door voor een getal dat we inlezen van de schakelaars. Het decimale resultaat wordt naar het scherm van de PC gestuurd. org 00000h mov sp,#07fh ;stackpointer klaar zetten voor gebruik lcall initsio ;seriële poort initialiseren lcall initdipswitch ;schakelaars klaar zetten mov a,#ff ;scherm eenmalig leeg maken lcall siooutchar ;naar scherm sturen loop2: mov a,p4_data ;lees de schakelaars in accu mov r0,#003h ;max uitkomst is 255 dus 3 ; keer delen (getal bestaat uit drie karakters) loop: mov b,#00ah ;we gaan delen door 10d div ab ;a/b en a=quotient b=rest push b ;rest bewaren op de stack djnz r0,loop ;3 keer uitvoeren ; op de stack zitten de drie resten. De stack werkt als een LIFO ; (last in first out). De eerste rest was de eenheden, de ; laatste de honderdtallen. Bij het poppen komen eerst de ; honderdtallen dan de tientallen, en als laatste de eenheden. ; Die waarden moeten nog omgezet worden naar ASCII codes. ; de ascii codes van 0-9 zijn 030h-039h. 149

150 mov r0,#003h ;ook in lus zetten loop1: pop acc ;waarde van stack halen add a,#030h ;omzetting naar ASCII lcall siooutchar ;naar het scherm sturen djnz r0,loop1 ;er zitten drie waarden op de stack mov a,#cr ;cursor vooraan de lijn plaatsen lcall siooutchar ;naar scherm ljmp loop2 ;volgende getal omzetten #include c:\xcez1.inc Voor de omzetting van grotere getallen (groter dan 8 bit) kunnen we de div instructie niet meer gebruiken. We zullen dan een deling moeten gebruiken die getallen van grotere omvang kan verwerken (zie uitleg vermenigvuldigen en delen van grote getallen in paragraaf 5.8). Onderstaand programma kan ook gebruikt worden maar duurt héééééél lang. Het staat hier enkel als voorbeeldprogramma. Het is geschreven voor een 16 bit omzetting (maximale waarde (5 decimale karakters) maar kan aangepast worden voor getallen van onbeperkte afmetingen). Het hex getal wordt ingelezen van het klavier van de PC, de uitkomst komt op het scherm van de PC. ; dit programma leest van de PC een 16 bit hex getal. Het ; wordt omgezet naar een 24 bit bcd getal. De gebruikte methode ; gaat van het hex getal 1 aftrekken tot 0 bereikt wordt. ; Gelijktijdig wordt bij het bcd getal 1 opgeteld. Deze methode ; trekt op niks en vraagt veel processor tijd. De oefening is ; enkel ter illustratie. start equ 00000h ;start adres programma hexhoog equ 020h ;hoogste 8 bits hex getal hexlaag equ 021h ;laagste bits hex getal bcdhoog equ 022h ;hoogste bits bcd getal bcdmid equ 023h ;middelste bits bcd getal bcdlaag equ 024h ;laagste bist bcd getal org start mov sp,#07fh ;stack pointer klaar zetten lcall initsio ;seriële poort klaar zetten mov a,#ff ;scherm eenmalig leeg maken lcall siooutchar lus: mov dptr,#msg1 ;boodschappeke op het scherm lcall sioinbufa ;lees in mov r0,#startbuf ;pointer naar start tabel (default =054h) lcall ascii2 ;2 eerste ASCII codes naar hex getal ;omzetten 150

151 jc start ;fout in omzetting mov hexhoog,a ;opslaan mov r0,#(startbuf+2) ;volgende 2 ASCII codes lcall ascii2 ;omzetten jc start ;fout in omzetting mov hexlaag,a ; er is een geldig hex getal ingegeven. We gaan nu de omzetting ;starten mov bcdhoog,#000h ;initialisatie registers mov bcdmid,#000h ;idem mov bcdlaag,#000h ;idem ; bij de omzetting gebruiken we geen lusteller maar gaan we ; omzetten tot het hex getal 0 is. Dit kan bij de ingave reeds ; het geval zijn! test: mov a,hexhoog ;nagaan hexhoog en hexlaag=0 orl a,hexlaag ;a=0 als hexhoog=hexlaag=0 jz uit ;dan uitkomst naar scherm ; we gaan het 16 bit hex getal met 1 verminderen mov a,hexlaag ;gebruiken een 16 bit - clr c ;carry uit verleden weg subb a,#001h ;-1 mov hexlaag,a ;terug wegschrijven mov a,hexhoog ;eventuele carry verrekenen subb a,#000h mov hexhoog,a ;terug wegschrijven ; nu het bcd getal met 1 verhogen. mov a,bcdlaag ;met lage deel starten add a,#001h ;let op dit is een bcd + da a ;dus corrigeren mov bcdlaag,a ;terug wegschrijven mov a,bcdmid ;eventuele carry doorgeven addc a,#000h da a ;ook dit is bcd + mov bcdmid,a mov a,bcdhoog ;hoogste deel addc a,#000h da a mov bcdhoog,a ;terug wegschrijven ; nagaan of we mogen stoppen. Dit is het geval als het hex ; getal=0 151

152 ljmp test uit: mov a,bcdhoog ;eerst hoge weg lcall siooutbyte mov a,bcdmid ;dan de middelste lcall siooutbyte mov a,bcdlaag ;dan de laagste lcall siooutbyte mov a,#lf ;cursor lijn lager lcall siooutchar mov a,#cr ;cursor vooraan lijn lcall siooutchar ljmp lus msg1: db geef een 16 bit hex getal in:,000h #include c:\xcez1.inc 5.7 Omrekening BCD naar HEX Bij de omrekening van een bcd getal naar een hex getal is er een klein probleem. De controller kan op een bcd getal enkel de add of addc bewerking uitvoeren, om met behulp van de da a instructie, een correct resultaat te produceren. We kunnen wel berekeningen uitvoeren op de individuele nibbles van het getal. Die hebben immers altijd een correcte hex waarde (0 bcd =0 hex en 009 bcd =009 hex ). Als we een bcd getal van rechts naar links bekijken, stellen we vast dat de waarde van de volgende nibble 00ah groter is (zie decimale getallen). Als we die berekening in een programma plaatsen en de getallen optellen bekomen we de hex waarde. Volgend programma voert dit uit voor een 2 karakter bcd getal. Voor grotere getallen zal je de routines voor het vermenigvuldigen van grote getallen moeten gebruiken. Andere mogelijkheden geven omslachtige programma s. ; dit programma leest een 2 karakter bcd getal in via het ; klavier van de PC en zet het om naar een 8 bit hex getal. ; de ingave is heel summier. De echo komt pas na het ingeven ; van de 2 karakters van het getal. Na een spatie wordt de ; uitkomst afgedrukt. start equ 00000h ;start adres programma uitkomst equ 020h ;hier uitkomst in stoppen org start mov sp,#07fh ;stack pointer initialiseren 152

153 lcall initsio ;seriële poort initialiseren mov a,#ff ;scherm eenmalig leeg maken lcall siooutchar ;weg er mee lus: mov dptr,#msg1 ;boodschap naar het scherm lcall siooutmsga lcall sioinbyte ;inlezen van een 8 bit getal ; er is geen echo naar het scherm, we doen ook geen foutcontrole ; in de accu zit het bcd getal push acc ;effe copie naar stack lcall siooutbyte ;byte naar scherm mov a,#blank ;spatie naar het scherm lcall siooutchar pop acc ;accu herstellen push acc ;nieuwe copie op stack anl a,#00fh ;laagste 4 bits afzonderen ; die laagste bits moeten niet omgerekend worden mov uitkomst,a ;bewaren pop acc ;opnieuw herstellen accu anl a,#0f0h ;hoogste 4 bits afzonderen swap a ;moeten in laagste 4 bits zitten mov b,#00ah ;deze nibble is 10 keer meer waard mul ab ;vermenigvuldigen add a,uitkomst ;vorige waarde bijtellen de maximale ;uitkomst kan 99d of 063h zijn zodat er maar ;1 byte nodig is om de uitkomst op te slaan. lcall siooutbyte ;uitschrijven naar scherm ljmp lus msg1: db #include cr,lf, geef getal in: (geen echo naar het scherm),000h c:\xcez1.inc Hier laten we zien hoe een 4 karakter bcd getal omgezet wordt: bcd getal =1234h ( b) omzetten naar nibbles: 01h 02h 03h 04h (elke nibble zit in een byte) elke nibble vermenigvuldigen met de passende decimale waarde: 01*1000d 02*100d 153

154 03*10d 04*1d omdat we niet met decimale getallen kunnen vermenigvuldigen wordt dat: 01h*03e8h=03e8h 02h*0064h=00c8h 03h*000ah=001eh 04h*0001h=0004h de som van de producten is 04d2h Merk op dat bij het schrijven van het programma het best een lus kan gebruikt worden. De lus wordt evenveel keer doorlopen als er bcd karakters zijn. 5.8 Vermenigvuldigen en delen van grote getallen In dit deel van de cursus staan 2 voorbeeld programma s die voor 32 bit getallen geschreven zijn. Het programma kan aangepast worden naar zo veel bits als nodig. De gebruikte rekentechnieken komen overeen met die voor decimale getallen, maar dan toegepast op binaire getallen. Voor de deling wordt dat de staartdeling en bij het vermenigvuldigen gebruiken we de sommatie van deelproducten. De techniek kan ook op andere niet 8051 controllers toegepast worden. ; dit programma zal twee getallen van 32 bit met elkaar ; vermenigvuldigen. We gaan er van uit dat ze reeds in de ; registers van de controller staan. De uitkomst wordt ook naar ; registers geschreven. We gebruiken registers in het indirect ; adresseerbare gebied. Omdat het een onderdeel is van een ; groter programma zijn de gebruikelijke org en # directieven ; weggelaten. ;LET OP!! deze adressen mogen niet overlappen met de stack ruimte. ;de traditionele mov sp,#07fh kan nu dus niet. ;de stack kan wel het geheugen gebruiken boven 093h. Mov sp,#093h ;kan dus wel (stack vertrekt vanaf basiswaarde +1, in dit geval 94h). get1hh equ 080h ;adres hoogste byte get1 get1h equ 081h ;lagere byte get1l equ 082h ;volgende lagere get1ll equ 083h ;laagste werkhh equ 084h ;4 werkregisters werkh equ 085h werkl equ 086h werkll equ 087h get2hh equ 088h ;zie hierboven maar get2 get2h equ 089h ;idem 154

155 get2l equ 08ah get2ll equ 08bh uithhhh equ 08ch ;64 bit uitkomst uithhh equ 08dh uithh equ 08eh uith equ 08fh uitl equ 090h uitll equ 091h uitlll equ 092h uitllll equ 093h teller equ 020h ;lusteller telbits equ 021h ;bitteller ; we gaan eerst de uitkomstregisters op 0 zetten mov a,#000h ;gaan uitkomst op 0 zetten mov teller,#008h ;er zijn 8 registers mov r0,#uithhhh ;r0 als pointer naar uithhhh lus: ;naar geheugen schrijven inc r0 ;pointer aanpassen djnz teller,lus ;herhaal 8 keer ; we gaan eerst de werkregisters op 0 zetten mov a,#000h ;gaan uitkomst op 0 zetten mov teller,#004h ;er zijn 8 registers mov r0,#werkhh ;r0 als pointer naar werkhh lus1: ;naar geheugen schrijven inc r0 ;pointer aanpassen djnz teller,lus1 ;herhaal 4 keer ; we testen de bits van get1 van rechts naar links. Telkens een ; bit 1 is tellen we het 32 bit getal werkhh, werkh, werkl, ; werkll, get2hh, get2h, get2l, get2ll op bij het 32 bit getal ; uithhhh, uithhh, uithh, uith, uitl, uitll, uitlll, uitllll. ; Na elke bittest wordt het 32 bit getal werkhh, werkh, werkl, ; werkll, get2hh, get2h, get2l, get2ll met 2 vermenigvuldigd. ; omdat het over grote getallen gaat worden lussen gebruikt ; de operatie moet 32 keer uitgevoerd worden mov telbit,#032d ;totale lusteller ; we schuiven getal1 1 plaats naar rechts op om die bit te ; testen lus6: mov teller,#004h ;gaat 0ver 4 bytes mov r0,#get1hh ;adres hoogste byte 155

156 lus2: mov ;byte lezen rrc a ;rechts schuiven ;terug naar het geheugen inc r0 ;pointer aanpassen djnz teller,lus2 ;herhaal voor 4 bytes ; in de carry zit de uiterst rechtse bit van get1. Die gaan we ; testen. Als die 1 is moeten we getal2 en de werkregs bij uit ; optellen. Anders niet jnc lus4 ;niet bijtellen dan lus4 ; hier staat een bit som. mov teller,#008h ;gaat over 8 bytes mov r0,#get2ll ;adres laagste byte mov r1,#uitllll ;adres laagste byte clr c ;carry moet op 0 staan lus3 mov a,@r0 ;som uitvoeren addc a,@r1 ;bijtellen ;naar uit schrijven dec r0 ;pointer aanpassen dec r1 ;pointer aanpassen djnz teller,lus3 ;herhaal voor 8 bytes ; De som is klaar. Nu moet get2 met twee vermenigvuldigd worden. ; Bij elke vermenigvuldiging wordt het getal 1 bit groter. ; Om dit op te vangen gebruiken we de 4 werk registers. Lus4: mov teller,#008h ;lusteller mov r0,#get2ll ;adres laden laagste byte clr c ;deze bit wordt ingeschoven lus5: mov a,@r0 ;getal lezen rlc a ;maal 2 ;terug schrijven dec r0 ;pointer aanpassen djnz teller,lus5 ;klaar djnz telbit,lus6 ;32 keer herhalen ; in de uit registers is het 64 bit resultaat beschikbaar. Het volgende programma laat een deling van twee 32 bit getallen zien. Het is opnieuw een onderdeel van een groter programma. We gaan er van uit dat het te delen getal get2 is en de deler is get1. Na de bewerking staat de uitkomst in uit en de rest in de werk registers. get1hh equ 080h ;adres hoogste byte get1 156

157 get1h equ 081h ;lagere byte get1l equ 082h ;volgende lagere get1ll equ 083h ;laagste werkhh equ 084h ;4 werkregisters werkh equ 085h ;bevatten rest na bewerking werkl equ 086h werkll equ 087h get2hh equ 088h ;zie hierboven maar get2 get2h equ 089h ;idem get2l equ 08ah get2ll equ 08bh uithh equ 08ch ;32 bit uitkomst uith equ 08dh uitl equ 08eh uitll equ 08fh tussenhh equ 090h ;bewaren tussenresultaat tussenh equ 091h tussenl equ 092h tussenll equ 093h teller equ 020h ;lusteller telbits equ 021h ;bitteller ; eerst gaan we de werk registers op 0 zetten. De uit registers ; moeten niet op 0 staan omdat ze gevuld worden tijdens de ; berekening. mov teller,#004h ;het gaat over 4 bytes mov r0,#werkhh ;die vanaf dit adres staan mov a,#000h ;ze moeten op 0 komen lus: ;in geheugen stoppen inc r0 ;volgende nemen djnz teller,lus ;4 keer uitvoeren ; de bitteller wordt gebruikt om te tellen hoe dikwijls het ; gehele programma doorlopen wordt. Dit is evenveel keer als er ; bits zitten in het te delen getal (nu 32) mov telbits,#032d ;aantal keer lus doorlopen ; bij de deling gaan we het te delen getal in de werk registers ; shiften (1 bit per keer dat de lus doorlopen wordt). Dit ; nieuwe getal wordt vergeleken met de deler. Is de inhoud van ; de werk registers kleiner, dan wordt in de uit registers ; een 0 geshift. Is de inhoud van de werkregisters groter, dan ; wordt van werk de deler afgetrokken. In de uit registers wordt 157

158 ; een 1 geshift. Op die manier voeren wij ook een staartdeling ; uit. ; het te delen getal wordt een bit opgeschoven naar links in de ; werk registers lus6: mov teller,#008h ;het gaat over 8 bytes mov r0,#get2ll ;hiermee starten lus1: mov a,@r0 ;getal lezen rlc a ;shiften ;opnieuw opslaan dec r0 ;naar volgende wijzen djnz teller,lus1 ;8 keer doen ; we gaan kijken of het getal in de werk registers groter is dan ; de deler. Is dat zo, dan komt het verschil in de werk ; registers te staan. Omdat we dat niet op voorhand weten, ; gebruiken we de tussen registers om het tussenresultaat op te ; slaan. mov teller,#004h ;aantal bytes te bewerken mov r0,#werkll ;adres brongetal mov r1,#get1ll ;adres deler mov b,#tussenll ;adres tussen clr c ;carry op 0 lus2: mov a,@r0 ;byte ophalen subb a,@r1 ;verschil berekenen ; we hebben maar twee pointers. Daarom effe de adressen ; van plaats veranderen. xch a,b ;inhoud omruilen xch a,r0 ;inhoud omruilen ;uitkomst wegschrijven ; adressen terug op hun plaats zetten xch xch a,r0 a,b ; adressen aanpassen dec dec dec r0 r1 b ; moeten we 4 keer doen djnz teller,lus2 158

159 ; als de carry op 1 staat was werk<get1 en mag werk niet ; vervangen worden door tussen, anders wel. jc lus4 ;als carry 1 naar lus4 ; we copieren de inhoud van de tussen registers naar de werk ; registers. mov teller,#004h ;gaat over 4 bytes mov r0,#werkll ;adres bestemming mov r1,#tussenll ;adres bron lus3: mov a,@r1 ;ophalen tussen ;schrijven naar werk dec r0 ;pointers aanpassen dec r1 djnz teller,lus3 ;4 keer herhalen ; als de carry op 1 staat was werk<dan get1 en moet er een 0 ; in uit geschoven worden. Anders een 1 lus4: cpl c ;moeten omgekeerde hebben mov teller,#004h ;moeten 4 bytes shiften mov r0,#uitll ;adres bestemming lus5: mov a,@r0 ;byte lezen rlc a ;carry inshiften ;terug wegschrijven dec r0 ;pointer aanpassen djnz teller,lus5 ; dit moeten we 32 keer herhalen djnz telbits,lus6 5.9 Vierkantswortel berekenen In sommige toepassingen kan het nodig zijn de vierkantswortel te berekenen. In onderstaand voorbeeld leggen we uit hoe dat voor een geheel decimaal getal kan uitgevoerd worden. We wensen de wortel te berekenen van We verdelen het getal in groepjes van twee digits. We gebruiken een, om de groepjes aan te geven. \/ 6,65,64 We zoeken van het eerste groepje het grootste getal waarvan het kwadraat kleiner of gelijk is aan dat groepje. In dit geval is dat 2 want 2*2=4 en 3*3 zou 9 geven, wat te groot is. 159

160 _2 \/ 6,65, We schrijven de twee (is onderdeel van de uitkomst) bovenaan, nemen er het kwadraat van en trekken het van het groepje af. We laten het volgende groepje zakken. Het dubbele resultaat (2*2=4) zetten we voor het nieuw gevormde getal. We zoeken een getal d, zodat d*4d kleiner is of gelijk aan 265. De juiste waarde lijkt hier 5, want 5*45=225 2_5 \/ 6,65, We herhalen de vorige redenering (het dubbel van 25 is 50 en d*50d 4064) \/ 6,65, De uitkomst kan je vinden op: Deze redenering gaan we toepassen op een binair getal. Het voorbeeldprogramma neemt de wortel van een 8 bit geheel getal. Om de berekening uit te voeren gebruiken we een aantal hulpregisters. Bron bevat het getal waar we de wortel willen van berekenen werk daarin shiften we het brongetal per 2 bits probeer bevat de waarde van (uit *4 +1) uit zal de uitkomst bevatten tel lusteller=aantal bits/2 160

161 Het programma is geschreven als een onderdeel van een ander programma. We gaan er van uit dat in bron reeds het getal staat waar we de wortel willen van berekenen. mov werk,#000h ;op 0 zetten mov uit,#000h ;idem mov tel,#004h ;bron is 8 bits groot ; eerst zetten we in werk twee bits van bron lus: mov a,bron ;in accu om te shiften rlc a ;eerste bit mov bron,a ;terug bewaren mov a,werk ;inschuiven rlc a mov werk,a mov a,bron ;in accu om te shiften rlc a ;tweede bit mov bron,a ;terug bewaren mov a,werk ;inschuiven rlc a mov werk,a ; nu in probeer (uit *4 +1) mov a,uit ;in accu klaar maken rl a ;*2 setb c ;carry inshiften=*2+1 rlc a ;klaar mov probeer,a ;in register schrijven ; we gaan kijken of het in werk kan mov a,werk ;gaan verschil berekenen clr c ;mag niet meespelen subb a,probeer ;carry=0 ok jc lus1 ;carry 1 zie verder ; de carry is 0. Werk wordt vervangen door het berekende ; verschil. In uit wordt een 1 ingeschoven mov werk,a ;verschil in werk mov a,uit ;moet 1 in komen setb c rlc a ;*2+1 mov uit,a ;terug op zijn plaats ljmp lus2 ; de carry was 1, het verschil mag niet in werk. In uit moet een 161

162 ; 0 ingeschoven worden lus1: mov a,uit ;moet 0 ingeschoven worden rl a ;*2 mov uit,a ;terug op zijn plaats ; er is een stap van de itteratie uitgevoerd. Dat moeten we ; herhalen tot tel=0 lus2: djnz tel,lus ;herhaal ; de berekening is klaar. In uit staat de wortel 5.11 Referenties naar de ftp site Op de FTP site van de hogeschool is een database van gegevens rond microcontrollers samengebracht. De informatie is in mappen ondergebracht per type controller. Algemene informatie aangaande 8051 controllers zit in de map 8051 general. Voor de XC888 controller is er een specifieke map met alle informatie en beschikbare software. Op het internet kan je tal van application notes vinden over binaire berekeningen. Deze application notes zijn niet steeds 100% foutloos. Neem ze niet klakkeloos over!!! 162

163 Hoofdstuk 6 XC888 hardware units 6.1 Inleiding De vorige hoofdstukken hebben de controller behandeld vanuit een software standpunt. Om een controller te kunnen programmeren moet je een goed inzicht hebben van de geheugenstructuur en de beschikbare instructies. Om een minimale I/O toe te laten werd in het vorige hoofdstuk gebruik gemaakt van de parallelle poorten en van het LCD scherm en de seriële poort die via drivers aanspreekbaar waren. Een controller heeft echter heel wat bijkomende hardware units aan boord. In het blokschema in figuur kan je de I/O units terugvinden. Figuur Hardware units van de XC888 microcontroller Figuur geeft een opsomming van de hardware mogelijkheden van de controller. De hardware units kunnen de CPU ondersteunen bij specifieke opdrachten, die in software niet of nauwelijks uitvoerbaar zijn: gebeurtenissen tellen, tijd afpassen (nauwkeurig), spanning meten, signalen genereren (o.a. PWM), communicatie en complexe berekeningen. 163

164 Figuur Hardware mogelijkheden controller Het is niet de bedoeling om de XC888 User s Manual hier op te nemen. De volgende paragrafen geven een beperkte greep uit de hardware mogelijkheden. Voor meer info en een bespreking van alle mogelijkheden verwijzen we naar de XC888 User s Manual, de XC888 datasheet en de XC800 Architecture and instruction set Manual. Deze documenten kan je terugvinden op de FTP site van de campus en de site. Vele van deze units kunnen interrupts gebruiken. Een interrupt laat toe dat de hardware ingrijpt in het verloop van een programma. Op deze manier kan een hardware gebeurtenis een bijhorend (sub)programma opstarten. De reactietijd van de controller op een gebeurtenis of event wordt zo geminimaliseerd. 6.2 Interrupt Inleiding Wanneer een processor een taak uitvoert, bestaat die meestal uit een cyclische opeenvolging van opdrachten. In figuur wordt dat weergegeven door het programmaverloop uit te zetten in de tijd. Binnen een cyclus wordt er op een bepaald moment gekeken of er een hardware gebeurtenis zich voordoet (vb. indrukken schakelaar). Wanneer dat niet het geval is, gaat de processor verder met het normale programmaverloop, en is het wachten tot de volgende test, alvorens het indrukken van de schakelaar getest (gezien) wordt. In de tussentijd is het programma blind voor variaties in de hardware. De reactietijd is dus afhankelijk van de lengte van het programma. Je zou ook meerdere keren 164

165 kunnen testen op de hardware gebeurtenis, maar dan wordt de duurtijd van het programma nodeloos langer als er geen gebeurtenissen zijn. 1 cyclus programma Tijd Test HW Test HW Test HW Geen test HW Geen test HW Geen test HW Figuur Programmaverloop in de tijd. Door hardware opgestart Hoofd programma Hoofd programma Interrupt routine Initialisaties (geen interrupts) Initialisaties (ook interrupts) Taak 1 Taak 1 Neen Test HW Ja Speciaal 1 Speciaal 1 Speciaal 2 Speciaal 2 Taak 2 Taak 2 RETI Taak 3 Taak 3 Zonder interrupt Met interrupt Figuur Flowcharts programma zonder- en met interrupt 165

166 In figuur zijn twee flowcharts opgenomen. De flowchart zonder interrupt komt overeen met de tijdslijn uit figuur Wanneer we interrupt gebruiken, wordt de test HW (test op Hard Ware gebeurtenis) overgelaten aan een apart circuit in de microcontroller, het interrupt systeem of interrupt controller. Het gewone programma test de gebeurtenis niet meer, en voert cyclisch de normale taken uit (taak 1, taak 2 en taak 3). Wanneer de interrupt controller de hardware gebeurtenis detecteert (ongeacht waar de CPU in het hoofdprogramma zit), wordt het hoofdprogramma onderbroken, en zal de interruptroutine opgestart worden. Na de RETI instructie (RETurn from Interrupt), wordt het hoofdprogramma verder uitgevoerd (vanaf de plaats waar het onderbroken werd). Van zodra interrupt gebruikt wordt, bestaat de flowchart uit minimaal 2 delen (hoofdprogramma en minimaal 1 interruptroutine), die NIET met elkaar verbonden zijn. Er is immers geen verband tussen de uitvoering van het hoofdprogramma en het moment waarop de hardware gebeurtenis zich voordoet Interrupt bronnen Interrupt bronnen zijn hardware units die een toestandsverandering kunnen detecteren, en op die manier een interrupt kunnen genereren. Zo zullen niet alle aansluitklemmen van de controller een verandering in toestand kunnen signaleren doormiddel van interrupt. Hier volgt een opsomming van de mogelijke interrupt bronnen: Systeembronnen: WDT, PLL, FLASH, Brown out Timers: T0, T1, T2, T21, CCU6 Pinnen: EXT0-EXT6, T2ex, T21ex Seriële communicatie: UART, UART1, SSC, MULTICAN ADC CORDIC MDU Een bron kan maar een interrupt genereren wanneer het via het programma wordt toegestaan. Na reset zijn dus alle interrupt bronnen uitgeschakeld!! Het programma moet dus initialisatie software bevatten die zowel de hardware als de CPU klaar zet om interrupts te genereren en te verwerken Interrupt vectoren In de figuur kon je zien dat er een aparte (deel)flowchart is voor de interruptroutine. Je kan een interruptroutine het best vergelijken met een hardware 166

167 geactiveerde subroutine. Die wordt niet opgestart door het programma via een lcall instructie, maar door de hardware via een signaal naar de CPU. Voor elke interrupt bron is er een apart signaal naar de processor, die op deze manier weet, welke interrupt routine opgestart moet worden (figuur ). Figuur Interrupt vectoren en interrupt bron 167

168 Er kunnen dus meerdere interruptroutines aanwezig zijn. De programmeur moet de door hem geschreven interruptroutines beschikbaar maken voor de CPU. Dat gebeurt door de routines op welbepaalde plaatsen in het geheugen op te slaan. M.a.w. de startadressen van de interruptroutines liggen vast, en zijn afhankelijk van de interrupt bron. Die adressen worden interrupt vectoren genoemd. In figuur staan de interrupt vectoren met bijhorende interrupt bron afgebeeld In de figuur kan je ook vaststellen dat sommige vectoren door verschillende bronnen gebruikt worden (vb. 0073h). In dat geval zal bij de aanvang van de interruptroutine nagegaan moeten worden wie de interrupt effectief heeft gegenereerd (Indien je, bij voorbeeld, in de groep XINTR9 alleen external interrupt 3 hebt toegestaan, dan hoef je natuurlijk de andere (die niet werden ingeschakeld) niet te testen) Interrupt prioriteit Interrupts worden vooral gebruikt wanneer de CPU snel moet reageren op een hardware gebeurtenis. Zo zal er informatie verloren gaan, wanneer de CPU niet snel genoeg inkomende data op een seriële verbinding verwerkt. Is er maar 1 interrupt bron, dan stelt zich geen probleem. Het hoofdprogramma kan enkel door die ene interrupt routine onderbroken worden. Meestal worden meerdere Interrupts gebruikt. Ze kunnen dan ook gelijktijdig of kort na elkaar voorkomen. In dat geval kan het zijn dat er voorrang gegeven moet worden aan bepaalde interrupt routines. Nemen we een auto als voorbeeld. Wanneer een embedded systeem in een wagen een botsing detecteert, dan krijgt dit signaal best voorrang op het signaal van het gaspedaal (versnellen is immers niet erg zinvol, de airbag gebruiken wel). Worden geen prioriteiten gebruikt, dan zal de CPU het interrupt signaal verwerken dat eerst komt. Alle andere signalen moeten wachten tot de opgestarte interrupt routine is afgewerkt. Pas daarna wordt opnieuw een interrupt signaal verwerkt. Een interrupt kan dus pending (hangende of wachtend op verwerking) zijn. Om een inkomend interrupt signaal niet verloren te laten gaan, beschikt elke interrupt bron over een bit die als geheugen werkt voor de hardware gebeurtenis. In sommige gevallen zal de CPU deze pending bit zelf clearen na de uitvoering van de interrupt routine, in andere gevallen (wanneer er meerdere interrupt bronnen zijn per vector), zal dat via software moeten gebeuren voor het einde van de interrupt routine. Vermits er maar 1 pending bit is per bron, moet die terug op 0 staan voor de volgende gebeurtenis. Als dat niet zo is, gaan er interrupts verloren. Worden prioriteiten gebruikt, dan krijgen interrupt bronnen voorrang t.o.v. andere bronnen, en mogen ze zelfs de interrupt routines van andere bronnen onderbreken. De XC888 beschikt over 4 prioriteit niveaus (standaard bij 8051 is dat 2). 168

169 bron2 bron1 bron1 bron2 Figuur laat zien wat er gebeurt voor 2 interrupt routines op een verschillend niveau van prioriteit. Prioriteit Introut2 Introut1 Hoofdprogrmma Tijd bron1 pending Figuur Wisselwerking interruptroutines We doorlopen de figuur volgens de tijdsas (links naar rechts): 1. Het hoofdprogramma wordt onderbroken door een signaal van bron2. 2. Introut2 wordt opgestart, Het hoofdprogramma ligt stil. 3. Er komt een signaal van bron1. De bron heeft geen hogere prioriteit dan bron2, de interrupt moet wachten (bron1 pending). 4. Introut2 is afgewerkt. Het hoofdprogramma wordt opgestart voor 1 instructie, waarna het signaal van bron1 verwerkt wordt. 5. Na de uitvoering van de introut1 loopt het hoofdprogramma tot er opnieuw een signaal komt van bron1 en de bijhorende routine opgestart wordt. 6. Er komt een signaal van bron2. Dat heeft een hogere prioriteit dan bron1, waardoor de introut1 onderbroken wordt, en introut2 van start gaat 7. Introut2 is klaar, de CPU gaat verder met introut1 8. Introut1 is klaar waardoor het hoofdprogramma terug verder gezet wordt. Het al of niet toekennen van een hogere prioriteit aan een interruptroutine is afhankelijk van de lengte van de interruptroutine en het tijdsinterval tussen de interrupts. Figuur laat zien wat er kan gebeuren indien een interruptroutine die relatief lang duurt een te hoge prioriteit krijgt. 169

170 bron2 bron1 bron1 bron1 Prioriteit Introut2 Introut1 Hoofdprogrmma Tijd bron1 pending Nieuwe interrupt bron1 vorige gaat verloren Figuur Pending tijd te lang Binnen elk van de 4 interrupt prioriteiten is er een volgorde waarmee de CPU de interrupt bronnen afvraagt. Dat worden in de 8051 manuals ook prioriteiten genoemd. Gelet op het feit dat het hier slechts over een prioriteit gaat in de volgorde van scannen, en niet het onderbreken van elkaars routines, is dat geen echte prioriteit, en wordt dan verder ook niet besproken Interrupt initialisatie In figuur is voor een beperkt aantal interrupt bronnen het signaalpad weergegeven. Alle onderdelen aan de linker kant van de grijze lijn behoren tot de hardware van de unit die de interrupt kan genereren. Laten we als voorbeeld de UART nemen. De initialisatie en de werking van de UART is niet opgenomen in deze figuur. De twee signalen van de UART geven aan dat er een byte verzonden (TI) of ontvangen (RI) werd. Dat wordt opgeslagen in de RI en TI bits die de interrupt pending bits vormen. Wil het signaal tot bij de CPU komen (rechts van de grijze stippellijn), moeten de schakelaars ES en EA gesloten worden. De schakelaar EA is gemeenschappelijk voor alle interrupt bronnen en wordt de algemene interrupt enable schakelaar genoemd (Enable All). De ES schakelaar is er enkel voor de seriële poort. De andere bronnen hebben hun eigen individuele interrupt enable schakelaar. De IP schakelaars laten toe om de prioriteit in te stellen. De hardware russen beide grijze lijnen wordt de interrupt controller genoemd. 170

171 Figuur Interrupt pad De schakelaars in de figuur worden aangestuurd door bitvariabelen in de SFR s. De initialisatie bestaat uit volgende stappen: 1. Initialisatie van de betrokken hardware unit, zodat die doet wat de bedoeling is (vb. UART instellen voor juiste baud rate en frame format, pinnen activeren) 171

172 2. Initialisatie van de interrupt controller (sluiten van de individuele interrupt enable schakelaar, sluiten van de algemene interrupt enable schakelaar, en indien gewenst de juiste prioriteit instellen) 3. Interruptroutine moet op juiste adres in het geheugen staan Vormvereisten interrupt routines Een interrupt routine moet aan een aantal voorwaarden voldoen wil je voorkomen dat de toepassing vast loopt: 1. Interrupt routines moeten zo kort mogelijk zijn. 2. Interrupt routines mogen alleen relevante gegevens aanpassen. 3. Interrupt routines MOETEN afgesloten worden met de RETI instructie Verklaring: 1: Indien interrupt routines te lang duren kunnen ze de werking van andere interrupts hypothekeren (figuur ), of ze kunnen het hoofdprogramma zo lang onderbreken dat dit schijnbaar te traag wordt. In interrupt routines worden dan ook: GEEN DELAY s gebruikt geen lussen die de uitvoeringstijd lang maken (vb. oneindige loops) aansturen van trage I/O (vb. boodschappen naar LCD of seriële poort) vermeden wachten op externe gebeurtenissen (vb. indrukken schakelaars) vermeden 2: Zowat elk programma zal een variabele testen of wijzigen. Om dit te doen wordt meestal gebruik gemaakt van de accu en PSW. In het hoofdprogramma worden die ook gebruikt. De interrupt routine onderbreekt het hoofdprogramma, en moet er voor zorgen dat (door gebruik te maken van PUSH en POP instructies) de registers die in het hoofdprogramma in gebruik zijn hun originele waarde behouden (zie voorbeeldprogramma). LET OP!! Dit is ook van toepassing op de SFR s. Doordat er verschillende pagina s en mappen zijn, moet een interrupt routine die de I/O gebruikt, de originele selecties herstellen na gebruik. (zie voorbeeldprogramma) 3: Indien een interrupt routine niet afgesloten wordt met een RETI, maar met een gewone RET instructie, zal het interrupt systeem geen verdere interrupts verwerken. De RETI instructie grijpt namelijk in op de interrupt controller, en hersteld het scannen voor volgende interrupts. Voorbeeld van programma met een timer 0 interrupt Het programma gebruikt timer 0 om interrupts te genereren (voor de werking van de timer verwijzen we naar de volgende paragraaf). Het is de bedoeling om op interrupt 172

173 basis op de LED s een looplicht te laten zien dat elke seconde 1 plaats opschuift. In het hoofdprogramma laten we een teller zien op het LCD scherm. loopl equ 020h ;wordt gebruikt als geheugen looplicht div1 equ 021h ;hulpregisters introut div2 equ 022h ;idem teller equ 023h ;register om teller op te slaan org 00000h ;start adres programma ljmp main ;spring over de interrupt vector over org 0000bh ;start adres interrupt routine timer 0 ljmp introutt0 ;spring naar interrupt routine main: mov sp,#07fh lcall initlcd ;LCD scherm klaar voor gebruik mov a,#003h ;code om cursor uit te schakelen lcall lcdoutchar ;afdrukken lcall initleds ;LED's klaar voor gebruik mov loopl,# b ;startwaarde looplicht mov div1,#250 ;software deler introutt0 mov div2,#192 ;idem mov teller,#000h ;startwaarde teller op 0 lcall initt0 ;timer 0 klaar zetten voor gebruik lcall initint ;interrupts toelaten lus: mov a,#00dh ;cursor vooraan de lijn lcall lcdoutchar mov a,teller ;teller afdrukken lcall lcdoutbyte mov a,#020d ;wachten gedurende 1s lcall delaya0k05s ;20 keer 0,05s=1s inc teller ;teller +1 ljmp lus ;herhaal ; initto zet de timer 0 klaar voor gebruik. We gebruiken de timer in de 8 bit auto ; reload mode. De teller telt aan cyclustijd: 1/ s. ; In de 8 bit auto reload mode delen we door 250. ; Er komen dus interrupts alle 1/48000 s ; we zullen verder in software moeten afdelen initt0: mov tl0,#6 ;teller telt omhoog en geeft overflow bij 256 mov th0,#6 ;reload waarde voor tl0 mov tmod,# b ;t0 in 8 bit auto reload, timer, no gate setb tr0 ;timer starten ret ; initint zet de interrupts klaar. initint: setb et0 ;enable timer 0 interrupts setb ea ;algemene schakelaar sluiten ret ; Dit is de interrupt routine. Ze wordt alle /250 s opgestart. ; Dat is per seconde. Door te delen door 250 en 192 komen we aan ; 1 interrupt per seconde introutt0: djnz div1,intend ;indien niet 0 einde introutt0 173

174 mov div1,#250 ;indien 0 herladen djnz div2,intend ;indien niet 0 einde introutt0 mov div2,#192 ;indien 0 herladen ; hier komen we na interrupts, dat wil zeggen na 1 seconde. Omdat we nu registers ; gaan gebruiken die in het hoofdprogramma ook gebruikt worden, moeten we pushen en poppen push acc push psw mov a,loopl ;aanpassen looplicht rl a ;door te shiften mov loopl,a ;terug in geheugen plaatsen mov p3_data,a ;laten zien pop psw ;registers herstellen pop acc ; De psw werd in de interrupt routine niet aangepast, en hadden we dus niet moeten ; bewaren op de stack. intend: #include reti xcez1.inc Stel dat het hoofdprogramma de map en de pages zou gebruiken (omdat het dingen doet met poorten en vb. MDU) dan moeten de vetgedrukte lijnen aan de interrupt routine toegevoegd worden: ; Dit is de interrupt routine. Ze wordt alle /250 s opgestart. ; Dat is per seconde. Door te delen door 250 en 192 komen we aan ; 1 interrupt per seconde introutt0: djnz div1,intend ;indien niet 0 einde introutt0 mov div1,#250 ;indien 0 herladen djnz div2,intend ;indien niet 0 einde introutt0 mov div2,#192 ;indien 0 herladen ; hier komen we na interrupts, dat wil zeggen na 1 seconde. Omdat we nu registers ; gaan gebruiken die in het hoofdprogramma ook gebruikt worden, moeten we pushen en poppen push acc push psw push syscon0 ;map select mov syscon0,#004h ;basis map kiezen push port_page ;pagina bewaren mov port_page,#000h ;nu is p3_data toegankelijk mov a,loopl ;aanpassen looplicht rl a ;door te shiften mov loopl,a ;terug in geheugen plaatsen mov p3_data,a ;laten zien pop port_page ;pagina herstellen pop syscon0 ;map herstellen pop psw ;registers herstellen pop acc ; De psw werd in de interrupt routine niet aangepast, en hadden we dus niet moeten ; bewaren op de stack. intend: reti 174

175 Syscon0 en port_page registers (zoals meerdere page registers in de XC888) hebben hun eigen hardware back-up registers. Hierdoor kan de push en mov instructie vervangen worden door 1 move instructie, waarbij automatisch de huidige waarde bewaard wordt in de back-up registers. Het herstellen gebeurt ook door een mov i.p.v. een pop. Dit systeem laat toe om 1 instructie te besparen per SFR in de interrupt routine. Het nadeel van het systeem is dat de programmeur goed moet bijhouden waar welk back-up register gebruikt wordt. Via de gewone stack kost het een extra instructie, maar dat systeem is makkelijker bij te houden. Voorbeeldprogramma uurwerk Dit programma drukt een uurwerk af op het LCD scherm. Omdat het afdrukken een trage gebeurtenis is, doen we dat vanuit het hoofdprogramma. De berekening van de klok zit in de interrupt routine. Door een bit te zetten in de interruptroutine geven we aan wanneer de tijd aangepast is. Op die manier wordt voorkomen dat het hoofdprogramma permanent data afdrukt die niet aangepast wordt. Merk op dat het programma het kristal als tijdsbasis gebruikt. De RC keten laat een nauwkeurigheid toe van 5s op 3 minuten (2,78%). Met het kristal wordt dat 3s/dag. loopl equ 020h ;wordt gebruikt als geheugen looplicht div1 equ 021h ;hulpregisters introut div2 equ 022h ;idem teller equ 023h ;register om teller op te slaan uur equ 024h ;opslaan uren min equ 025h ;opslaan minuten sec equ 026h ;opslaan seconden bitsec equ 027h.0 ;bit om aan te geven tijd aangepast org 00000h ;start adres programma ljmp main ;spring over de interrupt vector over org 0000bh ;start adres interrupt routine timer 0 ljmp introutt0 ;spring naar interrupt routine main: mov sp,#07fh lcall xcsw2xtal ;overschakelen van RC klok naar kristal lcall initlcd ;LCD scherm klaar voor gebruik mov a,#003h ;code om cursor uit te schakelen lcall lcdoutchar ;afdrukken lcall initleds ;LED's klaar voor gebruik lcall lcdlighton ;achtergrond verlichting aan mov loopl,# b ;startwaarde looplicht mov div1,#250 ;software deler introutt0 mov div2,#192 ;idem mov uur,#020 ;startwaarde uurwerk mov min,#010 mov sec,#000 clr bitsec lcall initt0 ;timer 0 klaar zetten voor gebruik lcall initint ;interrupts toelaten lus: mov a,#00dh ;cursor vooraan de lijn lcall lcdoutchar ;afdrukken van uu:mm:ss jnb bitsec,$ ;wachten op verandering vanuit introutt0 mov a,uur 175

176 lcall hexbcd8 ;decimaal afdrukken lcall lcdoutbyte mov a,#':' lcall lcdoutchar mov a,min lcall hexbcd8 lcall lcdoutbyte mov a,#':' lcall lcdoutchar mov a,sec lcall hexbcd8 lcall lcdoutbyte ljmp lus ;herhaal ; initto zet de timer 0 klaar voor gebruik. We gebruiken de timer in de 8 bit auto ; reload mode. De teller tellen aan cyclustijd: 1/ s. ; In de 8 bit auto reload mode delen we door 250. ; Er komen dus interrupts alle 1/48000 s ; we zullen verder in software moeten afdelen initt0: mov tl0,#6 ;teller telt omhoog en geeft overflow bij 256 mov th0,#6 ;reload waarde voor tl0 mov tmod,# b ;t0 in 8 bit auto reload, timer, no gate setb tr0 ;timer starten ret ; initint zet de interrupts klaar. initint: setb et0 ;enable timer 0 interrupts setb ea ;algemene schakelaar sluiten ret ; Dit is de interrupt routine. Ze wordt alle /250 s opgestart. ; Dat is per seconde. Door te delen door 250 en 192 komen we aan ; 1 interrupt per seconde introutt0: djnz div1,intend ;indien niet 0 einde introutt0 mov div1,#250 ;indien 0 herladen djnz div2,intend ;indien niet 0 einde introutt0 mov div2,#192 ;indien 0 herladen ; hier komen we na interrupts, dat wil zeggen na 1 seconde. Omdat we nu registers ; gaan gebruiken die in het hoofdprogramma ook gebruikt worden, moeten we pushen en poppen setb bitsec ;uurwerk wordt aangepast push acc push psw mov a,sec ;berekening uurwerk in hex add a,#001h mov sec,a cjne a,#60,dag2 mov sec,#000h mov a,min add a,#001h mov min,a cjne a,#60,dag2 mov min,#000 mov a,uur 176

177 add a,#001 mov uur,a cjne a,#24,dag2 mov uur,#000h dag2: mov a,loopl ;terug in geheugen plaatsen mov p3_data,a ;laten zien (zit ook nog looplicht in) rl a mov loopl,a pop psw ;registers herstellen pop acc intend: reti #include xcez1.inc 6.3 Timer0 en timer Inleiding De timers 0 en 1 zijn beschikbaar in zowat alle 8051 microcontrollers. Ze waren aanwezig in het originele ontwerp van Intel (1980) en zijn als minimum timers overgenomen in alle nieuwe ontwerpen. Beide timers zijn (op 1 uitzondering na) 100% compatibel. In onderstaande tekst wordt enkel timer 0 besproken. De naam timer laat vermoeden dat het gaat over hardware units om tijd af te passen. In realiteit is de kern van de unit een teller (counter) die gebeurtenissen kan tellen. Als die gebeurtenissen via een externe aansluiting worden aangelegd, wordt de benaming counter gebruikt. Worden inwendige systeemklok pulsen geteld, dan wordt de benaming timer gebruikt. Omdat het onderscheid tussen beide minimaal is, worden beide benamingen door elkaar gebruikt. Sommige fabrikanten spreken dan ook van counter/timer. In figuur staan de 4 modes waarin de timers gebruikt kunnen worden. Mode 0 is een compatibiliteitsmode met de 8048 controllers. Deze mode wordt in 8051toepassingen niet gebruikt. Mode 3 wordt enkel gebruikt wanneer er te weinig timers/counters beschikbaar zijn. In deze mode wordt timer 0 ontbonden in 2 timers. Deze mode wordt uitzonderlijk toegepast in de kleinste 8051 derivaten die maar over 2 timers beschikken. De modes 1 (16 bit timer/counter) en 2 (8 bit auto reload mode) zijn de twee belangrijkste toepassingsvormen. Alleen deze twee worden verder besproken. 177

178 Figuur T0 en T1 modes bit timer/counter In figuur staat het blokdiagram afgebeeld van de timer0. Figuur Blokdiagram timer0 16 bit mode De registers TL0 en TH0 (beide 8 bit SFR s) worden door de hardware als 1 geheel aanzien, en vormen een 16 bit counter. Wanneer de counter niet telt (TR0 bit=0) 178

179 kunnen beide registers geschreven worden met een willekeurige waarde. Ze kunnen altijd uitgelezen worden. LET OP!! wanneer de counter loopt is het mogelijk dat een foutieve waarde uitgelezen wordt. De counter moet immers per byte uitgelezen worden. Het is best mogelijk dat de 16 bit waarde tijdens de 2 leesbeurten aangepast wordt, waardoor de uitlezing foutief is (figuur ). TH0 TL0 00 fe 00 ff mov r0,tl0 r0 ff r mov r1,th Figuur Foutief uitlezen 16 bit timer/counter Aan de linker kant is de inhoud van de counter afgebeeld. We gaan er van uit dat de counter continu aangepast wordt t.g.v. een inkomend signaal. Aan de rechterkant staan de 2 mov instructies afgebeeld die de counter uitlezen. Uiterst rechts staan de getallen die uiteindelijk in de registers r0 en r1 terecht komen. Uitlezen doe je best wanneer de counter uitgeschakeld is. Hierdoor kunnen wel pulsen verloren gaan. Telt de teller relatief traag (t.o.v. uitvoeringstijd instructies), dan kan je overwegen om de counter meerdere keren na elkaar uit te lezen, tot twee opeenvolgende leesbeurten dezelfde waarde opleveren. Figuur Overflow bit 179

180 In figuur zie je dat de 16 bit counter over een overflow bit beschikt. Deze wordt op 1 gezet als de counter waarde ffffh+1 wordt. De counter wordt op 0000h gezet en de TF0 vlag komt op 1. Zijn interrupts ingeschakeld, dan zal de CPU de overflow vlag automatisch clearen wanneer de interrupt routine opgestart wordt. Worden geen interrupts gebruikt, dan blijft de vlag op 1 staan, ook wanneer de counter opnieuw een overflow heeft. Je kan de vlag altijd software matig terug op 0 zetten. De TF0 vlag is ook de interrupt pending bit. Ze kan een overflow onthouden. De figuur laat zien dat er twee mogelijke bronnen zijn voor de inkomende pulsen. Indien de externe klem T0 wordt gekozen, dan spreken we van counter werking (Fmax=500kHz bij een systeemklok van 24 Mhz). Wordt de systeemklok gekozen, dan wordt de unit een timer genoemd. In het laatste geval tellen we pulsen met een vaste tijdsbasis nl. één puls alle 83ns, of de dubbele periode van de systeemklok. De selectie tussen counter- en timermode gebeurt via de controlebit T0S. Figuur Counter/timer mode Interrupts kunnen gegenereerd worden na een bepaalde tijd, of na een bepaald aantal gebeurtenissen. Omdat de interrupt afkomstig is van een overflow (ffffh+1=0000h en een interrupt), kan het noodzakelijk zijn de counter te laden met een startwaarde. Wil je na 100 gebeurtenissen een interrupt, dan al de startwaarde ffffh+1-64h=ff9ch zijn. Na elke interrupt zal de programmatuur de counter moeten herladen (reloaden). Omdat hierbij de counter gestopt moet worden, kunnen inkomende pulsen verloren gaan. De klem T0 kan via het MODPISEL SFR toegekend worden aan 2 verschillende ingangspinnen (T0_0 en T0_1). De counter stoppen en starten gebeurt via de logica uit figuur

181 Figuur Aan/uit controle counter De TR0 bit is vergelijkbaar met een hoofdschakelaar. Die moet op 1 wil het controlesignaal actief worden. Door de GATE0 bit op 1 te zetten kan je het al of niet actief zijn van het controlesignaal laten afhangen van een extern signaal. Dit laat toe om de periode van een puls te meten. De puls wordt aangelegd aan de EXINT0 klem. De counter wordt in de timer mode gezet, en de GATE0 bit op 1. De counter telt nu alleen de systeemklok als de ingangsklem hoog is. In het andere geval wordt de counter gestopt. De EXTINT0 klem kan bovendien een interrupt genereren bij een verandering van signaal. Op die manier hoef je de pin niet te pollen om te weten wanneer de puls ten einde is (zie volgende paragraaf voor een gedetailleerde uitleg) bit timers: periodemeting Bij tijdsmetingen van events (tijdsinterval of periode) worden timers meestal 'gated' gebruikt. De signaalpuls waarvan we de tijdsduur willen kennen wordt m.a.w. gebruikt als schakelsignaal om een kloksignaal met gekende periode door te schakelen naar het tellerregister. Zolang de signaalpuls duurt zal de teller zal worden geïncrementeerd. Indien we het tellerregister voorafgaandelijk clearen, kan nadat de puls verstreken is de tellertoestand gelezen worden. De tellerwaarde is dan een maat voor de verstreken tijd uitgedrukt in klokperiodes. Voor een gekende klokperiode kan hieruit dan de verstreken tijd worden berekend (figuur ). Als kloksignaal wordt meestal het interne oscillatorsignaal gedeeld door 2 gebruikt, wat er op neer komt dat de teller iedere machinecyclus geïncrementeerd wordt. Indien gewenst kan ook een extern kloksignaal op de T0 of T1 ingang als tellerklok gebruikt worden. Men moet het te meten pulssignaal aanleggen aan de INT0/P3.2 ingang, die naast de 'gate'-functie ook tegelijk als interruptingang kan aangeschakeld worden. Dit heeft het bijkomende voordeel dat bij het beëindigen van de puls (event) ook direct een interrupt kan worden gegenereerd, die de routine voor de tijdsmeting opstart. 181

182 OSC Div 2 Set&Cleared door hardware 5V Gnd Extern event T0 pin INT0 pin t 1 Gate > 1 TR0 C/T =0 C/T =1 & Control TL0 (8 Bits) TH0 (8 Bits) Resetten voor intervalmeting TF0 Interrupt INT0 kan gelijktijdig gebruikt worden als een interruptingang en als gate. Wat is de meetonzekerheid, nauwkeurigheid en het bereik van de timer? 166.7nSEC onzekerheid 166.7nSEC onzekerheid t Timerincrements elke nSEC. Figuur Meetonzekerheid bij tijdsmeting van het 'gating'signaal. Afhankelijk van de oscillatorfrequentie zal de teller met een bepaalde snelheid worden geïncrementeerd. Voor een klokfrequentie van 12 MHz is dit 166.7ns. Door het feit dat het 'event' (de te meten puls) asynchroon met het clocksignaal van de teller verloopt zal er een meetonzekerheid bestaan van maximum 166.7ns aan de beide flanken van de te meten puls. Dit resulteert in een onzekerheid van 333.4ns op de tijdsmeting van de puls. Dit is vooral nadelig bij een kleine pulsbreedte (procentuele fout groot). De nauwkeurigheid van de oscillatorfrequentie bepaald ook deze van de pulsbreedte, dit is meestal geen probleem daar de oscillatorfrequentie meestal wordt afgeleid van een quartskristal met een nauwkeurigheid van enkele ppm. Het bereik van de timer wordt bepaald door de mode waarin de timer wordt geschakeld, het grootste bereik (65536 counts of ms@12MHz) wordt bekomen als 16 bit teller in mode1. Softwarematig kan echter het bereik van de timer worden uitgebreid bij eenzelfde resolutie (clockfrequentie). Dit kan door de timeroverflows interrupts te laten genereren (IRQ Timer) die dan softwarematig worden geteld. Op deze manier kunnen we toch een timer implementeren met een praktisch onbeperkt bereik en een hoge resolutie (figuur ). 182

183 Teller register 16 bit FFFFh C/T=0 TR0=1 GATE=1 RESET TH0,TL0 Timer overflow 108Bh 0000h Start meting IRQ Timer IRQ Timer IRQ Timer IRQ Timer t Stop: Gate dicht Gatesignaal t Gate tijd= 4x10923µSEC µsec IRQ Timer : INC COUNTER IRQ gate : lees TH0, TL0 en COUNTER en bereken de tijd IRQ gate Overflows tellen COUNTER TH0 TL0 Figuur Uitbreiding meetbereik timer bit genereren van periodische timeroverflows of 'timeticks' In de meeste systemen moeten er, naast een background taak(hoofdprogramma), op periodische basis een aantal andere taken uitgevoerd worden. De meest gebruikelijke manier om dit te implementeren is deze taken als interruptroutine uit te voeren die periodisch wordt opgestart aan de hand van een timer interrupt. Er zijn een aantal mogelijkheden om dit te verwezenlijken met een timer. 16 bit TIMER (mode1) met software reload. Wanneer we timer 0 of timer 1 in mode1 schakelen en starten, zal hij bij elke machinecyclus geïncrementeerd worden en na counts via een overflow weer vanaf 0000h verder tellen. Door interrupts te laten genereren bij timeroverflow kunnen we zo periodisch om de ms@12MHz een taak laten uitvoeren. Het 183

184 nadeel van deze methode is dat we een vaste periode verkrijgen als tijdsbasis (figuur ). FFFFh Timer overflow 16 bit timer (mode1) zonder reload 0000h t 10923µSEC TimerIRQ TimerIRQ Figuur Time tick van ms. Een oplossing voor dit probleem is het preloaden van de tellerregisters (THx,TLx) met een bepaalde waarde (bv. XXYY) en dan pas de teller te starten. Op deze manier zal de teller veel vlugger zijn eindwaarde bereiken en een interrupt genereren bij het overlopen naar 0000h. Wanneer we nu in de interruptroutine, die als gevolg van de overflow opgestart wordt, de timer even stoppen om hem weer te herladen met de waarde XXYY en hem daarna weer starten, dan zal zich na de ingestelde periode weer een overflow voordoen. De periode wordt zo op een softwarematige manier aanpasbaar (figuur ). De tijd tussen de overflows wordt gelijk aan Tp (10000h-xxyyh)*2/f, plus de tijd nodig om de timer softwarematig te herladen, plus de interruptlatency tijd van de microcontroller. In deze formule is xxyyh de reload waarde van de timer, en f de oscillatorfrequentie. De interruptlatency tijd is de tijd die de controller nodig heeft na het genereren van de interruptrequest (IRQ) tot het uitvoeren van de eerste instructie in de interruptroutine. Deze tijd is afhankelijk van het type instructie die de controller uitvoert bij het opwekken van de IRQ. Niet alle instructies duren immers even lang. Dit heeft timingjitter als gevolg tussen de opeenvolgende timeroverflows. Voor een aantal toepassingen heeft dit geen gevolgen, maar indien we deze 'timeticks' (periodische interrupts) gebruiken voor het genereren van timingsignalen op poortpinnen van de controller, of voor het updaten van een RTC dan zal dit ook hier aanleiding geven tot timingjitter, wat hier zeker niet toelaatbaar is. Zijn er nog andere interrupts mogelijk, dan wordt de tijdsafpassing helemaal onzeker. 184

185 Er moet dus een betere manier gevonden worden (zie reload modes T0 en T1, maar vooral de andere timers)! FFFFh Timer overflows XXYY preload 0000h Timing jitter! t (FFFF-XXYY). 2/f TimerIRQ TimerIRQ TimerIRQ TimerIRQ TimerIRQ Interruptroutine bij timeroverflow: Interrupt latency time = constant!!! stop timer: TR0=0 reload timer: TH0=XX TL0=YY timingjitter start timer: TR0=1 toepassing bv. Sturen van poortpinnen = geschikt als timetick RETI Accumulatie van timingfouten!! Fig Timingjitter bij software reload van de timer bit auto reload mode In figuur is het blokdiagram voor de 8 bit auto reload mode weergegeven. De werking van de counter/timer is bijna identiek aan de 16 bit mode. De enige afwijking zit in het counter deel van het systeem. De counter bestaat uit TL0 en vorm op die manier een 8 bit teller. Die heeft een maximale telwaarde van ffh. Wanneer ffh+1 bereikt wordt, wordt een overflow gegenereerd. De belangrijkste afwijking is het herladen (reloaden) van TL0 met de waarde uit TH0 wanneer er een overflow is. Dit herladen gebeurt in hardware, waardoor de counter niet gestopt moet worden, waardoor er geen inkomende pulsen verloren kunnen gaan. De programmeur moet op voorhand de waarde in de TH0 en TL0 registers schrijven. 185

186 Figuur bit reload mode bit TIMER met autoreload voor het genereren van timeticks De onzekerheid bij het genereren van exacte tijdsintervallen (paragraaf ) kan alleen worden opgelost indien de timer kan herladen worden zonder de softwarematige tussenkomst van de controller. De 8 bit auto reload mode biedt deze mogelijkheid. FFh timeroverflows THx reload waarde 00h (100h-reload).2/f t TLx en THx laden Start timer timer IRQ timer IRQ timer IRQ timer IRQ timer IRQ Fig Hardware reload van de timer 186

187 De timingjitter is hier verdwenen en de periode tussen de interrupt requests wordt enkel nog bepaald door de clockfrequentie en de reloadwaarde van de timer. Deze mode heeft het voordeel dat ze wel kan gebruikt worden voor bv. het incrementeren van een RTC. Zelfs indien de interruptverwerking even moet wachten, start de volgende tijdsperiode op het juiste moment (hardware reload). Het nadeel van deze timermode is dat er bij de standaard 8051 timers (TIMER0 &1) slechts met een 8-bit teller kan gewerkt worden. De maximale periode tussen de interrupts wordt daardoor beperkt tot 256 keer de clockperiode wat voor sommige systemen veel te klein is. Sommige 8051 varianten hebben een bijkomende 16-bit timer(s) (o.a. TIMER2) met autoreload mogelijkheden, wat het probleem oplost. Dit euvel kan echter bij de basistimers TIMER0&1 softwarematig worden weggewerkt door in de interruptroutine het aantal gegenereerde IRQ's te tellen, en pas na een bepaald aantal de toepassing uit te voeren (figuur ). 'COUNTER' is de variabele die na elke IRQ wordt gedecrementeerd en die wanneer hij nul wordt softwarematig weer wordt herladen met de waarde 'SKIP_IRQ'. Ook bij de initialisatiefase van het systeem moet COUNTER met deze variabele worden geladen. timerirq Initialisatie: MOV COUNTER, #SKIP_IRQ DJNZ COUNTER,BACK MOV COUNTER,#SKIP_IRQ Toepassing BACK: RETI Figuur Software verlengen van het tijdsinterval Controleregisters De controle en het aansturen van timer0 en timer1 gebeurt via de registers uit figuur TL0, TH0, TL1 en TH1 zijn de registers die door de hardware gebruikt worden om te tellen. Via IEN0 kunnen interrupts ingeschakeld worden. TCON en TMOD worden in figuur en toegelicht. Merk op dat het TCON register 4 bits bevat die niets te maken hebben met de aansturing van T0 of T1. Het komt wel meer voor dat niet alle bits in een SFR dezelfde functie controleren. Om het register te laden kan je dus best bit-instructies gebruiken (indien bit adresseerbaar), of ORL 187

188 (bits op 1 zetten) of ANL (bits op 0 zetten) zodat enkel de specifieke bits van toestand veranderen. Figuur Controleregisters T0 en T1 Figuur TCON register 188

189 Figuur TMOD register 189

190 6.4 Timer2 en timer Inleiding De meeste 8051 derivaten bevatten ook een timer 2. In tegenstelling met T0 en T1 is de werking van T2 niet bij alle controllers dezelfde. Het is belangrijk de datasheet te raadplegen alvorens software te schrijven. De XC888 heeft T2 en T21. Dit zijn 2 quasi identieke timers. Voor de bespreking beperken we ons dan ook tot T2. LET OP!! De T2 registers zijn toegankelijk in RMAP=0 terwijl de T21 registers in RMAP=1 zitten. RMAP kan aangepast worden via SYSCON0 T2 en T21 zijn 16 bit timers met bijkomende mogelijkheden t.o.v. T0 en T Basis counter T2 In figuur is de basiscounter opgenomen van T2. Dit deel zal, ongeacht de mode waarin de timer gebruikt wordt, steeds terugkeren. Figuur Basis counter T2 (T21) De THL2 counter is een 16 bit teller die uit 2 8 bit SFR s bestaat TH2 en TL2. Beide registers kunnen gelezen en geschreven worden (zie T0 en T1 voor beperkingen). Het inschakelen van de counter gebeurt via de controlebit TR2. Het ingangssignaal kan gekozen worden via de controlebit C/T2. Is de bit 1, dan wordt een extern signaal op klem T2 geteld (Fmax=500kHz indien systeemklok 24MHz). De T2 ingangsklem kan toegewezen worden aan T2_0 en T2_1. 190

191 Is de bit 0, dan wordt er geteld op basis van de systeemklok. Is de bit PREN=0, dan is het ingangssignaal systeemklok/24 = 12 cycles per puls (1µs/puls). Is PREN=1, dan wordt een prescaler (voordeler) gebruikt. Hierdoor kan de klok hardware gedeeld worden (figuur ) Figuur Prescaler T2 Is f T2 =f PCLK dan komt er een puls alle 83ns (12MHz) Is f T2 =f PCLK /128 dan komt er een puls alle 10,67µs Afhankelijk van de andere settings kan de counter gebruikt worden in de volgende modes: auto reload zonder up/down counting auto reload met up/down counting capture mode Bij een overflow van de counter kan er een interrupt gegenereerd worden Auto reload mode en toepassingen De werking van de auto reload mode is afhankelijk van het al of niet selecteren van de Up/Down count mogelijkheid. Wanneer de U/D count niet geactiveerd is, is het blokdiagram van figuur van toepassing. Wanneer de counter een overflow genereert, wordt de THL2 herladen met de inhoud van RC2. De mode is vergelijkbaar met de 8 bit auto reload mode van de T0/T1, alleen betreft het hier 16 bit waarden. Het is mogelijk T2 zo in te stellen dat een extern signaal een reload oplegt. Dit laat toe een time-out bewaking in hardware te implementeren. Indien pulsen die de counter moeten herladen te lang uit blijven, zal de timer een overflow genereren (missing of late pulse detection (figuur )). Het extern herladen van de counter kan een ook interrupt genereren. Omdat dezelfde vector gebruikt wordt als bij een overflow, kan het nodig zijn dat er in de interruptroutine de bron getest wordt. Omdat er meerdere interrupt bronnen zijn per vector, zal de gebruiker de pending bits zelf moeten clearen. 191

192 Figuur T2 auto reload zonder U/D count FFFFh Timer overflow TL2,TH2 laden Reload XXYY 0000h TR2= on EXEN2= on Geen overflow IRQ Overflow IRQ t T2EX pin ok Niet ok ok t Vanaf hier detectie Puls ontbreekt Fig Missing pulse detectie 192

193 Missing pulse detectie kan o.a. gebruikt worden voor het bewaken van de netspanning. Indien we de pulstrein die de reload activeert, afleiden van een nuldoorgangsdetectie van de netspanning (de pulsen komen dan om de 10 ms) dan het wegvallen van de nuldoorgang een overflow veroorzaken. In de Up/Down counter mode wordt de werking weergegeven in figuur Figuur T2 auto reload met U/D count Timer2 kan bij de XC888 ook als up-down counter worden geschakeld, waarbij de 'direction' pin (T2EX) aangeeft in welke richting geteld wordt. In de count up mode wordt een overflow gegenereerd wanneer de waarde ffffh+1 wordt bereikt. De counter zal herladen met de waarde in RC2. In de count down mode wordt de counterwaarde vergeleken met de waarde in RC2. Wordt die bereikt, dan wordt een interrupt gegenereerd, en wordt de counter herladen met ffffh. Op de T2 pin kan in dit geval een extern signaal worden aangelegd waarvan we de pulsen kunnen tellen, terwijl T2EX de telrichting aangeeft. Op deze manier kunnen we een absolute positiemeting doen a.d.h.v. een incrementele lineaire- of hoekencoder. Deze encoders leveren twee 90º verschoven blokgolf-vormig signalen, waarbij elke alternantie overeenkomt met een bepaalde lineaire- of hoekverplaatsing (figuur ). De fase van het 'B' signaal t.o.v. het 'A' signaal (voorijlend of naijlend) is afhankelijk van de bewegingsrichting van de encoder. 193

194 Zo zijn er bv. hoek-encoders op de markt met 100 tot enkele duizenden pulsen per omwenteling! Bij een lijnsensor (lineaire encoder) is een resolutie van 5 pulsen per mm verplaatsing (1 periode per 200 micrometer) courant, denk hierbij maar aan de lijnsensoren die worden gebruikt in de low cost inktjet printers. B ccw B cw A Figuur Hoekencoder met een quadratuur gecodeerd uitgangssignaal B D Q Direction T2EX pin Clk A Count T2 pin Figuur Omzetting van quadratuursignalen in count en direction signalen Door de signalen A en B aan te leggen aan een D-FF halen we uit deze signalen de 'direction' en 'count' informatie die we respectievelijk kunnen aanleggen aan de ingangen T2EX en T2 van timer2 (figuur ). Op deze manier kunnen we de absolute positie bijhouden met de timer indien we deze preloaden met de offsetwaarde 7FFFh. Dit is onze 'home' positie (nulpositie), de positie waarvan we vertrekken met de meting. We kunnen nu evenveel pulsen (de helft van het 16-bit bereik of pulsen) naar boven als naar beneden tellen. Op deze manier kunnen we de absolute positie van onze encoder bijhouden zonder verdere tussenkomst van de CPU (figuur ). Bij een lijnsensor met 5 pulsen per mm zorgt dit voor een bereik van 6,56 m in beide richtingen bij een resolutie van 200 μm! 194

195 Indien dit bereik moet worden uitgebreid, kan dit op eenvoudige manier door softwarematig a.d.h.v. de underflows en overflows een bijkomende variabele (die de MSB vormt van het uiteindelijke bereik) te decrementeren of te incrementeren. FFFFh + 7FFFh TR2= on 0 positie home Preload h t Direction Up Down Up t Count Start beweging Figuur Automatisch bijhouden absolute positie t Capture mode Een 'capture' mode van een timer is een mode waarbij de tellerwaarde van een timer bij een bepaalde gebeurtenis (typisch een flank aan een controlepin van de timer) wordt gecopiëerd naar een capture-register. Dit capture-register kan dan door de CPU worden gelezen en bewaard in het geheugen. Bij een tweede 'capture' kan de CPU het capture-register opnieuw lezen en het verschil maken tussen de twee capture waarden. Het verschil tussen beide waarden is een maat voor het tijdsverschil (periode) tussen de captures (flanken op de controlepin). De CPU wordt op interruptbasis verwittigd van het capturemoment zodat deze op het gepaste moment het captureregister kan lezen ( figuur ). 195

196 Figuur Capture mode De counter telt op het ritme van een vaste klok omhoog, van 0000h tot ffffh. Indien de waarde ffffh+1 bereikt wordt, zal een overflow opgewekt worden, en indien aangeschakeld ook een interrupt. Indien een stijgende- en/of dalende flank aangelegd wordt (instelbaar) aan klem T2EX, zal een copie genomen worden van de counterwaarde. Deze gecopieerde waarde kan uitgelezen worden uit RC2 (capture register). Dit systeem laat toe om heel nauwkeurig tijdsintervallen (periode) (clockresolutie!) tussen signalen meten (figuur ). FFFFh Tellerwaarde Capture2 E01fh overflow Capture1 0000h 1713h Timeroverflow IRQ t T2EX Capture IRQ Capture IRQ t time= (capture2 - capture1)x 12/f Figuur Principe van periodemeting via de capture mode van een timer 196

197 6.4.5 Controleregisters Voor de uitvoerige bespreking van de instellingen verwijzen we naar de XC888 user s manual. Hier staan enkel de namen van de bijhorende SFR s vermeld in figuur LET OP!! Figuur T2/T21 SFR s De SFR s van T2 en T21 hebben dezelfde adressen maar zitten in een verschillende RMAP (SYSCON0). In de regxc888.inc file zijn de namen uit de figuur voorafgegaan door t2_ of t21_ (t2_t2l of t21_t2l). 6.5 Capture/Compare Unit 6 (CCU6) Inleiding De CCU6module van de XC888 is een hardware unit die speciaal ontworpen is om complexe signalen te genereren. De tijdsbasis voor deze signalen is afkomstig van 2 timers, timer T12 en T13, waarbij T12 de hoofd timer is. T13 is vergelijkbaar met T2 maar kan enkel in de compare mode werken (indien een bepaalde waarde bereikt wordt, wordt er actie ondernomen). Beide timers zijn 16 bit groot. T12 stuurt 3 onafhankelijke kanalen aan, die elk in de capture of de compare mode gebruikt kunnen worden. Gelet op de hoge complexiteit en het scala aan mogelijkheden beperken we ons hier tot een principiële bespreking van de mogelijkheden. In figuur is het blokdiagram van de CCU6 opgenomen. Uit de figuur kan je afleiden dat T13 een ondersteunende functie heeft. T12 beschikt over 3 kanalen, waarbij elk kanaal een aantal uitgangsklemmen kan aansturen. De voornaamste toepassingen van CCU6 zijn PWM sturingen (figuur ). 197

198 Figuur Blokdiagram CCU PWM sturing Een Puls With Modulated signaal (figuur ) wordt voornamelijk gebruikt om een aan/uit sturing te kunnen bekomen voor een belasting. Door het PWM signaal te gebruiken om de transistor of de H-brug aan te sturen, wordt de motor verliesloos in snelheid geregeld. De transistor(en) zal (zullen) ofwel sperren (geen stroom voeren, en dus ook geen vermogen dissiperen) ofwel in verzadiging zijn (kleine spanningsval, en dus weinig dissipatie), waarbij P transistor =U transistor I transistor. Het PWM signaal wordt gekenmerkt door: resolutie frequentie De frequentie is het aantal PWM perioden per seconde. Is de frequentie te laag, dan zal het toerental (maar vooral het koppel) van de motor waarneembaar variëren. 198

199 De resolutie is een maat voor de minimale variatie in duty cycle van het PWM signaal. Omdat het signaal digitaal opgewekt wordt, wordt de resolutie uitgedrukt in een aantal bits. Is de resolutie 4 bit, dan kan de duty cycle met 1/16 van de PWM periode aangepast worden. In figuur wordt weergegeven hoe het PWM signaal opgewekt wordt. Amplitude / Gemiddelde waarde PWM periode tijd + 24V M PWM GND Figuur PWM motorsturing via een enkelvoudige transistor of H-brug. 199

200 klok 4 bit teller 4 bit comparator PWM out Compare waarde 4 bit teller compare waarde E D C B A PWM out tijd tijd Figuur PWM digitaal genereren In CCU6 wordt als PWM teller een 16 bit timer gebruikt. Hierdoor is de resolutie van de PWM 16 bit (1/65536). De CCU6 kan 4 (3 via T12 en 1 via T13) PWM signalen genereren in hardware. De CCU6 is vooral bedoeld om 3 fasige borstelloze DC motoren aan te sturen. Dit type motor kan best vergeleken worden met een 3 fasige AC motor met permanente magneet. Het toerental van de motor kan geregeld worden door een 3 fasig signaal met instelbare frequentie te maken. In dat geval is een schakeling nodig zoals in figuur Hierbij is het vooral belangrijk op te merken dat er een dode tijd moet zijn in het omschakelen van de transistoren. Anders worden kortsluitingen gemaakt. De CCU6 kan dergelijke signalen perfect opwekken. Bovendien is er een voorziening om voor de aansturing gebruik te maken van een HALL sensor. 200

201 Figuur Borstelloze DC motor De figuur laat ook zien dat het meten van de EMF signalen bijkomende info over de motor kan leveren. Deze metingen zijn maar zinvol wanneer de MOSFET s niet worden aangestuurd. De ADC van de XC888 kan gesynchroniseerd worden met de andere I/O (vandaar de complexe structuur van de ADC). 6.6 UART en UART Inleiding Een Universal Asynchronous Receiver and Transmitter Is een communicatiebouwsteen waarover zowat alle microcontrollers beschikken. Het systeem kan 1 byte verzenden of ontvangen volgens het frame format uit figuur Figuur Byte format UART 8 en 9 bit mode Voor de communicatie worden twee aansluitklemmen gebruikt: TxD voor de zender en RxD voor de ontvanger. 201

202 De communicatie verloopt asynchroon omdat er geen klok mee verzonden (ontvangen) wordt. De bittijd moet wel bij zender en ontvanger op dezelfde waarde ingesteld worden. Hiervoor wordt het begrip baud rate gehanteerd. De baud rate van een communicatie komt overeen met het aantal bit dat er per seconde verzonden (ontvangen) kan worden (inclusief start en stop bits). Het aantal databits is bij de 8051 compatibele microcontrollers steeds 8. De UART laat ook toe 9 bits te verzenden in de negen bit mode (NBM). De TB8 uit figuur is de negende bit, en wordt gebruikt om de interrupt overhead op een asynchroon netwerk te reduceren. De XC888 UART s laten ook toe dat de communicatie verloopt volgens het LIN protocol. Het byte format blijft hierbij hetzelfde, maar er wordt per boodschap een synchronisatie deel toegevoegd. Hierdoor kunnen zender en ontvanger hun baud rate beter op elkaar afstellen. Dit is vooral belangrijk wanneer er geen kristal als klok gebruikt wordt (vb. RC oscillator). De signalen die op de TxD en RxD pinnen verzonden/aangelegd worden zijn 0V en 5V. Omdat met deze spanningen geen grote afstanden kunnen overbrugd worden zijn level shifters noodzakelijk. In de figuren , , en zijn deeltjes van het XC888 SBC schema opgenomen met de beschikbare level shifters. De omvorming van UART naar USB is bovendien een protocol converter. Figuur UART RS232 level shifter 202

203 Figuur UART LIN level shifter Figuur UART RS485 level shifter 203

204 Figuur UART naar USB protocol omvorming De XC888 beschikt over 2 UART s (UART en UART1). Omdat ze identiek zijn aan elkaar wordt enkel UART besproken. De XC888 UART is compatibel met de UART s van alle andere 8051 controllers. Hij kan dan ook in 4 verschillende modes gebruikt worden (figuur ). Voor de verdere bespreking beperken we ons tot de meest gebruikte mode 1, 8 bit UART met variabele baud rate. De 9 bit UART komt overeen met de negen bit mode. Figuur UART modes Baud rate generator De XC888 laat toe om de baud rate te genereren via een unieke baud rate generator per kanaal (UART en UART1), of via timer 1. Die laatste mogelijkheid werd behouden uit historisch perspectief, maar wordt in de XC voor dit doel niet gebruikt. In figuur is het blokdiagram van de baud rate generator opgenomen. 204

205 Figuur Dedicated baud rate generator UART De baud rate wordt afgeleid van de systeemklok. Gelet op het gegeven dat de baud rate klok van zender en ontvanger best niet meer dan 2% afwijking mag hebben, kan de RC oscillator onvoldoende stabiel zijn (figuur ). Figuur Toleranties inwendige RC oscillator 205

206 De XC888 kan in dat geval best gebruikt worden met een extern kristal (figuur ). De XC888 SBC is uitgerust met een kristal van 12MHz. Figuur Extern kristal op XC888 SBC Voor de formules, en de registers die gebruikt worden bij het berekenen en instellen van de baud rate verwijzen we naar de XC888 User s Manual SFR registers UART De besturing van de UART gebeurt via 2 controleregisters SBUF (figuur ) en SCON (figuur ). Figuur UART data register Wanneer naar het SBUF register een byte geschreven wordt, start automatisch het verzenden van de byte (wanneer de UART geïnitialiseerd werd (zie 206

207 voorbeeldprogramma)). Wanneer de TI bit in SCON op 1 komt (aangestuurd door hardware) is de byte effectief verzonden. Er kan pas een nieuwe byte verzonden worden wanneer de TI bit door software op 0 werd gezet. Wanneer de RI bit in SCON op 1 komt (aangestuurd door hardware), dan werd een byte ontvangen, en kan in SBUF gelezen worden. RI moet ook door software op 0 gezet worden alvorens een nieuwe byte ontvangen kan worden. Het controleregister wordt gebruikt om de UART mode in te stellen via de SM0, SM1 en SM2 bits. Door de REN bit op 1 te zetten wordt de ontvanger ingeschakeld. Wordt de bit op 0 gezet, kunnen er geen bytes ontvangen worden. De zender is altijd actief. De bits TI en RI geven aan of een byte verzonden of ontvangen werd (worden in dat geval door hardware op 1 gezet). Deze bits moeten ALTIJD door software opnieuw laag gemaakt worden. Gebeurt dat niet, dan zal de UART niet langer in staat zijn bytes te verzenden of te ontvangen. De RI en TI bits zijn ook de interrupt pending bits (figuur ). Figuur TI en RI interrupt pending bits De TB8 en RB8 bits worden gebruikt om de negende bit die verzonden gaat worden, of die ontvangen werd op te slaan. Deze bits spelen alleen een rol in de negen bit mode van de UART. De UART kan ook gebruikt worden als een synchroon schuifregister. Deze mode laat toe om met standaard schuifregisters (74 reeks logica) poorten toe te voegen aan de controller. Omdat de SSC (zie paragraaf 6.7) en I 2 C interfaces meer mogelijkheden bieden, wordt de synchrone mode van de UART zelden gebruikt. 207

208 Figuur UART controle register 208

209 Voorbeeldprogramma initialisatie subroutine UART 9600 baud Het programma is een subroutine voor het instellen van de poortpinnen, zodat de UART functie naar buiten kan komen. Verder wordt de baud rate ingesteld op 9600 baud, en wordt UART mode 1 geselecteerd. De routine is zodanig geschreven dat het systeem niet verstoort wordt (syscon0, scu_page, en port_page registers worden hersteld in originele toestand) initsio: push acc ;registers op de stack zetten push syscon0 ;map bewaren mov syscon0,#004h ;hier zit al wat we nodig hebben push port_page ;pagina op stack zetten push scu_page mov scu_page,#000h ;pagina 0 system control regs ; eerst gaan we de pinnen van poort 1 juist zetten: ; -p1.0 als input en alt1 selectie ; -p1.1 als output en alt2 selectie mov port_page,#002h ;pagina 2 selecteren anl p1_altsel0,# b orl p1_altsel0,# b anl p1_altsel1,# b orl p1_altsel1,# b mov port_page,#000h ;pagina 0 selecteren anl p1_dir,# b ;p1.0=input orl p1_dir,# b ;p1.1=output ; Nu moet de baud rate generator ingesteld worden ; We gaan er van uit dat de systeemklok 24MHz is mov scon,# b ;UART initialiseren ; LET OP!!!!!!!!!!!!!! eerst BG laden, dan bcon, anders wordt BG waarde niet ; gebruikt!! mov bg,#155 ;zie in XC888 UM mov bcon,# b pop scu_page pop port_page ;alles terug herstellen pop syscon0 pop acc ret 209

210 Voorbeeldprogramma zenden 1 byte De routine moet geen rekening houden met mapping en paging omdat de registers steeds bereikbaar zijn! siooutchar: mov sbuf,a ;karakter verzenden siooutchar1: jnb ti,siooutchar1 ;wacht tot zender beschikbaar clr ti ;laag maken van de bit ret Voorbeeldprogramma ontvangen 1 byte De routine moet geen rekening houden met mapping en paging omdat de registers steeds bereikbaar zijn! sioinchar: jnb ri,sioinchar ;blijf wachten op het karakter clr ri ;bit laag maken mov a,sbuf ;karakter in de accu ret LIN interface De UART modules kunnen gebruikt worden om het Local Interconnect Network of LIN protocol (zowel master als slave werking) te ondersteunen (UART volledig, UART1 mits bijkomende software). In figuur is het LIN frame format opgenomen. Figuur LIN frame format LIN is een communicatiesysteem dat vooral in automotive toepassingen gebruikt wordt. Figuur geeft een overzicht van de andere automotive communicatiesystemen. Hieruit kan je afleiden dat de LIN bus voornamelijk een low cost/low speed communicatiesysteem is. 210

211 Figuur Vergelijking automotive communicatiesystemen De fysische interface (zie datasheet TJA1020) bestaat uit een 1 draad half duplex verbinding waarbij 0V een dominant - en 12V een recessief niveau is. De LIN bus gebruikt de traditionele asynchrone communicatie (zie werking UART). Het belangrijkste verschil is dat bij het verzenden van ELK frame de ontvanger automatisch de baud rate zal bepalen en aanpassen. Hierdoor vervalt de noodzaak om een kristal te gebruiken als klok voor de microcontroller (een kristal is mechanisch kwetsbaar en relatief duur). Door de data te verzenden in een pakket dat voorafgegaan wordt door een gestandaardiseerd break- en synchronisatie karakter, kan de ontvanger meten wat de exacte communicatiesnelheid is (de break duurt minimaal 13 bittijden en het synchronisatiekarakter is 55h). De controller biedt de mogelijkheid om T2 te gebruiken om te meten wat de inkomende baud rate is. De instellingen gebeuren via de controleregisters van de dedicated baud rate generator. 6.7 SSC Inleiding De High Speed Synchronous Serial Interface (SSC) is een synchroon serieel communicatiesysteem dat bij andere fabrikanten omschreven wordt met de naam SPI (Serial Peripheral Interface). In figuur zijn 3 devices op deze manier verbonden. In de figuur ontbreken de selectielijnen waarmee de master de slaves (devices 2 en 3) selecteert. Hiervoor worden gewone poortpinnen gebruikt die door software aangestuurd moeten worden. 211

212 Figuur SPI verbinding tussen master en slaves De communicatie gebeurt altijd per 8 bits. De master zal de 8 benodigde klokpulsen genereren die aangeven wanneer de 8 bits verzonden worden. Alleen de geselecteerde slave zal de data inlezen (op het ritme van de klok). Gelijktijdig zal (kan) het ontvangende device 8 bits terugsturen. De snelheid van de communicatie wordt ingesteld tussen de 183 baud en de 12 Mega baud Controleregisters Voor de gebruikte controleregisters verwijzen we naar de XC888 User s Manual. 212

213 6.8 CAN Inleiding Een Controller Area Network (CAN) is een communicatiesysteem dat, over een busverbinding, tegen 1megabit/seconde data kan overdragen tussen microcontrollers. Het systeem wordt vooral gebruikt in automotive netwerken. Het belangrijkste voordeel van het CAN systeem is dat het belangrijkste deel van het communicatieprotocol in hardware afgehandeld wordt (foutdetectie, her-transmissie, synchronisatie, ). CAN gebruikt geen adressen, maar identifiers om een boodschap te routen. Een identifier bestaat uit een 11- of 29 bit getal dat de aard van de boodschap omschrijft. Alleen de nodes die een boodschap van deze aard willen bekijken (instelbaar) zullen de boodschap ontvangen. De hardware meldt een geldige ontvangst via een statusregister en/of interrupt. De boodschap zelf wordt een message object genoemd en kan maximaal uit 8 bytes bestaan. De XC888 beschikt over 2 onafhankelijke CAN modules zodat 2 onafhankelijke CAN netwerken kunnen gebruikt worden. In figuur is een blokdiagram opgenomen van de CAN controller. Figuur Blokdiagram CAN controller XC

214 6.8.2 CAN SFR s Omdat de CAN controller over veel SFR s (tot bytes) moet kunnen beschikken is een speciaal systeem bedacht om met behulp van slechts 7 reële SFR s (DATA0-3, ADH, ADL en ADCON) de CAN controller aan te spreken. De registers DATA0, DATA1, DATA2 en DATA3 vormen een 32 bit databus, die gebruikt wordt om de gegevens van en naar de controller te verzenden. ADH en ADL zijn de registers die de adresbus vormen. Het ADCON register wordt gebruikt om de aard van de transactie vast te leggen. Voor een gedetailleerde beschrijving van de CAN controller verwijzen we naar de XC888 User s Manual. Uitgebreide informatie aangaande de CAN bus kan je terugvinden op volgende sites: Analoog naar digitaal omvormer (ADC) Inleiding De Analog to Digital Converter (ADC) is een unit die een analoge ingangsspanning kan omzetten naar een digitale getalwaarde. De analoge spanningen moeten aangelegd worden aan de klemmen van poort 2 (met de AGND als massapotentiaal). Het blokdiagram van de ADC is weergegeven in figuur Figuur Blokdiagram van de XC888 ADC Het analoge deel wordt met een externe referentiespanning verbonden (figuur laat een deel van het schema van de XC888 SBC zien). Via een jumper op de SBC kan gekozen worden tussen 4.096V of 5V. De waarde van de 214

215 referentiespanning bepaalt de maximaal meetbare waarde en kan nooit hoger zijn dan 5V of lager dan 1V. Een ingangsspanning (op klemmen poort 2) lager dan 0V, of hoger dan de voedingsspanning, mag niet aangelegd worden! De nauwkeurigheid van de referentie is ook een maat voor de nauwkeurigheid van het resultaat. Figuur Referentiespanning ADC De XC888 ADC kan, in tegenstelling tot andere controllers, zonder tussenkomst van de CPU een aantal acties uitvoeren. Dit heeft wel een grotere complexiteit van de ADC voor gevolg. De features van de XC888 ADC zijn opgenomen in volgende aandachtspunten, telkens voorzien van bijkomende uitleg. Successive approximation Integrated sample and hold circuitry De ADC werkt volgens het principe van opeenvolgende benaderingen (figuur ). 215

216 Figuur Successive approximation ADC Een Digitaal naar Analoog Convertor (DAC) wordt gebruikt om te raden wat de ingangsspanning is. Gedurende de omvorming moet het ingangssignaal constant gehouden worden. Dit wordt bekomen door de ADC te voorzien van een Sample & Hold (S&H) schakeling (figuur ). Bij de XC888 is die opgenomen in de ADC module, en wordt die automatisch aangestuurd. Figuur S&H schakeling 8-bit or 10-bit resolution De resolutie is de kleinste variatie in analoge ingangsspanning die door de ADC gemeten kan worden. Dit komt overeen met de spanningsvariatie die 216

217 nodig is om het digitale uitgangsresultaat met 1 te laten veranderen. Dit wordt berekend door het bereik van de ingangsspanning te delen door het aantal beschikbare schaaldelen: Als de 5 volt referentie gekozen is, dan is het ingangsbereik 0-5V. De ADC kan maximaal 10 bits gebruiken om de uitgangswaarde weer te geven (2 10 =1024 schaaldelen). Vullen we dat in de formule in, dan blijkt de kleinste meetbare spanningsverandering 0,004883V te zijn. Dit wordt 1 LSB genoemd. Wordt de 4,096V als referentie gekozen komt 1LSB overeen met 0,004V. Eight analog channels De 8 klemmen van poort 2 kunnen als ingang gebruikt worden. Four independent result registers De ADC kan meerdere kanalen automatisch bemonsteren en de resultaten beschikbaar stellen in afzonderlijke registers. Single conversion mode Autoscan functionality De gebruiker kan kiezen of een meting slechts 1 maal uitgevoerd moet worden, of dat er automatisch metingen moeten plaatsgrijpen. Limit checking for conversion results Het is mogelijk om automatisch te reageren wanneer een meting binnen bepaalde grenzen zit. Hierdoor hoeft de CPU niet permanent resultaten te toetsen. Data reduction filter (accumulation of up to 2 conversion results) De ADC kan automatisch 2 metingen bij elkaar optellen. Dit laat toe om een gemiddelde meting te bekomen. Flexible interrupt generation with configurable service nodes Er zijn meerdere mogelijkheden om vanuit de ADC een interrupt te genereren. Hierdoor wordt de CPU enkel onderbroken wanneer het absoluut nodig is. 217

218 Programmable sample time Programmable clock divider De ADC kloksystemen zijn instelbaar om een optimale afstemming te kunnen instellen tussen stroomverbruik, nauwkeurigheid en snelheid. De ADC unit heeft een maximale werkfrequentie van 10MHz! De ADC start op, na reset, in de laagste frequentie (24MHz/32=750kHz). Two independent conversion request sources with programmable priority De ADC beschikt over 2 units die een conversie kunnen starten (figuur ). De parallel request source en de sequential request source zijn twee arbitrage units die op een hardware manier bepalen welk event een ADC omvorming kan starten. Figuur ADC blokdiagram ADC instellingen en gebruik Voor een gedetailleerde beschrijving van alle mogelijkheden van de ADC wordt verwezen naar de XC888 User s Manual. We beperken ons hier tot een summiere beschrijving van de werking en instellingen. De ADC is speciaal ontworpen een omvorming te starten op verzoek van een andere hardware unit. De arbiter zal selecteren welk vragende unit aan de beurt komt om 218

219 een ADC omvorming te starten. De vraag kan komen via de parallel- of de serial request source. Per ingangskanaal kan er een uitgangsregister gekozen worden om het resultaat in op te slaan (maximaal 4 16 bit uitgangsregisters). Sequential request source is een systeem dat aanvragen tot conversie opslaat in de volgorde waarin ze toekomen (in een buffer). In die volgorde worden de vragen aangeboden aan de arbiter. Parallel request source is een systeem waarbij de aanvragen afgehandeld worden in de volgorde van hun kanaalnummer (eerst hoogste nummer). In deze request source kan ook een autoscanning mode gebruikt worden (beperkt aantal kanalen). De gebruiker kan via de ASEN0 en ASEN1 bits in PRAR bepalen welke request source gebruikt mag worden. De ADC voorziet in een scala van interrupt mogelijkheden (optreden van een event, vullen van een ADC register, voldoen aan grenswaarden van het resultaat, ). Een gedetailleerde beschrijving van de ADC en zijn werking is terug te vinden in de XC888 User s manual en AP van Infineon (Programming the Analog to Digital Converter on XC800 family of Microcontrollers). Voorbeeldprogramma ADC ; ; initadc is een subroutine die de adc klaar zet voor minimalistisch ; gebruik De routine zorgt er voor dat de potmeter en de lm335 als analoge inputs ; geschakeld worden. ; ; Gebruikt geen registers ; initadc: push syscon0 ;map saven mov syscon0,#004h ;basis pagina selecteren mov adc_page,#000h ;pagina 0 selecteren mov adc_globctr,# b ;adc inschakelen MUST!! ;klok delen door 32 (750kHz (max 10MHz) ;10 bit uitkomst mov adc_inpcr0,#00ah ;sample time verlengen met x klokpulsen ; Dit is niet echt nodig, maar hiermee vangen we de hoge impedantie van de potmeter op mov adc_prar,#080h ;arbitration slot parallelle arbitratie activeren ;MUST!! mov adc_page,#006h ;adc page 6 selecteren MUST!! mov adc_crmr1,#001h ;willen onmiddellijke actie MUST!! pop syscon0 ;herstellen syscon ret ; ; adclm335 is een subroutine die de spanning meet die van de lm335 sensor ; komt. De waarde wordt doorgegeven in a en b registers (kanaal 5). 219

220 ; ; Gebruikt: ; -accu als 8 msb meting ; -b als 2 lsb meting (links afgelijnd) (b bevat verder data van adc_resrxl) adclm335: push syscon0 mov syscon0,#004h ;map kiezen en vorige bewaren mov adc_page,#006h ;adc pagina 6 kiezen mov adc_crpr1,# b ;kanaal 5 starten mov adc_page,#000h ;naar pagina 0 schakelen adclm3351: mov a,adc_globstr ;kijken omvorming klaar jb acc.0,adclm3351 mov adc_page,#002h ;pagina 2 selecteren mov a,adc_resr0h ;uitkomst in accu mov b,adc_resr0l ;uitkomst in b pop syscon0 ret 6.10 MDU Inleiding De XC888 is uitgerust met een Multiplication and Division Unit (MDU). Dit is een hardware unit die in staat is berekeningen uit te voeren op getallen tot 32 bit. In figuur zijn de mogelijkheden van de MDU opgenomen. Figuur MDU mogelijkheden Werking en gebruik van de MDU De MDU bestaat voor de gebruiker uit een set van registers die geladen worden met de getallen waarop een berekening moet uitgevoerd worden. Via een controleregister 220

221 wordt aangegeven welke berekening men wil (MDUCON), en na een uitvoeringstijd zijn de resultaten beschikbaar in een set SFR s (figuur ). Figuur MDU timing In figuur zijn de SFR s afgebeeld die door de MDU gebruikt worden. LET OP! Figuur MDU SFR s De registers van de MDU zitten in SFR map 1. Die moet geselecteerd worden via SYSCON0. 221

222 Het einde van de berekening kan op 3 manieren bepaald worden: delay routine (max 32 cycles of 2,67µs) pollen van een busy bit (BSY bit in MDUSTAT) een interrupt genereren De MDx registers en de MRx registers zitten fysisch op dezelfde adressen. Bij het schrijven worden de MDx registers geadresseerd, bij het lezen de MRx registers. M.a.w. de MDx worden als input naar de MDU gebruikt, de MRx bevatten de resultaten (figuur ) Figuur MDU MDx en MRx registers XCEZ1 driver en MDU De XCEZ1.inc driver gebruikt de MDU NIET voor de wiskundige routines. Die zouden veel sneller uitgevoerd worden, mocht dat wel het geval zijn. Deze keuze werd opzettelijk gemaakt omdat de MDU niet onderbroken kan worden. Dit is belangrijk wanneer in het hoofdprogramma berekeningen gebeuren, terwijl een interruptroutine dit ook moet doen. De interruptroutine kan immers de MDU niet gebruiken zonder de resultaten van het hoofdprogramma verloren te laten gaan. 222

223 De beste optie is de XCEZ routines te gebruiken in het hoofdprogramma (tijd is hier niet belangrijk) en de MDU te gebruiken in interrupt routines CORDIC Inleiding Het CORDIC ( COordinate Rotation by DIgtal Computer) algorithme. CORDIC is een algoritme om langs het gebruik van elementaire basisbewerkingen, functies te bepalen zoals oa. SIN, COS, TAN, ATAN, en dit op een iteratieve manier waarbij men bij elke iteratiestap 1 bit aan precisie wint. De elementaire bewerkingen zijn optel- en schuifbewerkingen, die op een eenvoudige processor of op digitale hardware kunnen worden uitgevoerd. CORDIC werkt door het coördinatenstelsel van een vector te roteren over een gevraagde hoek. Dit rotatieproces gebeurt iteratief met constante en vooraf bepaalde hoeken, en stopt wanneer het hoekverschil tussen de geroteerde en de ingestelde hoek klein genoeg is geworden. Dit hangt af van de benodigde nauwkeurigheid en dus het benodigde aantal bits van het resultaat. Deze vooraf bepaalde hoeken uit het iteratieproces worden in een kleine Look-Up- Table (LUT) opgenomen in het systeem. Tijdens dit iteratieproces zullen ook de projecties van de vector op de X-as en de Y- as stelselmatig gecumuleerd worden en zo een benadering van de SIN en de COS van de geroteerde hoek opleveren. Één en ander wordt verduidelijkt in de volgende paragrafen. De voordelen van CORDIC zijn: Er zijn géén Floating Point (FP) berekeningen en Taylor reeksontwikkelingen nodig om deze trigoniometrische (en andere) functies te berekenen. De combinatie van reeksontwikkelingen én FP bewerkingen, hebben het nadeel erg traag te verlopen op eenvoudige processoren. Er zijn géén grote LUT s nodig, die wel nodig zijn in het geval de functiewaarden via een loop-up algorithme worden bepaald. Voor de praktische implicaties verwijzen we naar de XC888 User s manual en de application notes op de website van Infineon. 223

224 CORDIC werking in de rotation mode. A) Vectorrotatie over een hoek. Y y1 P 1 x1, y1 y P x, y 0 Figuur vectorrotatie over een hoek Als een vector P ( x, y) over een hoek wordt geroteerd in een X,Y assenstelsel dan kan de nieuwe geroteerde vector P1 ( x1, y1) als volgt worden berekend: x Pcos en y Psin (1) x 1 Pcos( ) en y 1 Psin( ) (2) Er kan bewezen worden dat: cos( ) cos cos sin sin (3) sin( ) sin cos cos sin (4) De vergelijkingen (2) worden dan: x 1 P cos cos P sin sin y 1 P sin cos P cos sin (5) Hierin kunnen we dan (1) substitueren, dit geeft: x 1 x cos y sin y 1 y cos x sin x sin y cos (6) Dit zijn de formules voor het bepalen van de coördinaten bij een eenvoudige vectorrotatie. Maar hoe kan een vectorrotatie ons nu helpen voor het bepalen van bv. SIN en COS functies? B) Rotatie van de eenheidsvector over een hoek. Laten we als startvector een eenheidsvector ( 1,0) nemen die samenvalt met de X-as. x1 x X 224

225 Als we deze vector over een hoek roteren geeft dit volgende coördinaten in ons X,Y stelsel. x 1 cos en y 1 sin (7) Y P x1, y1 y1 sin 0 x1 cos 1,0 Figuur Rotatie van een eenheidsvector over een hoek. X C) Opdeling van de hoek in en aantal (getabuleerde) subhoeken. We kunnen de hoek iteratief proberen te bereiken door een soort van successive approximation toe te passen op de hoek, door er steeds kleinere subhoeken (uit de LUT) bij te tellen of af te trekken. Na elke rotatie over een subhoek kunnen we de nieuwe x,y coördinaten bepalen uitgaande van de vorige x,y coördinaten volgens de formules (6) van de vectorrotatie. Y x nieuw x vorig cos( subhoek ) y vorig sin( subhoek ) y1 y3 y4 y y nieuw y vorig cos( subhoek ) x vorig sin( subhoek ) 3 1 1,0 0 x1 x3 x4 x2 X Figuur Iteratieve procedure voor het roteren van een eenheidsvector D) De iteratie procedure. De iteratieve procedure voor het roteren van een eenheidsvector over een hoek ziet er dan als volgt uit: x( i 1) x( i) cos( ( i) ) y( i) sin( ( i) ) y( i 1) y( i) cos( ( i) ) x( i) sin( ( i) ) (8) 225

226 Om de vordering in het iteratieproces bij te houden introduceren we een nieuwe variabele z, die de totale gecumuleerde hoek voorstelt: z is m.a.w. de hoekaccumulator. z( i 1) z( i) ( i) (9) Laten we dit iteratieproces illustreren a.d.h.v. een voorbeeld met 10 iteraties gebruik makend van volgende LUT. i (i) 45 26,6 14,0 7,1 3,6 1,8 0,9 0,4 0,2 0,1 in Tabel1:LUT met subhoeken voor het iteratieve rotatieproces. Om de eenheidsvector (1,0) over een hoek van bv. 30 te roteren via 10 iteraties moeten we volgend schema van hoekrotaties volgen voor een beste benadering: ,6 +14,0-7,1 +3,6 +1,8-0,9 +0,4-0,2 +0,1 =30,1 30 Uiteraard kunnen we na elke stap ook de x en de y waarden berekenen (8) om uiteindelijk te komen tot de benaderende SIN en COS (7) van de geroteerde hoek. Dit levert ons tot nu geen enkel voordeel op, immers om de benaderende SIN en COS van de totaal geroteerde hoek te berekenen hebben we na elke iteratie ook een SIN en COS functie nodig! Om dit probleem op te lossen voeren we een aantal vereenvoudigingen in. E) Vereenvoudigingen voor de hardware-implementatie. 1) Vereenvoudiging door afzonderen van de cos( (i) ) factor. Om de uitvoering van het algorithme op een standaard processor te vereenvoudigen, gaan we de vergelijkingen (8) herschrijven en de cos( (i) ) factor afzonderen. Dit geeft: x( i 1) x( i) cos( ( i) ) y( i) sin( ( i) ) x( i 1) cos( ( i) ) ( x( i) y( i) tan( ( i) )) y( i 1) y( i) cos( ( i) ) x( i) sin( ( i) ) y( i 1) cos( ( i) ) ( y( i) x( i) tan( ( i) )) (10) Deze cos( (i) ) factoren zijn constanten K (i) voor de vaste subhoeken uit de LUT. Het is onbelangrijk of de subhoek in het iteratieproces nu moet worden opgeteld of afgetrokken van de gecumuleerde hoek z ( i 1), immers cos( (i) ) = cos( (i )). Dit alles heeft als consequentie dat we het product van al deze constanten, nodig in het interactieproces, op voorhand kunnen berekenen. 226

227 K K i (11) ( ) n We kunnen K dus berekenen voor het nodige aantal iteraties in onze toepassing, de precisie van dit product zal toenemen naarmate we meer iteratiestappen toepassen. We kunnen het aantal iteratiestappen beperken en dus ook dit product trunceren in functie van het aantal benodigde bits. 2) Vereenvoudiging door de oordeelkundige keuze van de subhoeken (i). Om de berekeningen nu mogelijk te maken op een standaard processor (of digitale hardware) gaat men de subhoeken kiezen zodat ze voldoen aan: tan( ) 1 2 ( i ) d i met i i subhoek. d = -1 voor het optellen of +1 voor het aftrekken van de Dit geeft aan dat de subhoeken zodanig worden gekozen dat de TAN van de subhoek steeds een breuk is van een macht van 2. Immers, ,,,,,, voor i 0,1,2,3,4,, 10 i Merk op dat deze delingen door machten van 2 heel eenvoudig kunnen worden uitgevoerd door shift instructies op een processor. De hoeken (i) die hiermee overeenkomen zijn dan gelijk aan: 1 ( i) arctan( ) en deze kunnen vooraf worden berekend en in een LUT i 2 opgeslagen. We kunnen de vergelijkingen (10) dus in een andere en eenvoudiger vorm herschrijven: 1 x( i 1) K( i) ( x( i) di y( i) ) met K i (i) = cos( (i) ) (12) 2 1 y( i 1) K( i) ( y( i) di x( i) ) met d i i als rotatie richtingsvariabele 2 z z d ( i 1) ( i) i ( i) 1 1 Het grote voordeel van deze vergelijkingen is dat de termen y( i) en x i ( i ) op i 2 2 een standaard processor door shift instructies kunnen worden bepaald, wat zeer snel kan gebeuren. Met deze iteratieve vergelijkingen (12) kunnen we een algoritme ontwikkelen dat de gegeven starthoek, die wordt opgegeven in de hoekaccumulator z, iteratief reduceert tot nul ( d i = -1 subhoek optellen of +1 subhoek aftrekken). 227

228 Bij elke iteratiestap wordt ook bij de x en de y coördinaten de benodigde waarde (de verschoven vorige x en y waarden) bijgeteld of afgetrokken zodat de nieuwe coördinaten worden bijgehouden doorheen de rotatie. Met de factoren K (i) houden we tijdens het iteratieproces geen rekening, we brengen ze pas na het totale iteratieproces in rekening als factor K volgens (11). Na n iteraties zijn de x en y waarden respectievelijk benaderingen voor de cos en de sin met een gainfactor 1 (ten gevolge van het weglaten van de K (i) factoren) die we dus nog moeten K compenseren door de resultaten in x en y nog te vermenigvuldigen met de K factor (11) die in tabel 2 wordt berekend. i 1 i (i ) in (i) in rad cos( (i) ) of K (i) , , , /2 26, , , /4 14, , , /8 7, , , /16 3, , , /32 1, , , /64 0, , , /128 0, , , /256 0, , , /512 0, , , /1024 0, , ,00000 K K( i ) n K= Tabel2: K K( i ) berekening n Een programmaflow voor dit algorithme wordt in figuur gegeven. 228

229 START i 0 Initialisatie: n, z, y 0, x K nee i n? dx x i 2 dy y i 2 dz (i) ja END ja z 0? nee x x dy y y dx z z dz x x dy y y dx z z dz i i 1 Figuur Programmaflow voor het iteratief rotatieproces Startwaarden van x, y en z voor het bepalen van x cos en y sin. Y y1 sin 0 x1 cos Hiervoor nemen we als startwaarden: Er is convergentie als de starthoek (K,0) Figuur Rotation mode X z, x K 1 en y 0 met K=0, (0) ( 0) z ligt tussen: (0) ( 0) ) A z( 0 A met A rad (90 ) 2 Waarbij A de som is van alle vooraf bepaalde en in de LUT opgeslagen subhoeken: 229

230 1 A arctan( ) of A ( ) i ( i) 2 n n Buiten dit bereik moet men de regels van de trigoniometrie toepassen, bv. cos( ) cos of bv. sin( ) sin. 2 Deze manier van werken waar de men de rotation mode van CORDIC. z iteratief naar 0 wordt gereduceerd noemt (0) CORDIC kan ook op een andere manier gebruikt worden nl. de vector mode, deze iteratiemethode wordt besproken in het volgende deel CORDIC werking in vector mode (Omzetting van carthesische coördinaten naar poolcoördinaten). Y r sin y 0 x r cos X Figuur Vector mode Bij deze manier van werken zal CORDIC de omzetting maken van een vector gegeven door zijn carthesische coördinaten ( x r cos en y r sin ) naar een weergave in poolcoördinaten (r en ). In deze mode zal de inputvector (x,y) geroteerd worden totdat hij samenvalt met de X-as. De resultaten van deze bewerking zijn dan de rotatiehoek, dit is de z component van het resultaat, en de (geschaalde) lengte r van de vector. Dit is de x component van het resultaat. De vector mode werkt door via iteratie de y (0) component van de vector te reduceren naar nul door opeenvolgende rotaties over vaste subhoeken. Het teken van de y (i) component wordt hierbij gebruikt om de richting van de volgende rotatie te bepalen. 230

231 Door in dit geval de hoekaccumulator met nul te initialiseren z 0, zal z na het ( 0) iteratieproces de benaderende waarde van de doorlopen hoek bevatten. De iteratie vergelijkingen zijn hier eveneens: 1 x( i 1) K( i) ( x( i) di y( i) ) met K i (i) = cos( (i) ) (12) 2 1 y( i 1) K( i) ( y( i) di x( i) ) i 2 z z d ( i 1) ( i) i ( i) Hier zal nu de variabele d i =+1 zijn als y 0 en d i =-1 in het andere geval. Na n itteraties krijgen we dan: x 2 2 ( n) An x(0) y(0) ( i) en y 0 (vector mode) ( n) x n stelt dus de geschaalde lengte voor van de startvector (Pythagoras). Waarbij kan bewezen worden dat de schaalfactor A n gelijk is aan: 1 ( ) 1 i =1,64675 (zie tabel 3 ) n 2 y(0) y(0) z(0) arctan( ) met arctan( ) en meestal is z ( 0) 0. x x An A i 2 n z( n ) (0) (0) i A 1, , , , , , , , ,00001 (i) Tabel 3: De schaalfactoren in vector mode voor de verschillende itteratiestappen. y(0) In vector mode kunnen we dus iteratief de arctan( ) x we de absolute waarde van de inputvector. (0) berekenen en tegelijk krijgen 231

232 A) Bepaling van ARCSIN via CORDIC. Y Inputwaarde C ,0 Figuur Iteratie naar de y-inputwaarde De boogsinus (ARCSIN) kan worden berekend vertrekkend van de eenheidsvector op de positieve X-as. Door de vector zodanig te roteren dat zijn y-component gelijk wordt aan de inputwaarde vinden we de overeenkomende hoek. Deze hoek is de ASIN van het inputargument. De beslissingsvariabele d i is in dit geval het resultaat van de vergelijking tussen de inputwaarde en de y (i) component van de geroteerde vector na elke iteratie. Ook hier gelden de iteratie vergelijkingen: 1 x( i 1) K( i) ( x( i) di y( i) ) met K i (i) = cos( (i) ) (12) 2 1 y( i 1) K( i) ( y( i) di x( i) ) i 2 z z d ( i 1) ( i) i ( i) Hierbij is d i 1 wanneer y( i ) C inputwaard e en d i 1 in het andere geval. Na rotatie via n iteratiestappen krijgen we als resultaat: x n y n z n A x ( C met n 0) C inputwaarde z ( 0) arcsin A n C x (0) An A( i ) 2 n n X 1 =1,64675 (zie tabel 3 ) i 2 Indien het iteratieproces start met z 0 en A n x ( 1 vinden we dus als zn de arcsin C. ( 0) 0) 232

233 CORDIC geeft een correcte waarde van voor inputwaarden van C die voldoen C aan: 1 1 A x n (0) De nauwkeurigheid neemt echter wel af voor een hoek die dicht bij de Y-as ligt, dus voor inputs dicht bij 1. De fout is significant voor inputwaarden groter dan 0,98. B) Bepaling van ARCCOS via CORDIC. De boogcosinus (ARCCOS) kan op gelijkaardige manier worden bepaald, alleen wordt nu het verschil tussen de x-component en de inputwaarde als beslissingsfunctie gebruikt. Het algoritme werkt echter alleen voor inputs kleiner dan 1. A n De ARCCOS kan dan ook beter worden berekend door gebruik te maken van de ARCSIN functie door van het resultaat af te trekken, gevolgd door een 2 hoekreductie als het resultaat in het 4 e kwadrant ligt Uitbreiding van CORDIC naar lineaire en hyperbolische functies. Y m x y 1 m 0 m x y 1 y x 1 X Figuur Verschillende modes van CORDIC 233

234 De CORDIC vergelijkingen die we tot nu gebruikten kunnen aangepast worden tot een meer algemene vorm. Dit door het invoeren van een bijkomende variabele m, de mode variabele. De factor m controleert de vectorrotatie en bepaalt ook de te gebruiken LUT met opgeslagen subhoeken voor circulaire, lineaire en hyperbolische functies. Deze mode variabele m kan de waarde +1 hebben, dit voor de gevallen in een circulair coördinatenstelsel die we tot nu toe illustreerden. De variabele m kan ook de waarde 0 hebben, wat toelaat om lineaire functies te berekenen. Tenslotte kan de variabele m ook de waarde -1 hebben, voor het bepalen van hyperbolische coördinatentransformaties. De algemene CORDIC vergelijkingen zien er, zonder rekening te houden met de constante factor K (i), als volgt uit: 1 x( i 1) x( i) m di y( i) i 2 (13) 1 y( i 1) y( i) di x( i) i 2 met d i als rotatie richtingsvariabele En 1 z( i 1) z( i) di arctan( ) i 2 voor m=1 (circulaire mode) 1 z( i 1) z( i) di i 2 voor m=0 (lineaire mode) 1 z( i 1) z( i) di arctan h( ) i 2 voor m=-1 (hyperbolische mode) Merk op dat er voor de hoekaccumulator z in de drie gevallen een andere functie staat, wat dus ook het gebruik van andere LUT s veronderstelt. A) Berekening van lineaire functies met CORDIC (m=0). In dit geval herleiden de CORDIC iteratievergelijkingen zich tot: x( i 1) x( i) (14) 1 y( i 1) y( i) di x( i) i 2 met d i als rotatierichtingsvariabele 1 z( i 1) z( i) di i 2 voor m=0 (lineaire mode) We kunnen met deze vergelijkingen werken in de rotation mode en dus de initiële waarde van de hoekaccumulator z naar nul reduceren via het reeds aangegeven iteratieproces. 234

235 Merk op dat de x waarde steeds gelijk blijft aan de initiële waarde x (0) en dat we dus werken op een vertikale rechte (lineair) door het punt x (0). Hierbij is de beslissingsvariabele d 1 als z 0 en d 1 in het andere geval. i ( i) De lineaire rotatie geeft dan volgende resultaten na n iteraties: i x n y n z n 0 x (0) y( 0) z(0) x(0) De werking is vergelijkbaar met de shift/add implementatie van een vermenigvuldiger en is dus niet zo n optimale oplossing. Wanneer we werken in vector mode en dus de waarde van y naar nul reduceren in het iteratieproces kunnen we via deze methode verhoudingen (delingen) berekenen. Hierbij is de beslissingsvariabele d 1 als y 0 en d 1 in het andere geval. Het resultaat na n iteraties is: i ( i) i x n y 0 x (0) n z n z (0) y x (0) (0) De rotaties in het lineaire coördinatenstelsel hebben een schaalfactor van 1, er is dus geen bijkomende correctiefactor meer nodig na het iteratieproces. B) Berekening van hyperbolische functies met CORDIC (m=-1). 235

236 Y 1 x 2 y cosh sinh 1 sinh cosh 1 X Figuur Hyperbolische functies. De CORDIC vergelijkingen voor hyperbolische functies zien er als volgt uit: 1 x( i 1) x( i) d i y( i) i 2 (13) 1 y( i 1) y( i) di x( i) i 2 met d i als rotatierichtingsvariabele 1 z( i 1) z( i) di arctan h( ) i 2 In de rotation mode is de beslissingsvariabele d 1 als z 0 en d 1 in i ( i) het andere geval. Na een iteratieve reductie van de hoekaccumulator z tot nul geeft dit als resultaat: i x y n n z n A x cosh z y z met n A 0 n y ( 0) (0) (0) sinh ( 0) cosh z (0) x (0) sinh z (0) (0) An A( i ) 2 n n 1 1 0,8 i 2 Voor een initiële waarde x 0, y 1 en z geeft dit als resultaat: ( 0) x A sinh en y A cosh n n n n ( 0) (0) 236

237 sinh Hieruit kan dan ook tanh θ = worden bepaald. cosh In de vector mode waar de initiële y (0) waarde naar nul wordt gereduceerd is de beslissingsvariabele d 1 als y 0 en d 1 in het andere geval. Dit geeft na iteratie: x n y n i ( i) An x ( 0) y(0) met An A( i ) 1 2i 0,8 n n 2 0 y (0) y (0) z n z ( 0) arctan h waarbij arctan h x (0) x(0) in het hyperbolisch coördinatenstelsel. De iteratieve rotaties in het hyperbolische coördinatensysteem convergeren echter niet. Het kan echter bewezen worden [1,Walther] dat convergentie kan bekomen worden als bepaalde iteraties ( i=4, 13, 40,,k, 3k+1) herhaald worden. De hyperbolische equivalenten van alle functies uit het circulaire coördinatenstelsel kunnen berekend worden. Bijkomend kan worden aangetoond [1, Walther] dat volgende functies kunnen worden afgeleid van de CORDIC functies. y ln 2 arctan h met x 1 en y 1 x = x y met x en y 4 4 i Referenties. [1] J.S. Walther, A Unified Algorthm for elementary functions, Joint Computer Conference Proceedings v.38 Spring 1971, [2] J. Volder, The CORDIC Computing Technique, IRE Trans. Computers, v.ec-8 (september 1959), [3] Ray Anchaka, A survey of CORDIC algorithms for FPGA based computers. [4] Oliver Sinnen, Reconfigurable computing CORDIC algorithms Univ. of Auckland (presentation) [5] Sin Hitotumatu, Complex Arithmatic through CORDIC. Kodaï Math. Sem. Rep. 26 (1975) [6] Daniel R. Llamocca-Obregón & Carla P. Agurto-Rios, A fixed point implementation of the expanded hyperbolic CORDIC algorithm. [7] Ken Turkowski, Fixed point trigonometry with CORDIC itterations, Apple Computer Jan. 17, [8] Neil Eklund, CORDIC: Elementary Function Computation using Recursive Sequences. 237

238 ;************************************************************************************** ; Demoprogramma voor het gebruik van de CORDIC ; ; XC_sincos : Deze routine berekent de sinus en de cosinus van de in r1,r0 als ;integer opgegeven hoek. De hoek (in rad.) staat in 2compl. formaat en moet ;vermenigvuldigd worden met een schaalfactor 32768/pi. ; Het hoekbereik gaat van pi/2 tot -pi/2. ; Dwz. een hoek van pi/2 wordt gegeven als (4000h) en ; -pi/2 als (c000h) ; ; De return parameters zijn de sinus en cosinus van de opgegeven hoek die ook als ; geschaalde 2compl. getallen ter beschikking komen. ; Het bereik is hier: -1 (8000h) tot +1 (7fffh) dus 15 bit + teken (msb). ; INPUT= r1(msb),r0 => hoek (in rad) * 32768/pi ; OUTPUT SIN= r4,r5 (scaled) ; OUTPUT COS= r6,r7 (scaled) ; ;Deze routine gebruikt de r4,r5,r6,r7 registers ;************************************************************************************** XC_sincos: push acc push psw push syscon0 ;cordic instellen mov syscon0,#005h ;RMAP1 mov cd_statc,#000h mov cd_con,#00ah ;Circ. rotatie mode, MPS magnitude prescaler=1 mov cd_cordyl,#000h ;Y=0 mov cd_cordyh,#000h ;Y=0 mov cd_cordxh,#4dh ;X=32767/ =19898 = 4dbah (K= ) ;input hoek Z in scaled radians mov cd_cordzh,r1 ;bv. 90graden=16384 of 4000h mov cd_cordzl,r0 ;start Cordic mov cd_cordxl,#0bah ;X low byte schrijven start Cordic. jnb eoc,$ ;wachten tot cordic klaar is ;sinus laden mov r4,cd_cordyh mov r5,cd_cordyl ;cosinus laden mov r6,cd_cordxh mov r7,cd_cordxl pop syscon0 pop psw pop acc ret 238

239 6.12 WDT Inleiding Een WatchDog Timer (WDT) is een systeem dat het programmaverloop bewaakt (in mindere mate ook hardware). De WDT werkt als een keukenwekker. Die wordt ingesteld op een bepaalde tijd. Als de software de timer binnen dit tijdbestek niet reset, zal de timer aflopen en een hardware reset genereren. Een watchdog is geen garantie dat er altijd een herstart van een vastgelopen programma is. Wanneer het resetten van de watchdog vanuit een interrupt routine gebeurt is de kans groot dat een vastgelopen hoofdprogramma niet gedetecteerd wordt SFR s en instellingen watchdog In figuur is het blokdiagram van de WDT opgenomen. Figuur Blokdiagram WDT De WDT werkt op een instelbare klok van f PCLK (standaard 24MHz) gedeeld door 2 of door 128. DE WDT zelf is een 16 bit timer, waarvan de 8 hoogste bits gebruikt kunnen worden om de time out in te stellen. De timer telt omhoog en zal bij een overflow het systeem resetten. Door vòòr de overflow een reload van de hoogste 8 bit af te dwingen (refresh van de WDT) wordt dit voorkomen. Er bestaat ook de mogelijkheid om een dode zone in te stellen waarbinnen een refresh onmogelijk is (figuur ) 239

240 De periode waarbinnen de WDT gerefreshed moet worden kan berekend worden via onderstaande formule: Figuur WDT timing diagram Voor een gedetailleerde beschrijving van de SFR s verwijzen we naar de XC888 User s manual. LET OP!! Bepaalde bits in de SFR s die de WDT besturen zijn beschermd! Je moet een speciale procedure volgen alvorens je de inhoud van deze bits/registers kan aanpassen. 240

241 6.13 OCDS inleiding De On Chip Debug Support (OCDS) is een combinatie van ROM software en bijkomende hardware. Het systeem laat toe om het debuggen van een programma te vereenvoudigen. Single stepping en breakpoints zijn de belangrijkste technieken. Single stepping laat toe dat het programma na elke instructie gestopt wordt, zodat nagegaan kan worden wat de inhoud van de CPU registers is. Bij een breekpunt wordt het programmaverloop gestopt wanneer een bepaalde locatie (adres) in het geheugen bereikt wordt. Helaas kunnen worden deze features minimaal gedocumenteerd, en zijn ze enkel bruikbaar via een JATG interface ROM floating point routines Inleiding De XC888 is uitgerust met een ROM geheugen dat door de fabrikant voorzien is van firmware. De ROM bevat routines voor het programmeren van de FLASH (bootloader en IAP routines), maar ook subroutines die gebruikt kunnen worden voor floating point berekeningen. De software werd geschreven door KEIL (ARM company). Informatie over de routines is dan ook enkel via hun site beschikbaar ( ). De werking van de routines wordt niet door Infineon (fabrikant van de XC888) gegarandeerd of gedocumenteerd! Rom routines en hun gebruik In de ROM van de XC888 zitten subroutines die toelaten om wiskundige berekeningen uit te voeren. Onderstaande tekst legt uit hoe de routines aangesproken worden. 241

242 ;************************************************************************************** ; Gebruik van de in het ROM geheugen van de XC888 opgeslagen rekenkundige ; library routines van de firma Keil Elektronik GmbH. Deze mogen vrij gebruikt ; worden in eigen toepassingen. ; Deze routines zitten op een basisadres "baseadr" dat afhankelijk is van de versie ; van XC888 chip: XC888 step AA : baseadr=0e800h ; XC888 step AB : baseadr=0e734h ; Dit basisadres moet door de gebruiker zelf worden gecontroleerd. ; ; Keil ROM Library Routine Overview ; ================================= ; Integer operations. ; =================== ; XC_imul: int multiply 16int x 16int =16int prod ; XC_uidiv: unsigned int divide/modulo 16int / 16int =16int quot+16 rest ; XC_lmul: signed/unsigned long multiply 32int x 32int =32int prod ; XC_uldiv: unsigned long divide/modulo 32int / 32int =32int quot+32 rest ; XC_lneg: signed long negate 32int = -32int ; XC_ulshr: unsigned long shift right 32word >> invoeging 0 ; XC_slshr: signed long shift right 32long >>invoeging msb ; XC_lshl: signed/unsigned long shift left 32word/long <<invoeging 0 ; ; IEEE 754 Floating point operations. ; =================================== ; XC_fpadd: float addition ; XC_fpsub: float subtract ; XC_fpmul: float multipy ; XC_fpdiv: float divide ; XC_fpcmp: float compare with generic fuzzy setting ; XC_fpcmp3: float compare with 3-bit fuzzy setting ; XC_suc2f: type cast: signed/unsigned char to float ; XC_sui2f: type cast: signed/unsigned int to float ; XC_sul2f: type cast: signed/unsigned long to float ; XC_f2sucil: type cast: float to signed/unsigned char/int/long ; ; Een lijst van veel gebruikte constanten in IEEE754 floating point formaat: ; ================================================================ ; =37 27 C5 AC =47 C ; =38 D1 B =46 1C = ; =3A F 1000=44 7A =45 9C ; 0.01 =3C 23 C7 0A 100=42 C = ; 0.1 =3D CC CC CD 10= = ; 0.5 =3F =3F = ; 5.0 =40 A = = ; WORTEL2=3F B5 04 F3 PI= F DB PI/2=3F C9 0F D8 ; 3PI/2 =40 96 CB E4 2PI=40 C9 0F DA 32768/PI=46 22 F9 83 ;PI/32768=38 C9 0F DB 1RAD= E E6 DEG 1DEG=3C 8E FA 34 RAD ; -1.0 =BF ;************************************************************************************** 242

243 ;************************************************************************************** ; ; XC_imul: int multiply ; ======================= ; Input: R6 R7 = value1, R4 R5 = value2 (MSB LSB) ; Return: R6 R7 = value1 * value2 ; Use Registers: R0 ; ;************************************************************************************** XC_imul: push acc ;?C?IMUL CODE (BASEADR + 0x015C) push psw push b lcall Baseadr+015ch ;int multiply pop b pop psw pop acc ret ;************************************************************************************** ; ; XC_uidiv: unsigned int divide/modulo ; ===================================== ; Input: R6 R7 = value1, R4 R5 = value2 ; Return: R6 R7 = value1 / value2, R4 R5 = value1 % value2 ; Use Registers: R0 ; ;************************************************************************************** XC_uidiv: push acc ;?C?UIDIV CODE (BASEADR + 0x016E) push psw push b lcall Baseadr+016eh ; unsigned int divide/modulo pop b pop psw pop acc ret ;************************************************************************************** ; ; XC_lmul: signed/unsigned long multiply ; ======================================== ; Input: R4 R5 R6 R7 = value1, R0 R1 R2 R3 = value2 ; Return: R4 R5 R6 R7 = value1 * value2 ; Use Registers: R0 ; ;************************************************************************************** XC_lmul: push acc ;?C?LMUL CODE (BASEADR + 0x01C3) push psw push b lcall Baseadr+01c3h ; signed/unsigned long multiply pop b 243

244 pop psw pop acc ret ;************************************************************************************** ; ; XC_uldiv: unsigned long divide/modulo ; ====================================== ; Input: R4 R5 R6 R7 = value1, R0 R1 R2 R3 = value2 ; Return: R4 R5 R6 R7 = value1 / value2, R0 R1 R2 R3 = value1 % value2 ; Use Registers: none ; ;************************************************************************************** XC_uldiv: push acc ;?C?ULDIV CODE (BASEADR + 0x024E) push psw push b push dpl lcall Baseadr+024eh ; unsigned long divide/modulo pop dpl pop b pop psw pop acc ret ;************************************************************************************** ; ; XC_lneg: signed long negate ; ============================= ; Input: R4 R5 R6 R7 = value1, ; Return: R4 R5 R6 R7 = -value1 ; Use Registers: none ; ;************************************************************************************** XC_lneg: push acc ;?C?LNEG CODE (BASEADR + 0x02E0) push psw lcall Baseadr+02e0h ; signed long negate pop psw pop acc ret ;************************************************************************************** ; ; XC_ulshr: unsigned long shift right ; ==================================== ; Input: R4 R5 R6 R7 = value, R0 = shift_cnt ; Return: R4 R5 R6 R7 = value1 >> shift_cnt ; Use Registers: R0 ; ;************************************************************************************** XC_ulshr: push acc ;?C?ULSHR CODE (BASEADR + 0x02EE) push psw lcall Baseadr+02eeh ;unsigned long shift right 244

245 pop psw pop acc ret ;************************************************************************************** ; ; XC_slshr: signed long shift right ; ================================== ; Input: R4 R5 R6 R7 = value, R0 = shift_cnt ; Return: R4 R5 R6 R7 = value1 >> shift_cnt ; Use Registers: R0 ; ;************************************************************************************** XC_slshr: push acc ;?C?SLSHR CODE (BASEADR + 0x0301) push psw lcall Baseadr+0301h ;signed long shift right pop psw pop acc ret ;************************************************************************************** ; ; XC_lshl: signed/unsigned long shift left ; ========================================== ; Input: R4 R5 R6 R7 = value, R0 = shift_cnt ; Return: R4 R5 R6 R7 = value1 << shift_cnt ; Use Registers: R0 ; ;************************************************************************************** XC_lshl: push acc ;?C?LSHL CODE (BASEADR + 0x0315) push psw lcall Baseadr+0315h ;signed/unsigned long shift left pop psw pop acc ret ;************************************************************************************** ; ; XC_fpadd: float addition ; ========================= ; Input: R4 R5 R6 R7 = value1, R0 R1 R2 R3 = value2 ; Return: R4 R5 R6 R7 = value1 + value2 ; Use Registers: R0, R1, R2, R3 ; ;************************************************************************************** XC_fpadd: push acc ;?C?FPADD CODE (BASEADR + 0x032F) push psw push b lcall Baseadr+032fh ; float addition pop b pop psw 245

246 pop acc ret ;************************************************************************************** ; ; XC_fpsub: float subtract ; ========================= ; Input: R4 R5 R6 R7 = value1, R0 R1 R2 R3 = value2 ; Return: R4 R5 R6 R7 = value1 - value2 ; Use Registers: R0, R1, R2, R3 ; ;************************************************************************************** XC_fpsub: push acc ;?C?FPSUB CODE (BASEADR + 0x032B) push psw push b lcall Baseadr+032bh ; float subtract pop b pop psw pop acc ret ;************************************************************************************** ; ; XC_fpmul: float multipy ; ======================== ; Input: R4 R5 R6 R7 = value1, R0 R1 R2 R3 = value2 ; Return: R4 R5 R6 R7 = value1 * value2 ; Use Registers: R0, R1, R2, R3 ; ;************************************************************************************** XC_fpmul: push acc ;?C?FPMUL CODE (BASEADR + 0x0420) push psw push b lcall Baseadr+0420h ; float multipy pop b pop psw pop acc ret ;************************************************************************************** ; ; XC_fpdiv: float divide ; ======================= ; Input: R4 R5 R6 R7 = value1, R0 R1 R2 R3 = value2 ; Return: R4 R5 R6 R7 = value1 / value2 ; Use Registers: R0, R1, R2, R3 ; ;************************************************************************************** XC_fpdiv: push acc ;?C?FPDIV CODE (BASEADR + 0x0529) push psw push b lcall Baseadr+0529h ; float divide 246

247 pop b pop psw pop acc ret ;************************************************************************************** ; ; XC_fpcmp: float compare with generic fuzzy setting ; XC_fpcmp3: float compare with 3-bit fuzzy setting ; ================================================= ; Input: R4 R5 R6 R7 = value1, R0 R1 R2 R3 = value2 ; Fuzzy Mask: ACC = float rounding mask before compare, examples: ; ACC = 0xFF (compare all bits) ; ACC = 0xF8 (ignore last 3-bits) (entry?c?fpcmp3) ; ACC = 0x80 (ignore last 7-bits) ; Return: CY = 1 when (value1 > value 2), otherwise 0 ; ACC = 0 when (value1 == value2), otherwise!= 0 ; Use Registers: R0, R1, R2, R3, R4, R5, R6, R7 ; ;************************************************************************************** XC_fpcmp: push acc ;?C?FPCMP CODE (BASEADR + 0x05C8) push psw push b push dpl lcall Baseadr+05c8h ; float compare with generic fuzzy setting pop dpl pop b pop psw pop acc ret XC_fpcmp3: push acc push psw push b push dpl lcall Baseadr+05c6h pop dpl pop b pop psw pop acc ret ;?C?FPCMP3 CODE (BASEADR + 0x05C6) ; float compare with 3-bit fuzzy setting ;************************************************************************************** ; ; XC_suc2f: type cast: signed/unsigned char to float ; =================================================== ; Input: R4 = value, ACC.7 = MSB of value (for signed), ; ACC.7 = 0 (for unsigned) ; Return: R4 R5 R6 R7 = value in floating format ; Use Registers: none ; ;************************************************************************************** 247

248 XC_suc2f: push acc push psw push b lcall Baseadr+063dh pop b pop psw pop acc ret ;?C?FCASTC CODE (BASEADR + 0x063D) ; type cast: signed/unsigned char to float ;************************************************************************************** ; ; XC_sui2f: type cast: signed/unsigned int to float ; =================================================== ; Input: R4 R5 = value, ACC.7 = MSB of value (for signed), ; ACC.7 = 0 (for unsigned) ; Return: R4 R5 R6 R7 = value in floating format ; Use Registers: none ; ;************************************************************************************** XC_sui2f: push acc ;?C?FCASTI CODE (BASEADR + 0x0638) push psw push b lcall Baseadr+0638h ; type cast: signed/unsigned int to float pop b pop psw pop acc ret ;************************************************************************************** ; ; XC_sul2f: type cast: signed/unsigned long to float ; =================================================== ; Input: R4 R5 R6 R7 = value, ACC.7 = MSB of value (for signed), ; ACC.7 = 0 (for unsigned) ; Return: R4 R5 R6 R7 = value in floating format ; Use Registers: none ; ;************************************************************************************** XC_sul2f: push acc ;?C?FCASTL CODE (BASEADR + 0x0633) push psw push b lcall Baseadr+0633h ; type cast: signed/unsigned long to float pop b pop psw pop acc ret ;************************************************************************************** ; ; XC_f2sucil: type cast: float to signed/unsigned char/int/long ; ============================================================ ; Input: R4 R5 R6 R7 = value in float format 248

249 ; Return: R4 R5 R6 R7 = value in integer format ; Use Registers: none ; ;************************************************************************************** XC_f2sucil: push acc ;?C?CASTF CODE (BASEADR + 0x0671) push psw lcall Baseadr+0671h ; type cast:float to signed/unsigned char/int/long pop psw pop acc ret ;************************************************************************************** FP-notatie Scalars of type float are stored using four bytes (32-bits). The format used follows the IEEE-754 standard. A floating-point number is expressed as the product of two parts: the mantissa and a power of two. For example: ±mantissa 2 exponent The mantissa represents the actual binary digits of the floating-point number. The power of two is represented by the exponent. The stored form of the exponent is an 8-bit value from 0 to 255. The actual value of the exponent is calculated by subtracting 127 from the stored value (0 to 255) giving a range of 127 to The mantissa is a 24-bit value (representing about seven decimal digits) whose most significant bit (MSB) is always 1 and is, therefore, not stored. There is also a sign bit that indicates whether the floating-point number is positive or negative. Floating-point numbers are stored on byte boundaries in the following format: Address+0 Address+1 Address+2 Address+3 Contents SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM Where S represents the sign bit where 1 is negative and 0 is positive. E is the exponent with an offset of 127. M is the 24-bit mantissa (stored in 23 bits). 249

250 Zero is a special value denoted with an exponent field of 0 and a mantissa of 0. Using the above format, the floating-point number is stored as a hexadecimal value of 0xC In memory, this value appears as follows: Address+0 Address+1 Address+2 Address+3 Contents 0xC1 0x48 0x00 0x00 It is fairly simple to convert floating-point numbers to and from their hexadecimal storage equivalents. The following example demonstrates how this is done for the value shown above. The floating-point storage representation is not an intuitive format. To convert this to a floating-point number, the bits must be separated as specified in the floating-point number storage format table shown above. For example: Address+0 Address+1 Address+2 Address+3 Format SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM Binary Hex C From this illustration, you can determine the following: The sign bit is 1, indicating a negative number. The exponent value is binary or 130 decimal. Subtracting 127 from 130 leaves 3, which is the actual exponent. The mantissa appears as the following binary number: There is an understood binary point at the left of the mantissa that is always preceded by a 1. This digit is omitted from the stored form of the floating-point number. Adding 1 and the binary point to the beginning of the mantissa gives the following value: To adjust the mantissa for the exponent, move the decimal point to the left for negative exponent values or right for positive exponent values. Since the exponent is three, the mantissa is adjusted as follows: The result is a binary floating-point number. Binary digits to the left of the decimal point represent the power of two corresponding to their position. For example, 1100 represents (1 2 3 ) + (1 2 2 ) + (0 2 1 ) + (0 2 0 ), which is

251 Binary digits to the right of the decimal point also represent the power of two corresponding to their position. However, the powers are negative. For example, represents (1 2-1 ) + (0 2-2 ) + (0 2-3 ) +... which equals.5. The sum of these values is Because the sign bit was set, this number should be negative. So, the hexadecimal value 0xC is Low power modes Inleiding Het stroomverbruik van een microcontroller is afhankelijk van de kloksnelheid en het aantal onderdelen dat onder spanning staat. In realiteit wordt niet de spanning, maar de klok uitgeschakeld van het betrokken onderdeel. In bepaalde toepassingen (batterij gevoed) is het wenselijk het stroomverbruik laag te houden Uitschakelen onderdelen microcontroller Na reset worden alle onderdelen voorzien van een kloksignaal, zodat ze na initialisatie gebruikt kunnen worden. Via de PMCON1 en PMCON2 SFR s kan voor volgende I/O units de klok uitgeschakeld worden: ADC SSC CCU6 T2 MDU CAN CORDIC T21 UART1 Bovendien kan het analoge deel van de controller (ADC) volledig uitgeschakeld worden, zodat het stroomverbruik verder daalt (via SFR ADC_GLOBCTR) Algemene low power modes De globale microcontroller (I/O en CPU) kan ook in stroombesparende modes geschakeld worden (figuur ) 251

252 Figuur Power saving modes microcontroller De figuur laat zien hoe tussen de verschillende stroombesparende modes overgeschakeld kan worden. De ACTIVE mode In de ACTIVE mode werkt de processor zonder stroombesparende maatregelen. De performantie is maximaal. Dit is de mode die na het resetten van de controller automatisch geselecteerd wordt. De IDLE mode In de IDLE mode wordt de klok van de core (CPU) uitgeschakeld. De I/O modules kunnen blijven werken, maar ook individueel uitgeschakeld worden. Omdat de CPU niet meer werkt, wordt er ook geen programma uitgevoerd. In het geval de watchdog opgestart werd, zal die na verloop van tijd de CPU resetten. De CPU kan door een reset signaal, of een geactiveerde interrupt in actieve mode gezet worden. Het inschakelen van de power-down modes verloopt via het PROTECTION SCHEME, zie XC888 User s Manual). De POWER-DOWN mode 252

253 In de POWER-DOWN mode wordt de volledige klok gestopt. Omdat ook de I/O niet meer voorzien wordt van een kloksignaal kan de controller enkel in de actieve mode komen na een hardware reset, of een extern activeringssignaal (EXTINT0 of RxD). De SLOW-DOWN mode In de SLOW-DOWN mode wordt de systeemklok via een deler instelbaar tussen de 12MHz en de 62,5kHz. Hierdoor zal het stroomverbruik dalen in verhouding tot de klokfrequentie. LET OP!! Dit heeft invloed op ALLE onderdelen van de controller (o.a. rekensnelheid, resolutie timers, baud rate, MDU, CORDIC, ADC, ). 253

254 Stroomverbruik XC888 In figuur is een tabel opgenomen die het stroomverbruik van de XC888 weergeeft in functie van de gekozen mode. Figuur Stroomverbruik XC

255 De XC888 is niet bepaald een LOW-POWER microcontroller maar voor automotive en industriële applicaties is dat geen must. Hier is het belangrijker dat de controller robuust is Flash als data opslag Inleiding De meeste microcontrollers beschikken over een afzonderlijk EEPROM geheugen voor het opslaan van variabelen die niet verloren mogen gaan bij het uitschakelen van de voedingsspanning. In de XC888 werd geopteerd om hiervoor het FLASH geheugen te gebruiken. Bij een standaard 8051 is dat niet mogelijk omdat de FLASH programma geheugen is, dat niet geschreven kan worden. De XC888 CPU heeft een extra instructie die dit wel toelaat: Hierdoor bestaat er ook de mogelijkheid dat een programma zichzelf kan overschrijven (zoals een PC een upgrade kan doen van zijn eigen BIOS). Dit wordt In Application Programming (IAP)genoemd. FLASH geheugen kan niet per byte, maar enkel per sector gewist worden. Daarom is het FLASH geheugen verdeeld in sectoren (figuur ). Het FLASH geheugen bestaat uit banken van 4Kbytes. Er wordt een onderscheid gemaakt tussen P-banken en D-banken. Dit onderscheid heeft enkel te maken met hoe de bank inwendig verdeeld is in sectoren. Beide banken zijn enkel toegankelijk via het program memory van de controller. In figuur is de verdeling van de sectoren in P- en D-banken weergegeven. Het wissen van het geheugen gebeurt per sector. De D-banken zijn dus beter geschikt voor het manipuleren van kleine hoeveelheden data. De FLASH kan niet onbeperkt gewist en geschreven worden. In figuur zijn de endurance gegevens opgenomen. Je moet er bovendien rekening mee houden dat het wissen van het flashgeheugen tot 0,1s in beslag kan nemen. Het programmeren van gegevens duurt 2,6ms. 255

256 De werking van het IAP wordt in een volgende paragraaf besproken. Het gebruik van de bootloader en de bootloader mogelijkheden wordt volledig ondersteund door de XC888 ROM code en de door de fabrikant ter beschikking gestelde PC software.. Figuur FLASH memory map 256

257 Figuur Sectoren in P en D-banken Figuur FLASH endurance gegevens IAP (in application programming) De XC888 bevat een aantal ROM routines die IAP van de FLASH ondersteunen. Voor deze subroutines en hun gebruik verwijzen we naar de XC888 User s Manual. 257

258 LET OP!! je kan enkel data schrijven naar een bank die tijdens de duur van de schrijfoperatie niet gelezen wordt. je moet zelf nagaan dat de schrijfoperatie correct werd uitgevoerd door een verify (terug lezen data en vergelijken met de geschreven waarden) Er wordt een NMI (moet je wel inschakelen, waardoor het geen echte NMI is) gegenereerd wanneer de FLASH actie voorbij is. Pas dan mag je een nieuwe starten. Je zal dus een NMI routine moeten voorzien! je kan ook via polling nagaan of een bak gelezen kan worden. In figuur is een flowchart weergegeven die de interactie tussen hoofdprogramma, NMI routine en ROM routines weergeeft. Figuur Flowchart FLASH programming 258

259 6.17 Systeem klok Inleiding De klok van een microcontroller is bepalend voor de uitvoeringssnelheid van instructies. Bovendien wordt ze gebruikt als tijdsbasis voor allerhande periferiebouwstenen. Zo is ze bepalend voor de communicatiesnelheid van CAN, SSC en UART. Alle timers gebruiken de klok als tijdsbasis voor het meten van tijdsintervallen, of voor het genereren van tijdsgerelateerde signalen (PWM). Omdat de periferiebouwstenen over prescalers beschikken (instelbare delers), is de eigenlijke frequentie van de klok niet zo belangrijk, zolang ze maar gekend is. De stabiliteit van de klok is veel belangrijker. Als de klokfrequentie varieert in functie van de tijd komt de communicatiesnelheid en nauwkeurigheid van tijdsmetingen in gedrang. Om een stabiele klok te waarborgen wordt meestal een kristal gebruikt (figuur ) Frequency Tolerance ± 30ppm(Standard) at 25 ± 3 ºC Stability vs. Temperature ± 30ppm(Standard) Aging ± 3ppm/year Figuur Kristal In de figuur zijn ook enkele tolerantiegegevens opgenomen, waarbij 30ppm overeenkomt met een afwijking van 0,003%. Omdat een kristal relatief kwetsbaar en duur is, zijn de meeste controllers voorzien van een inwendige RC keten die als klokgenerator gebruikt kan worden. In figuur zijn de toleranties opgenomen van de inwendige klok van de XC

260 Figuur Toleranties inwendige oscillator XC888 Het is duidelijk dat de foutmarge veel groter is. Voor niet tijdkritische toepassingen volstaat de inwendige oscillator (minder componenten, hoge betrouwbaarheid, eenvoudige PCB design) Blokdiagram klokgenerator In figuur is het blokdiagram van de CGU (Clock Generator Unit) opgenomen. Als OSC (oscillator) kan de gebruiker kiezen uit een inwendige oscillator van 9,6MHz, of een uitwendig kristal tussen de 4 en de 12MHz. De prescaler (P), de delers (N en K) vormen samen met de PLL een schakeling die de inkomende OSC frequentie gebruikt om een stabiele, maar hogere, uitgangsfrequentie te genereren (frequentievermenigvuldiger). Hierdoor kan een kristal met een lage frequentie gebruikt worden zodat de signalen off chip minder storingen genereren. Sommige microcontrollers gebruiken een kristal van 32kHz om een uiteindelijke werkfrequentie te bekomen die veel hoger is (tientallen MHz). Fsys is de uiteindelijke systeemklok die door alle onderdelen van de controller gebruikt wordt als referentiesignaal. Fsys MOET altijd 96MHz zijn. De schakeling is ook voorzien van een klokbewaking (oscillator fail detect). Hierdoor kan de microcontroller detecteren of er nog een OSC signaal aanwezig is. 260

261 Figuur CGU van de XC Klokgenerator na reset Wanneer de XC888 uit reset komt zal de inwendige oscillator van 9.6MHz als default gekozen worden. De delers P, N en K krijgen een default waarde waardoor Fsys 96MHz zal zijn. In figuur kan je zien dat Fsys verder gedeeld wordt, afhankelijk van de onderdelen die er gebruik van maken. Standaard wordt de klok voor de periferie en de CPU ingesteld op 24MHz (SD in PMCON0=0). Door de SD (Slow Down) bit op 1 te zetten kan doormiddel van een deler de systeemklok verder gedeeld worden, waardoor de 24MHz teruggebracht kan worden naar en frequentie tussen de 12MHz en de 62,5kHz. Hoe lager de systeemklok, hoe lager het stroomverbruik. Indien gewenst, kan de 96MHz klok (via een deler instelbaar tussen 48MHz en 2,4MHz) naar buiten gebracht worden op p0.0 of p0.7. Deze pinnen zijn beschikbaar op het XC888 SBC bord via een header, zodat het signaal voor andere toepassingen beschikbaar is. 261

262 Figuur Distributie Fsys naar onderdelen XC Omschakelen tussen RC en kristal Wanneer een hogere stabiliteit gewenst is, kan de gebruiker omschakelen naar een extern kristal. In de XC888 User s Manual is een procedure opgenomen die strikt gevolgd moet worden. Voorbeeldprogramma omschakelen RC naar kristal 12MHz ;************************************************************************************** ; XCsw2xtal - Deze routine zorgt voor de omschakeling van de on-chip oscillator met een ; frequentie van 9,6MHz (+5%..-5%) naar de oscillator het die werkt met een extern ; kwarts kristal. De reden voor deze omschakeling is de veel hogere nauwkeurigheid van ; het externe kristal, wat nodig is voor bv. het nauwkeurig meten en het genereren van ; timingsignalen. Deze routine wordt meestal uitgevoerd na het opstarten van het ; systeem. Deze omschakelprocedure wordt beschreven in de XC888 Users Manual p7-13. ; ; Deze routine vernietigt geen registers en gebruikt geen geheugenlocaties. ; Geschreven door Pauwels D ; Aangepast voor cursus door Roggemans M. ;************************************************************************************** XCsw2xtal: push dph 262

263 push push push push dpl psw syscon0 scu_page mov syscon0,#04h ;selecteer RMAP0 mov scu_page,#1 ;page 1 van SCU selecteren orl pll_con,# b ;VCOBYP=1 bypass de PLL ;freq= VCO-free running =5MHz...20MHz? orl pll_con,# b ;OSCDISC=1 disconnect osc. en PLL anl osc_con,# b ;XPD=0 externe osc. power-up orl osc_con,# b ;OSCSS=1 externe oscillator selecteren mov dptr,#0f000h ;wacht tot externe osc stabiel is... XCsw2xtal0: inc dptr mov a,dpl orl a,dph jnz XCsw2xtal0 XCsw2xtal1: orl osc_con,# b ;ORDRES=1 osc run detectie starten ;wacht,...dit kan lang duren... tot >2048 VCO cycli... XCsw2xtal2: mov a,osc_con ;check OSCR en ORDRES bits (2 LSB's osc_con) jb acc.1,xcsw2xtal2 ;Osc.RunDETect klaar? ='0' ;Oscillator run detectie is klaar... jnb acc.0,xcsw2xtal1 ;OSCR=1? ja, dan oscillator running... mov a,pll_con ;lees pll_con anl a,#0fh ;maskeer onderste bits orl a,# b ;stel NDIV in op 1010=waarde 24 ;OPGELET: het password moet worden gegeven, dan kan er gedurende 32cclk cycli naar ;beveiligde locaties worden geschreven zoals NDIV en KDIV van de PLL, de watchdog ;enable bit WDTEN en de power-down en slow down enable bits PD en SD!!!! mov passwd,#98h ;het is nodig het password in te stellen!!! ;bij aanpassing van de NDIV van de PLL mov pll_con,a ;N=24 is nodig bij een 8MHz xtal anl pll_con,# b ;OSCDISC=0 connect osc en PLL orl pll_con,# b ;RESLD=1 restart PLL lock detection XCsw2xtal3: mov a,pll_con ;check de LOCK bit (lsb van dit register) jb acc.0,xcsw2xtal3 ;ga pas verder als PLL gelocked is op osc. anl pll_con,# b ;VCOBYP=0 fsys is PLL gelockte frequentie. orl osc_con,# b ;OSCPD=1 interne osc. power-down pop scu_page ;herstel controller status pop syscon0 pop psw pop dpl pop dph ret 263

264 Besluit & bedenkingen In deze cursus wordt de XC888 microcontroller van Infineon besproken. Deze cursus moet aangevuld worden met de documenten die beschikbaar zijn op de webpagina van Infineon, om een volledig beeld van de controller te geven. Het volgen van de lessen, maar vooral het maken van oefeningen, en het veelvuldig (her)lezen van de datasheets en user s manual zijn noodzakelijk om de technologie onder de knie te krijgen. De auteurs staan open voor elke vorm van constructieve kritiek die bijdragen tot het verbeteren van de kwaliteit van deze cursus. Toch willen we enkele veel voorkomende opmerking op voorhand weerleggen: het gebruik van assembler als programmeertaal: Er werd opzettelijk gekozen voor assembler vanuit de pedagogische doelstellingen van deze cursus. Het is immers de bedoeling studenten een grondige basiskennis te verschaffen van de hardware van een computersysteem. Dit houdt in dat low level programming noodzakelijk is om o.a. device drivers te kunnen maken. Dit is bovendien een cursus waar geen voorkennis geëist kan worden, en de programmeertaal bovendien een goede basis biedt voor het beter begrijpen van de hogere programmeertalen die later in de opleiding aan bod komen ( vb. in C wordt opstartcode gebruikt die in assembler geschreven is ). De aandachtige lezer zal bovendien opmerken dat de programmertaal geen doel is, maar een middel om de controller beter te begrijpen. de keuze van een 8 bit microcontroller: We merken dat alle controllers complexer worden. De 8 bit microcontrollers blijven (relatief) eenvoudig, alhoewel Door voor een 8-bitter te kiezen lukken we er in om een totale benadering van de component te maken. Het gebruik van assembler is bovendien op grotere controllers niet wenselijk. de keuze van een 8051 microcontroller: Nog altijd is de 8051 controller verantwoordelijk voor een aanzienlijk marktaandeel. Hij is uniek door zijn beschikbaarheid bij verschillende fabrikanten. Anderen blijven dikwijls beperkt tot 1 fabrikant (AVR, Microchip, ). De controllers van andere fabrikanten zijn niet slechter. Bovendien is de keuze ondergeschikt, gelet op de grote gelijkheid in werkingsprincipes en mogelijkheden. 264

265 Appendix A XC888 instructionset (snel geheugen) 265

266 266

267 267

Microcontrollers Labo

Microcontrollers Labo Microcontrollers Labo 8051 based microcontroller ADuC832 from Analog Devices 06/2016 Roggemans M. (MGM) LES 0 Testen en verdelen van de hardware FTP site overlopen Installeren van software om thuis te

Nadere informatie

Embedded systems V1.0

Embedded systems V1.0 Embedded systems Pauwels D. Embedded systems Hoofdstuk Inleiding Wat is een embedded systeem? We leven in een "embedded" wereld. We worden omringd door een groot aantal embedded systemen en in ons dagelijks

Nadere informatie

De AT90CAN microprocessor van ATMEL in de motorvoertuigentechniek (4)

De AT90CAN microprocessor van ATMEL in de motorvoertuigentechniek (4) De AT90CAN microprocessor van ATMEL in de motorvoertuigentechniek (4) Timloto o.s. / E. Gernaat / ISBN 978-90-79302-06-2 Op dit werk is de Creative Commens Licentie van toepassing. Uitgave: september 2012

Nadere informatie

De Arduino-microcontroller in de motorvoertuigentechniek (4)

De Arduino-microcontroller in de motorvoertuigentechniek (4) De Arduino-microcontroller in de motorvoertuigentechniek () E. Gernaat (ISBN 978-90-7930--6) De Atmel ATmega38/P microcontroller. Uitvoering De ATmega38 is een microprocessor van de Amerikaanse firma ATMEL

Nadere informatie

De Arduino-microcontroller in de motorvoertuigentechniek (2)

De Arduino-microcontroller in de motorvoertuigentechniek (2) De Arduino-microcontroller in de motorvoertuigentechniek (2) E. Gernaat (ISBN 978-90-79302-11-6) 1 Procescomputer 1.1 Microprocessoren algemeen De informatie-verwerking zoals is behandeld, is vrijwel geheel

Nadere informatie

Microcontrollers Week 1 Introductie microcontroller Jesse op den Brouw INLMIC/2014-2015

Microcontrollers Week 1 Introductie microcontroller Jesse op den Brouw INLMIC/2014-2015 Microcontrollers Week 1 Introductie microcontroller Jesse op den Brouw INLMIC/2014-2015 Computersysteem Een systeem dat rekenkundige operaties, data manipulaties en beslissingen kan uitvoeren, aan de hand

Nadere informatie

Inleiding microcontrollers. Week 1 Introductie microcontroller Jesse op den Brouw (met dank aan Ben Kuiper) INLMIC/

Inleiding microcontrollers. Week 1 Introductie microcontroller Jesse op den Brouw (met dank aan Ben Kuiper) INLMIC/ Inleiding microcontrollers Week 1 Introductie microcontroller Jesse op den Brouw (met dank aan Ben Kuiper) INLMIC/2018-2019 Microcontroller Uit Wikipedia: A microcontroller (sometimes abbreviated µc or

Nadere informatie

De AT90CAN microprocessor van ATMEL in de motorvoertuigentechniek (2)

De AT90CAN microprocessor van ATMEL in de motorvoertuigentechniek (2) De AT90CAN microprocessor van ATMEL in de motorvoertuigentechniek (2) Timloto o.s. / E. Gernaat / ISBN 978-90-79302-06-2 Op dit werk is de Creative Commens Licentie van toepassing. Uitgave: september 2012

Nadere informatie

2 Algemene opbouw van een computersysteem

2 Algemene opbouw van een computersysteem Procescomputer E. Gernaat 1 Microprocessoren algemeen Informatie-verwerking zoals behandeld is momenteel vrijwel geheel overgenomen door microprocessoren. Wanneer we voortborduren op het idee van combinatorische

Nadere informatie

Microcontrollers Theorie

Microcontrollers Theorie Microcontrollers Theorie 8051 based microcontroller ADuC832 from Analog Devices 07/2016 Roggemans M. (MGM) LES 1 Doelstellingen: situering vak, afspraken labo en evaluatie toelichten concept embedded oplossing

Nadere informatie

Microcontrollers. 8051 based microcontroller ADuC832 from Analog Devices. 12/2011 Roggemans M. (MGM)

Microcontrollers. 8051 based microcontroller ADuC832 from Analog Devices. 12/2011 Roggemans M. (MGM) Microcontrollers 8051 based microcontroller ADuC832 from Analog Devices 12/2011 Roggemans M. (MGM) LES 1 Doelstellingen: situering vak, afspraken labo en evaluatie toelichten concept embedded oplossing

Nadere informatie

BASIS MICROCONTROLLERS. INLEIDING EN ADDENDUM BIJ HET AduC800 DATABOEK.

BASIS MICROCONTROLLERS. INLEIDING EN ADDENDUM BIJ HET AduC800 DATABOEK. BASIS MICROCONTROLLERS INLEIDING EN ADDENDUM BIJ HET AduC800 DATABOEK. ROGGEMANS M. 07/2014 2 Inhoud INLEIDING:... 4 HOOFDSTUK 1: DE UNIVERSELE VERWERKINGSEENHEID... 8 1.1 INLEIDING:... 8 1.2 HET GEHEUGEN:...

Nadere informatie

Peripheral Interface Controllers. BRAC clubavond 5-105 PE2WDO

Peripheral Interface Controllers. BRAC clubavond 5-105 PE2WDO Peripheral Interface Controllers -10 PE2WDO Programma Introductie Wat is een PIC Wat heb je nodig om te beginnen Praktijkopdrachten: Voorbeeld met uitleg Opdrachten pag. 2 Wat is een PIC Programmable Intelligent

Nadere informatie

Wat is een busverbinding?

Wat is een busverbinding? Wat is een busverbinding? gemeenschappelijke verbinding tussen CPU, geheugen en I/O-schakelingen onderscheid tussen: databus/adresbus/controlbus intern/extern serieel/parallel unidirectioneel/bidirectioneel

Nadere informatie

De computer als processor

De computer als processor De computer als processor DE FYSIEKE COMPUTER Componenten van de computerconfiguratie Toetsenbord Muis Scanner Microfoon (Extern geheugen) Invoerapparaten Uitvoerapparaten Monitor Printer Plotter Luidspreker

Nadere informatie

Opgave Tussentijdse Oefeningen Jaarproject I Reeks 3: Tijd, licht en warmte

Opgave Tussentijdse Oefeningen Jaarproject I Reeks 3: Tijd, licht en warmte Opgave Tussentijdse Oefeningen Jaarproject I Reeks 3: Tijd, licht en warmte Voor deze oefeningenles heb je de handleiding van de uitgedeelde ARM processor nodig. Je kan deze vinden op de website van het

Nadere informatie

Hoofdstuk 7. Computerarchitectuur

Hoofdstuk 7. Computerarchitectuur Hoofdstuk 7 Computerarchitectuur 1 controlebus CPU MEMORY I/O databus adresbus Figuur 71 Schematische opbouw van een computersysteem 8 Figuur 72 Een busverbinding Buslijn Out E A In Out E B In Out E C

Nadere informatie

informatica. hardware. overzicht. moederbord CPU RAM GPU architectuur (vwo)

informatica. hardware. overzicht. moederbord CPU RAM GPU architectuur (vwo) informatica hardware overzicht moederbord CPU RAM GPU architectuur (vwo) 1 moederbord basis van de computer componenten & aansluitingen chipset Northbridge (snel) Southbridge ("traag") bussen FSB/HTB moederbord

Nadere informatie

Klas : 5 Industriële ICT Herhalingsvragen reeks 1 PC-techniek

Klas : 5 Industriële ICT Herhalingsvragen reeks 1 PC-techniek Klas : 5 Industriële ICT Herhalingsvragen reeks 1 PC-techniek VTI St.- Laurentius Neem eerst de tekst in het boek door, doe dit enkele keren en probeer uiteraard te onthouden wat je leest. Los nadien de

Nadere informatie

Tinyserir-RC5. Datasheet. Tinyserir-RC5 Page: 1 of 8

Tinyserir-RC5. Datasheet. Tinyserir-RC5 Page: 1 of 8 9600 bps RS-232 interface voor uitlezing van Ontvangen RC5 codes Led aanduiding bij ontvangst van Infrarood pulsen Led aanduiding goede werking Interne firmware Inwendige oscillator Weinig externe componenten

Nadere informatie

Wat is Arduino? Arduino = microprocessor (Atmel)

Wat is Arduino? Arduino = microprocessor (Atmel) Intro tot Arduino Wat is Arduino? Volgens de website: Arduino is an open-source electronics prototyping platform based on flexible, easy-to-use hardware and software. It's intended for artists, designers,

Nadere informatie

De CB channel controller TMS1022NL/NLL en TMS1023NL/NLL. ( Dit is een maskrom-programmed version van de Texas Instruments TMS1000 family)

De CB channel controller TMS1022NL/NLL en TMS1023NL/NLL. ( Dit is een maskrom-programmed version van de Texas Instruments TMS1000 family) De CB channel controller TMS1022NL/NLL en TMS1023NL/NLL ( Dit is een maskrom-programmed version van de Texas Instruments TMS1000 family) Ik begin even met een korte inleiding over de TMS1000. ( Wil je

Nadere informatie

Microcontrollers. 8051 based microcontroller XC888 from Infineon. 08/2011 Roggemans M. (MGM)

Microcontrollers. 8051 based microcontroller XC888 from Infineon. 08/2011 Roggemans M. (MGM) Microcontrollers 8051 based microcontroller XC888 from Infineon 08/2011 Roggemans M. (MGM) LES 1 Doelstellingen: situering vak, afspraken labo en evaluatie toelichten concept embedded oplossing probleem

Nadere informatie

Arduino CURSUS. door Willy - 09-juni-2017

Arduino CURSUS. door Willy - 09-juni-2017 Arduino CURSUS door Willy - w2@skynet.be, 09-juni-2017 OVERZICHT (1) OVERZICHT (2) Historiek Microcontroller (1) Microcontroller (2) Specificaties - Arduino UNO bord Specificaties - ATmega328P chip LET

Nadere informatie

Inhoud vandaag. Interrupts. Algemeen ARM7 AIC

Inhoud vandaag. Interrupts. Algemeen ARM7 AIC Inhoud vandaag Interrupts Algemeen ARM7 AIC Interrupts Wat is een interrupt? Een interrupt is een onderbreking van de huidige bezigheden ten gevolge van een externe gebeurtenis, zodanig dat de bezigheden

Nadere informatie

AP80 Display Controller

AP80 Display Controller Datasheet AP80 AP80 Display Controller Toepasbaar als: Display voor positie en snelheid Nokkencontroller Signaalomvormer Toerentalbewaking Linearisatie functie 72 mm ca. 160 mm 144 mm Voor sensoren met:

Nadere informatie

Oefeningen Interpretatie I Reeks 6 : Registermachines

Oefeningen Interpretatie I Reeks 6 : Registermachines Oefeningen Interpretatie I Reeks 6 : Registermachines Deze oefeningenreeks behandelt het beschrijven van computationele processen aan de hand van registermachineprogrammaʼs. Registermachines manipuleren

Nadere informatie

Labo digitale technieken

Labo digitale technieken .. Het gebied "elektronica" is reeds geruime tijd onderverdeeld in twee specialiteiten, namelijk de analoge en de digitale technieken. Binnen analoge schakelingen gebeurt de signaalverwerking met lineaire

Nadere informatie

Digitale technieken Microprocessoren

Digitale technieken Microprocessoren Digitale technieken Microprocessoren ir. Patrick Colleman Inhoudstafel Inhoudstafel. Afkortingen. Inleiding - voorwoord 1 Hoofdstuk 1 : Voorstelling van getallen en karakters. 2 1.1 Voorstelling van binaire

Nadere informatie

Geheugenbeheer. ICT Infrastructuren 2 december 2013

Geheugenbeheer. ICT Infrastructuren 2 december 2013 Geheugenbeheer ICT Infrastructuren 2 december 2013 Doelen van geheugenbeheer Reloca>e (flexibel gebruik van geheugen) Bescherming Gedeeld/gemeenschappelijk geheugen Logische indeling van procesonderdelen

Nadere informatie

Praktijkinstructie Industriële automatisering 3 (ICT09.3/CREBO:53270)

Praktijkinstructie Industriële automatisering 3 (ICT09.3/CREBO:53270) instructie Industriële automatisering 3 (ICT09.3/CREBO:53270) pi.ict09.3.v1 ECABO, 1 april 2002 Alle rechten voorbehouden. Niets uit deze uitgave mag worden vermenigvuldigd, overgenomen, opgeslagen of

Nadere informatie

Hardware-software Co-design

Hardware-software Co-design Jan Genoe KHLim Versie: maandag 10 juli 2000 Pagina 1 Wat is HW/SW Co-design Traditioneel design: De verdeling tussen de HW en de SW gebeurt bij het begin en beiden worden onafhankelijk ontwikkeld Verweven

Nadere informatie

Accelerometer project 2010 Microcontroller printje op basis van de NXP-LPC2368

Accelerometer project 2010 Microcontroller printje op basis van de NXP-LPC2368 Accelerometer project 2010 Microcontroller printje op basis van de NXP-LPC2368 Handleiding bij het gebruik van een microcontroller in het Accelerometerproject (Project II) Er zijn speciaal voor het Accelerometerproject

Nadere informatie

De seriële poort Jan Genoe KHLIM

De seriële poort Jan Genoe KHLIM De seriële poort Jan Genoe KHLIM De seriële poort 1 De seriële poort Een PC bezit een aantal seriële poorten: COM1, COM2,... Er zijn 1 of 2 seriële poorten voorzien op het moederbord Plug-in kaarten laten

Nadere informatie

1 graduaat Elektriciteit/elektronica KHLim - dep. IWT HALFGELEIDER-GEHEUGENS HALFGELEIDER GEHEUGENS STATISCH DYNAMISCH ROM PROM EPROM EEROM

1 graduaat Elektriciteit/elektronica KHLim - dep. IWT HALFGELEIDER-GEHEUGENS HALFGELEIDER GEHEUGENS STATISCH DYNAMISCH ROM PROM EPROM EEROM HALFGELEIDER-GEHEUGENS HALFGELEIDER GEHEUGENS WILLEKEURIG TOEGANKELIJK SERIEEL TOEGANKELIJK RAM ROM SRG CCD MBM STATISCH DYNAMISCH ROM PROM EPROM EEROM (ALLEEN-)LEES GEHEUGEN = ROM ROM = Read Only Memory:

Nadere informatie

Opgave Tussentijdse Oefeningen Jaarproject I Reeks 4: Lcd Interface & Files

Opgave Tussentijdse Oefeningen Jaarproject I Reeks 4: Lcd Interface & Files Opgave Tussentijdse Oefeningen Jaarproject I Reeks 4: Lcd Interface & Files 1 Introductie In deze oefening zal je je LCD display leren aansturen. Je controleert deze display door er instructies naar te

Nadere informatie

Microcontrollers Introductie INLMIC Jesse op den Brouw INLMIC/2014-2015

Microcontrollers Introductie INLMIC Jesse op den Brouw INLMIC/2014-2015 Microcontrollers Introductie INLMIC Jesse op den Brouw INLMIC/2014-2015 Microcontroller Uit Wikipedia A microcontroller (sometimes abbreviated µc or uc) is a small computer on a single integrated circuit

Nadere informatie

A Quick Start Guide: AVR programmeren

A Quick Start Guide: AVR programmeren A Quick Start Guide: AVR programmeren In deze guide wordt uitgelegd hoe men kan beginnnen met het programeren van een ATMEL AVR microcontroller. Er zal een testprogramma uit de software library AVRlib

Nadere informatie

Naam: Oumaima Bekour Klas: M4b ICT De Lange. Hardware

Naam: Oumaima Bekour Klas: M4b ICT De Lange. Hardware Naam: Oumaima Bekour Klas: M4b ICT De Lange Hardware Inleiding 1. Geschiedenis van de computer 2. Hardware 3. Interne componenten en Randapparatuur Geschiedenis De computer is uitgevonden door het rekenen.

Nadere informatie

Verslag: Computer. Naam: Tyrone Ste Luce. Klas: M4B

Verslag: Computer. Naam: Tyrone Ste Luce. Klas: M4B Verslag: Computer Naam: Tyrone Ste Luce Klas: M4B Inhoud 1. Inleiding 2. Binaire taal 3. Besturingssysteem 4. Hardware 5. Cmos en Bios 6. De processor 7. Internet 1. Inleiding Wanneer is de computer uitgevonden?

Nadere informatie

ES1 Project 1: Microcontrollers

ES1 Project 1: Microcontrollers ES1 Project 1: Microcontrollers Les 5: Timers/counters & Interrupts Timers/counters Hardware timers/counters worden in microcontrollers gebruikt om onafhankelijk van de CPU te tellen. Hierdoor kunnen andere

Nadere informatie

VRIJ TECHNISCH INSTITUUT Burg.Geyskensstraat 11 3580 BERINGEN. De PLC geïntegreerd in de PC. Vak: Toegepaste informatica Auteur: Ludwig Theunis

VRIJ TECHNISCH INSTITUUT Burg.Geyskensstraat 11 3580 BERINGEN. De PLC geïntegreerd in de PC. Vak: Toegepaste informatica Auteur: Ludwig Theunis Burg.Geyskensstraat 11 3580 BERINGEN De PLC geïntegreerd in de PC. Vak: Toegepaste informatica Auteur: Ludwig Theunis Versie: vrijdag 2 november 2007 2 Toegepaste informatica 1 De Microprocessor Zowel

Nadere informatie

ES1 Project 1: Microcontrollers

ES1 Project 1: Microcontrollers ES1 Project 1: Microcontrollers Les 3: Eenvoudige externe hardware & hardware programmeren in C Hardware programmeren in C Inmiddels ben je al aardig op gang gekomen met het programmeren van microcontrollers.

Nadere informatie

7,3. Samenvatting door een scholier 1961 woorden 16 januari keer beoordeeld. Informatica Informatica actief

7,3. Samenvatting door een scholier 1961 woorden 16 januari keer beoordeeld. Informatica Informatica actief Samenvatting door een scholier 1961 woorden 16 januari 2009 7,3 126 keer beoordeeld Vak Methode Informatica Informatica actief Hoofdstuk 3 Gespecialiseerde computers: kun je alleen voor een bepaalde functie

Nadere informatie

Stappenmotor Interface. Controller

Stappenmotor Interface. Controller Besturing In deze moderne tijd zal de besturing geheel elektrisch worden uitgevoerd. De bedoeling is dat er voor ieder afgaand spoor een wisseladres gebruikt worden. Dit betekend dan een reeks van 24 aansluitende

Nadere informatie

Interface Technieken. Roggemans M. 2012

Interface Technieken. Roggemans M. 2012 Interface Technieken Roggemans M. 2012 Evaluatie Begrijpen leerstof Figuren kunnen verklaren/uitleggen Kritische kijk op technologie (info van het internet) Basiskennis analoge 1 Herbekijk leerstof en

Nadere informatie

Tweede workshop Arduino

Tweede workshop Arduino Tweede workshop Arduino In deze workshop zal veel gewerkt worden met voorbeelden die meegeleverd worden met de Arduino IDE. Deze zijn te vinden onder het menu File >Examples. Oefening 1 - Seriële communicatie

Nadere informatie

Pajottenlandse Radio Amateurs

Pajottenlandse Radio Amateurs Pajottenlandse Radio Amateurs ON3BL 07/02/2014 SDR ontvangst met RTL-stick Waarvoor staat de afkorting SDR? SDR Software Defined Radio Definitie van Software Defined Radio Een radiocommunicatiesysteem

Nadere informatie

In- en uitgangssignalen van microprocessoren

In- en uitgangssignalen van microprocessoren In- en uitgangssignalen van microprocessoren E. Gernaat 1 Overzicht signalen Informatie van en naar een microprocessor kan parallel of seriëel gebeuren. Bij parallel-overdracht zal elke lijn (draad) een

Nadere informatie

Microcontrollers Week 4 Introductie microcontroller Jesse op den Brouw (met dank aan Ben Kuiper) INLMIC/

Microcontrollers Week 4 Introductie microcontroller Jesse op den Brouw (met dank aan Ben Kuiper) INLMIC/ Microcontrollers Week 4 Introductie microcontroller Jesse op den Brouw (met dank aan Ben Kuiper) INLMIC/2018-2019 Week 3 Lussen Ontdenderen Stack Parameteroverdracht 2 Wachtlussen In een programma willen

Nadere informatie

18 Embedded systemen 1

18 Embedded systemen 1 18 Embedded systemen 1 r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15(pc) NZCV CPSR Figuur 18.1 ARM-programmeermodel Byte 0 Byte 1 Byte 2 Byte 3 Byte 3 Byte 2 Byte 1 Byte 0 Figuur 18.2 Endian conversie

Nadere informatie

Windows Basis - Herman Van den Borre 1

Windows Basis - Herman Van den Borre 1 Windows Vista Basis Herman Van den Borre Praktische zaken Lessen Vrijdagmorgen 9u00 11u45 Pauze 10u15-10u30 Handboek Windows Vista Basis Roger Frans Uitgeverij Campinia Media ISBN: 978.90.356.1212.9 Prijs:

Nadere informatie

Opdracht 1 Integrated Circuit

Opdracht 1 Integrated Circuit Opdracht 1 Leg uit: IC. IC is de afkorting van Integrated Circuit, ook wel chip genoemd. Een IC bestaat uit duizenden of miljoenen uiterst kleine elektronische componenten zoals weerstanden, condensators

Nadere informatie

Gebruiksaanwijzing AVR910 USB Programmer

Gebruiksaanwijzing AVR910 USB Programmer TECHNISCH INSTITUUT SINT-PAULUS Kruisven 25 2400 Mol Gebruiksaanwijzing Schooljaar 2007-2008 Studierichting EE Gebruiksaanwijzing AVR910 USB Programmer Geïntegreerd in AVR-DevL Board Jan Cools Projecten

Nadere informatie

Van Poort tot Pipeline. Ben Bruidegom & Wouter Koolen-Wijkstra AMSTEL Instituut Universiteit van Amsterdam

Van Poort tot Pipeline. Ben Bruidegom & Wouter Koolen-Wijkstra AMSTEL Instituut Universiteit van Amsterdam Van Poort tot Pipeline Ben Bruidegom & Wouter Koolen-Wijkstra AMSTEL Instituut Universiteit van Amsterdam Van Poort tot Pipeline Pipeline processor One cycle machine Calculator File of registers Assembly

Nadere informatie

De Computer 15 mei 2018

De Computer 15 mei 2018 De Computer 15 mei 2018 Jos Heemskerk Ruud Blok De geschiedenis van de computer begint met de geschiedenis van het rekenen. Astronomen hadden een grote behoefte aan rekenkracht 1822 eerste computer met

Nadere informatie

Microcontrollers. Robert Langenhuysen, PA0RYL

Microcontrollers. Robert Langenhuysen, PA0RYL Microcontrollers Robert Langenhuysen, PA0RYL 1 RF Seminar B&D 2013 Eisen Niet al te ingewikkeld Kits, geschikt voor experimenteren, rapid prototyping, etc. I/O mogelijkheden HDMI, VGA, SD, analoog, digital,

Nadere informatie

AP21 SSI Display. Display voor positie en snelheid Nokkencontroller Signaalomvormer Display voor niet lineaire bewegingen. 96 mm

AP21 SSI Display. Display voor positie en snelheid Nokkencontroller Signaalomvormer Display voor niet lineaire bewegingen. 96 mm Datasheet AP21 AP21 SSI Display Toepasbaar als: Display voor positie en snelheid Nokkencontroller Signaalomvormer Display voor niet lineaire bewegingen 48 mm ca. 90 mm 96 mm Voor sensoren met Synchroon

Nadere informatie

Raspberry pi snel start handleiding

Raspberry pi snel start handleiding Raspberry pi snel start handleiding G.L.J. Quellhorst V _NL_2.0 Maart 2 0 15 Raspberry pi, snel start handleiding Deze informatie is onder ander verkrijgbaar via: http://www.raspberrypi.org http://www.zoekutuit.nl

Nadere informatie

Digitale en analoge technieken

Digitale en analoge technieken Digitale en analoge technieken Peter Slaets February 14, 2006 Peter Slaets () Digitale en analoge technieken February 14, 2006 1 / 33 Computerarchitectuur 1 Processors 2 Primair geheugen 3 Secundair geheugen

Nadere informatie

AVR-DOPER MINI ASSEMBLAGE HANDLEIDING + LAYOUT. Geschreven door: Tom Vocke

AVR-DOPER MINI ASSEMBLAGE HANDLEIDING + LAYOUT. Geschreven door: Tom Vocke AVR-DOPER MINI ASSEMBLAGE HANDLEIDING + LAYOUT Geschreven door: Tom Vocke Datum: 28-09-2010 Inleiding: Dit document bevat alle hardware informatie betreffende de AVR-Doper mini. Het eerste deel zal zich

Nadere informatie

De Arduino-microcontroller in de motorvoertuigentechniek (3)

De Arduino-microcontroller in de motorvoertuigentechniek (3) De Arduino-microcontroller in de motorvoertuigentechniek (3) E. Gernaat (ISBN 978-90-79302-11-6) 1 In- en uitgangssignalen van microprocessoren 1.1 Overzicht signalen Informatie van en naar een microprocessor

Nadere informatie

Hoofdstuk 6: Digitale signalen

Hoofdstuk 6: Digitale signalen Hoofdstuk 6: Digitale signalen 6. Algemeenheden Het decimale talstelsel is het meest gebruikte talstelsel om getallen voor te stellen. Hierin worden symbolen gebruikt ( t.e.m. 9 ) die ondubbelzinning de

Nadere informatie

RAM geheugens. Jan Genoe KHLim. Situering RAM-geheugens. Geheugens. Halfgeleider Geheugens. Willekeurig toegankelijk geheugen

RAM geheugens. Jan Genoe KHLim. Situering RAM-geheugens. Geheugens. Halfgeleider Geheugens. Willekeurig toegankelijk geheugen Jan Genoe KHLim Situering RAM-geheugens Geheugens Halfgeleider Geheugens Serieel toegankelijk geheugen Willekeurig toegankelijk geheugen Read Only Memory ROM Random Access Memory RAM Statische RAM SRAM

Nadere informatie

Hoofdstuk 3: Processen: Beschrijving en Besturing. Wat is een proces? Waarom processen? Wat moet het OS ervoor doen? Is het OS zelf een proces?

Hoofdstuk 3: Processen: Beschrijving en Besturing. Wat is een proces? Waarom processen? Wat moet het OS ervoor doen? Is het OS zelf een proces? Hoofdstuk 3: Processen: Beschrijving en Besturing Wat is een proces? Waarom processen? Wat moet het OS ervoor doen? Is het OS zelf een proces? 1 Wat is een proces? Een proces is een programma in uitvoering

Nadere informatie

AP40 Display Controller

AP40 Display Controller Datasheet AP40 Versie 03-2010 / NL AP40 Display Controller Toepasbaar als: Display voor positie en snelheid Nokkencontroller Signaalomvormer Toerentalbewaking Procestijdmeting (1/f) 48 mm ca. 150 mm 96

Nadere informatie

B3C 70cm converter besturing. v1.0 2010 PE5PVB www.het bar.net pe5pvb@het bar.net

B3C 70cm converter besturing. v1.0 2010 PE5PVB www.het bar.net pe5pvb@het bar.net B3C 70cm converter besturing v1.0 2010 PE5PVB www.het bar.net pe5pvb@het bar.net Deze schakeling en de bijbehorende software mag niet worden gedupliceerd voor commerciële verkoop zonder uitdrukkelijke

Nadere informatie

De AT90CAN microprocessor van ATMEL in de motorvoertuigentechniek (3)

De AT90CAN microprocessor van ATMEL in de motorvoertuigentechniek (3) De AT90CAN microprocessor van ATMEL in de motorvoertuigentechniek (3) Timloto o.s. / E. Gernaat / ISBN 978-90-79302-06-2 Op dit werk is de Creative Commens Licentie van toepassing. Uitgave: september 2012

Nadere informatie

Een intelligent DMX netwerk

Een intelligent DMX netwerk WORKSHOP STEPP Een intelligent DMX netwerk WORKSHOP STEPP Wat is DMX? Een intelligent DMX netwerk Demo opstelling Probleem oplossing Wat is DMX? Hoe is het DMX signaal ontstaan DMX in de praktijk Hoe

Nadere informatie

AP40 Display Controller

AP40 Display Controller Datasheet AP40 AP40 Display Controller Toepasbaar als: Display voor positie en snelheid Nokkencontroller Signaalomvormer Toerentalbewaking Procestijdmeting (1/f) Display voor niet lineaire bewegingen 48

Nadere informatie

von-neumann-architectuur Opbouw van een CPU Processoren 1 december 2014

von-neumann-architectuur Opbouw van een CPU Processoren 1 december 2014 von-neumann-architectuur Opbouw van een CPU Processoren 1 december 2014 Herhaling: Booleaanse algebra (B = {0,1},., +, ) Elke Booleaanse functie f: B n B m kan met., +, geschreven worden Met Gates (electronische

Nadere informatie

ES1 Project 1: Microcontrollers

ES1 Project 1: Microcontrollers ES1 Project 1: Microcontrollers Les 1: Installeren en verifiëren van de SDE Door Hugo Arends, augustus 2012 Microcontrollers Een microcontroller is een elektronische component dat gebruikt wordt om (complexe)

Nadere informatie

FORTH op de 80C535 processor met het ATS535 board.

FORTH op de 80C535 processor met het ATS535 board. FORTH op de 80C535 processor met het ATS535 board. ATS535 Het ATS535 board met 8052- ANS-Forth, is een product van de HCC Forth GG en Atelec Hoorn. Het board met de ingebouwde software is een uitstekend

Nadere informatie

Hoofdstuk 2. De Von Neumann-architectuur

Hoofdstuk 2. De Von Neumann-architectuur Input Interface Output Interface Informatica Deel III Hoofdstuk 2 De Von Neumann-architectuur 2.1. Organisatie. De overgrote meerderheid der digitale computers zijn georganiseerd zoals weergegeven in fig.

Nadere informatie

Hoofdstuk 19. Embedded systemen

Hoofdstuk 19. Embedded systemen Hoofdstuk 19 Embedded systemen 1 r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15(pc) NZCV CPSR Figuur 19.1: ARM-programmeermodel. Byte 0 Byte 1 Byte 2 Byte 3 Byte 3 Byte 2 Byte 1 Byte 0 Figuur 19.2:

Nadere informatie

Sequentiële Logica. Processoren 24 november 2014

Sequentiële Logica. Processoren 24 november 2014 Sequentiële Logica Processoren 24 november 2014 Inhoud Eindige automaten Schakelingen met geheugen Realisatie van eindige automaten Registers, schuifregisters, tellers, etc. Geheugen Herinnering van week

Nadere informatie

Een desktopcomputer kan uit de volgende onderdelen zijn opgebouwd:

Een desktopcomputer kan uit de volgende onderdelen zijn opgebouwd: SAMENVATTING HOOFDSTUK 1 Een computersysteem De twee meest gebruikte modellen computers zijn: * Desktop * Laptop Een desktopcomputer kan uit de volgende onderdelen zijn opgebouwd: Systeemkast Beeldscherm

Nadere informatie

Randappartuur. yvan vander sanden. 23 november 2014

Randappartuur. yvan vander sanden. 23 november 2014 Randappartuur yvan vander sanden 23 november 2014 ! muis, toetsenbord, scherm! speakers! scanners, printers! barcode readers! Drivers Zonder driver kan een apparaat niet werken. Device Drivers installeer

Nadere informatie

Computerarchitectuur en netwerken. Memory management Assembler programmering

Computerarchitectuur en netwerken. Memory management Assembler programmering Computerarchitectuur en netwerken 2 Memory management Assembler programmering Lennart Herlaar 10 september 2018 Inhoud 1 Protectie: Hoe het O.S. programma s tegen elkaar kan beschermen modes memory management

Nadere informatie

ES1 Project 1: Microcontrollers

ES1 Project 1: Microcontrollers ES1 Project 1: Microcontrollers Les 2: Architectuur ATmega32 en STK500 Door Hugo Arends, september 2012 Architectuur ATmega32 Een uitgebreide en gedetailleerde beschrijving van de ATmega32 microcontroller

Nadere informatie

0 of laag niveau V verboden zone 1 of hoog niveau. Voorbeeld van een digitaal signaal als functie van de tijd

0 of laag niveau V verboden zone 1 of hoog niveau. Voorbeeld van een digitaal signaal als functie van de tijd 5. Herhalingsvragen 1. Leg met eigen woorden en figuren uit: Wat is het verschil tussen analoog en digitaal? Analoog is continue, er zijn oneindig veel mogelijkheden tussen minimum en maximum. Digitaal

Nadere informatie

Jen Kegels, Eveline De Wilde, Inge Platteaux, Tamara Van Marcke. Hardware. De computer in een oogopslag. 1 / 11 Cursusontwikkeling

Jen Kegels, Eveline De Wilde, Inge Platteaux, Tamara Van Marcke. Hardware. De computer in een oogopslag. 1 / 11 Cursusontwikkeling Hardware De computer in een oogopslag 1 / 11 Cursusontwikkeling Opslag Er worden verschillende apparaten gebruikt om gegevens op te slaan. Dit zijn de meest voorkomende apparaten. Harde schijf; CD / DVD;

Nadere informatie

USB 3.0 naar VGA video adapter met automatische on-board driver installatie x1200

USB 3.0 naar VGA video adapter met automatische on-board driver installatie x1200 USB 3.0 naar VGA video adapter met automatische on-board driver installatie - 1920 x1200 Product ID: USB32VGAV Deze USB 3.0 naar VGA videoadapter werkt als een externe videokaart, waardoor via de USB-poort

Nadere informatie

EDK Walkthrough: Hardwareontwerp met GPIO en UART Deel 1

EDK Walkthrough: Hardwareontwerp met GPIO en UART Deel 1 EDK Walkthrough: Hardwareontwerp met GPIO en UART Deel 1 1. Doel Kennismaking met de EDK van Xilinx: - begrijpen van de ontwerpomgeving en design flow - aanmaken van een Xilinx Platform Studio project

Nadere informatie

TECHNISCHE UNIVERSITEIT EINDHOVEN FACULTEIT DER TECHNISCHE NATUURKUNDE

TECHNISCHE UNIVERSITEIT EINDHOVEN FACULTEIT DER TECHNISCHE NATUURKUNDE TECHNISCHE UNIVERSITEIT EINDHOVEN FACULTEIT DER TECHNISCHE NATUURKUNDE Tentamen Computers bij fysische experimenten (3BB20) op dinsdag 25 oktober 2005 Het tentamen duurt 90 minuten en wordt gemaakt zonder

Nadere informatie

Computertechniek vorige examens

Computertechniek vorige examens Computertechniek vorige examens Examen 2009 Groep 1 1. Geef de 2 manieren waarop de adressen van de I/O-module in de adresruimte geïntegreerd kunnen zijn. (memory-mapped en isolated dus) 2. Wat is post-indexering?

Nadere informatie

GEINTEGREERDE PROEF DE COMPUTER ALS TV AFSTANDSBEDIENING

GEINTEGREERDE PROEF DE COMPUTER ALS TV AFSTANDSBEDIENING 7 IC De Computer als TV afstandsbediening - 1 - KTA-Gent GEINTEGREERDE PROEF DE COMPUTER ALS TV AFSTANDSBEDIENING Arnoud De Kemel Industriële Computertechnieken Schooljaar 2004-2005 7 IC De Computer als

Nadere informatie

Logo quiz Project Inleiding op de Logo!

Logo quiz Project Inleiding op de Logo! Logo quiz Project Inleiding op de Logo! Project ontwikkelt door: Tim van Schuylenburg Ben van Kruisbergen Inhoudsopgave Projectbeschrijving en Planning 2 Blz. De benodigdheden en aansluitschema 4-8 Complete

Nadere informatie

LocoServo Handleiding

LocoServo Handleiding LocoServo Handleiding HDM12 Disclaimer van Aansprakelijkheid: Het gebruik van alle items die kunnen worden gekocht en alle installatie-instructies die kunnen worden gevonden op deze site is op eigen risico.

Nadere informatie

Basiscursus microcontrollers

Basiscursus microcontrollers Basiscursus microcontrollers Deel 6. Aansturen van een LCD Burkhard Kainka De data-uitvoer van het flash-board gaat gewoonlijk naar de aangesloten terminal, de PC dus. Voor stand-alone applicaties zonder

Nadere informatie

Vier aandachtspunten bij het specificeren van digitaal geregelde voedingen

Vier aandachtspunten bij het specificeren van digitaal geregelde voedingen Vier aandachtspunten bij het specificeren van digitaal geregelde voedingen De industrie staat soms nog wat afwachtend tegenover digitaal geregelde voedingen omdat engineers, anders dan bij de traditionele

Nadere informatie

IEEE 1394 firewire. Jan Genoe KHLim. I-link DV (digital video)

IEEE 1394 firewire. Jan Genoe KHLim. I-link DV (digital video) IEEE 1394 firewire I-link DV (digital video) Jan Genoe KHLim 1 Traditionele video bewerkingswerkwijze In draagbare video camera's worden beelden reeds lang aan de hand van CCD opgenomen, dit wil zeggen

Nadere informatie

Oefening 1 - Seriële communicatie via USB

Oefening 1 - Seriële communicatie via USB Werkbladen voor Arduino workshop 2 In deze workshop zal gewerkt worden met de voorbeelden die meegeleverd worden met de Arduino IDE. Deze zijn te vinden onder het menu Bestand->Voorbeelden. Oefening 1

Nadere informatie

Scan-pad technieken. Zet elk register om in een scan-pad register (twee opeenvolgende D-latches: master-slave):

Scan-pad technieken. Zet elk register om in een scan-pad register (twee opeenvolgende D-latches: master-slave): Zet elk register om in een scan-pad register (twee opeenvolgende D-latches: master-slave): D is de normale data ingang C is de normale fase 1 klok I is de data ingang van het shift-regiester A is de klok

Nadere informatie

Ontvanger met GSM-transmissie GSM 700

Ontvanger met GSM-transmissie GSM 700 HANDLEIDING Ontvanger met GSM-transmissie GSM 700 www.tempolec.be 01. INTRODUCTIE Ontvanger met : - een GSM-transmissie - een uitgang (contact NO / NF spanningsvrij). Mogelijke functie van de uitgang :

Nadere informatie

Programmering Tiny45 voor de DCC locdecoder

Programmering Tiny45 voor de DCC locdecoder Programmering Tiny45 voor de DCC locdecoder Dit is een beschrijving voor het programmeren van de Tiny45 van de locdecoder. Voor de eerste programmering is een programmer voor Atmel AVR mikrocontrollers

Nadere informatie

Netwerk Interfacing Data Logging.

Netwerk Interfacing Data Logging. Handleiding Netwerk Interfacing Data Logging. EduTechSoft.nl 2009-2010 H.O.Boorsma. Pagina - 2 - Netwerk Interfacing Data Logging Pagina - 3 - Inhoud Inleiding.... 4 Beschrijving van het programma....

Nadere informatie

Desktop, Laptop, Netbook, Ultrabook or Tablet? Which is best for what? Keuzes maken

Desktop, Laptop, Netbook, Ultrabook or Tablet? Which is best for what? Keuzes maken Desktop, Laptop, Netbook, Ultrabook or Tablet? Which is best for what?. Keuzes maken Wanneer je een computer wilt aanschaffen denk je tegenwoordig niet meteen meer aan de desktop. De desktop is een "grote"

Nadere informatie

EM2 Microcontroller Project. LED cube

EM2 Microcontroller Project. LED cube EM2 Microcontroller Project LED cube Door: Dennis Koster Klas: Tc202 Studentnummer: 536496 Docent: Jan Derriks & Ruud Slokker Versie 1.0 (12-1-2009) Inhoudsopgave Inleiding 3 De onderdelen 4 t/ m 6 Het

Nadere informatie

De Arduino-microcontroller in de motorvoertuigentechniek (8)

De Arduino-microcontroller in de motorvoertuigentechniek (8) De Arduino-microcontroller in de motorvoertuigentechniek (8) E. Gernaat (ISBN 978-90-79302-11-6) 1 Assembly (Assembleertaal) 1.1 Inleiding De Arduino kan ook in assembleertaal (assembly) worden geprogrammeerd.

Nadere informatie