Spring naar hoofdtekst

Hard- en software: AT89C2051 digitale klok

Geplaatst op door .
Laatste aanpassing op .

Inleiding

Een paar maanden geleden vroeg mijn vader, Jan Post, of ik hem wilde helpen met een elektronisch knutselproject: een digitale klok met zes 7-segment displays en een AT89C2051 microcontroller. Hij had in China een bouwpakket (1, 2) gekocht waarbij er, na het assembleren en verbinden met de voedingsspanning… helemaal niets gebeurde. Hij vond een mogelijke verklaring (YouTube): waarschijnlijk was de microcontroller geprogrammeerd met de broncode van de firmware, of zelfs helemaal niet geprogrammeerd.

Zoektocht

Aldus begon een zoektocht naar de passende hard-, soft- en firmware. De eerste stap was een zogenaamde programmer, een apparaatje om de microcontroller te kunnen flashen met de uit te voeren instructies. In eerste instantie vonden we alleen maar apparaten van meer dan €100,- per stuk – veel te duur voor een project zoals dit. Uiteindelijk verscheen er dan toch de SP200S-V2.0 programmer voor ongeveer €10,- per stuk ten tonele. Hebbes!

Naast de programmer moest er ook een programma komen om dat apparaatje aan te spreken, om zo de zich daarin bevindende chip te kunnen flashen. Je zou verwachten dat in de documentatie bij de programmer een downloadlink zou staan, nee dus. Dan misschien in de webshop waar de programmer werd aangeboden? Nee dus. Uiteindelijk vond ik WL-Pro V220. De firma achter deze software schijnt niet meer te bestaan. Althans, hun website willar.com is opvallend leeg. Desalniettemin draait het programma in een virtuele Windows 10 en kan via USB de prorgrammer aanspreken en de microcontroller lezen + schrijven. De seriële poort van de programmer (CH340-chip) werd zonder extra stuurprogramma's herkend.

Nu nog de passende firmware, zij het kant en klaar of als broncode om zelf te compileren. Ruthsarian, de maker van de video op YouTube, had zijn eigen variant geschreven en die gepubliceerd. Ik besloot dat project als basis te nemen, oftewel te forken. Pas toen ik die firmware voor het eerst flashte bleek er toch wel een belangrijk verschil te zijn tussen de klok van hem en die van ons: de zijne had vier cijfers, de onze zes.

Aanpassingen

Zonder praktische ervaring in C ging ik toch maar aan de slag met het bestuderen van de broncode en bijbehorende stroomkringschema. Het bleek al gauw dat een klok met zes cijfers andere outputs gebruikte dan die met vier. Ook de derde button moest ergens worden uitgelezen. Tot slot waren ook de al-dan-niet knipperende puntjes tussen de displays ergens anders aangesloten dan bij de kleinere kit.

Makefile

Een makefile is een soort hulpscript dat wordt gebruikt tijdens het ontwikkelen en bouwen van software. Het bevat variabelen en shellcommando's om verschillende taken te kunnen uitvoeren zoals het leegmaken van de bouwmap en natuurlijk het compileren van de afzonderlijke onderdelen of het gehele programma. Met de oorspronkelijke makefile verscheen echter een foutmelding als ik make clean liet uitvoeren

clean:
    rm -f "build/*"
    rmdir "build"

Wat bleek? De asterisk als zogenaamde wildcard voor nul of meer tekens (in deze context dus alle bestanden in de bouwmap) stond binnen de aanhalingstekens. Daardoor negeerde de shell de wildcard en deed helemaal niets. Het daarop volgende commando rmdir "build" ging aldus de mist in; de map was immers niet vooraf leeggemaakt. De juiste plaats voor de asterisk is achter het aanhalingsteken:

clean:
    rm -f "build/"*
    rmdir "build"

Compiler

Om broncode uitvoerbaar te maken voor een (micro-)processor moet er een zogenaamde compiler worden gebruikt. Dit programma zet de voor mensen leesbare code om in binaire instructies die de machine kan uitvoeren. Dit proces heet compileren. Bij dit project maakt ik voor het eerst kennis met de Small Device C-Compiler, oftewel SDCC.

In de documentatie van Ruthsarian stond dat het hem niet was gelukt om met een actuele versie van SDCC een bestand te bouwen dat in de 2kB geheugen van de AT89C2051 zou passen. Hij week uit naar versie 3.5.0. Deze kun je, na het uitpakken van de download, op zijn beurt compileren met behulp van make.

7-segment displays

Het was best een puzzel om de in- en uitgangen te vertalen van de oude naar de nieuwe situatie. In de klokkit met vier cijfers werd uitgang P3.3 (pin 7) gebruikt voor de buzzer. In de nieuwe klok was dit P3.7 (pin 11). De knipperende puntjes tussen de displays werden P1.7 (pin 19). Ook de zeven segmenten van de displays werden in een andere volgorde aangesloten:

segment/onderdeel 4-cijfers 6-cijfers
a P1.7 (pin 19) P1.2 (pin 14)
b P1.5 (pin 17) P1.3 (pin 15)
c P1.2 (pin 14) P1.4 (pin 16)
d P1.3 (pin 15) P1.6 (pin 18)
e P1.4 (pin 16) P1.5 (pin 17)
f P1.6 (pin 18) P1.1 (pin 13)
g P1.1 (pin 13) P1.0 (pin 12)
dp P1.0 (pin 12) (niet aangesloten)
knipper-punten (niet aangesloten) P1.7 (pin 19)
buzzer P3.3 (pin 7) P3.7 (pin 11)

Zie ook de stroomkringschema's van beide kits:

Schema van de 4-cijferige klok

Schema van de 6-cijferige klok

Buttons

Een opvallend detail van al deze klokkits (zowel 4- als 6-cijferig): bij het indrukken van de verschillende buttons licht één van de displays altijd volledig op. Als je het schema bekijkt is ook duidelijk waarom:

  • P3.2 (pin 6) is tegelijkertijd
    ingang voor Button 1 maar ook uitgang voor het vierde display van links
  • P3.4 (pin 8) is tegelijkertijd
    ingang voor Button 2 maar ook uitgang voor het eerste display van links
  • P3.5 (pin 9) is tegelijkertijd
    ingang voor Button 3 maar ook uitgang voor het derde display van links

Met deze chip kan het dus niet anders, dan dat die displays oplichten als je een button indrukt – ook met de officiële firmware. "It's not a bug, it's a feature."

Stuiteren

De microcontroller in deze kits draait op een kloksnelheid van 12 MHz. Dat betekent dat er 12.000.000 keer per seconde een instructie kan worden uitgevoerd. Ook de ingangen van de chip kunnen met die frequentie worden afgetast. Maar wat gebeurt er als één van de buttons wordt bediend?

De contacten van zo'n knop sluiten bij het indrukken niet meteen helemaal. Er is een paar milliseconden lang een welles-nietes spelletje, waarbij de elektronen dan weer wel, dan weer niet vloeien. Bij een aftastfrequentie van meerdere megahertz zal de ingang zo als het ware stuiteren, oftewel bouncen.

Bij de bediening van een apparaat (zoals deze klok met knoppen om de tijd en alarm in te stellen) wil je zo'n ping-pongspel als het kan voorkomen. Dat kan door de stroom tijdelijk te bufferen met een condensator en een weerstand. Of je kan in de firmware net zolang wachten totdat de ingang een vast bepaalde periode 'hoog' of 'laag' wordt gemeten. Zie ook dit diepgaand artikel (Engelstalig) over het hoe-en-waarom van debouncen.

Basis broncode

Zoals gezegd heb ik weinig tot geen ervaring in de programmeertaal C. Door het bestuderen van de verschillende broncodes voor deze microcontroller ben ik daarin een aantal overeenkomsten gaan zien:

  • om de registers van deze chip aan te kunnen spreken, worden eerst de header-definities toegevoegd:
    #include <mcs51/at89x051.h>
  • de functie die de chip uitvoert zogauw hij voedingsspanning krijgt heet main()
  • bovenin main() worden een aantal instellingen gekozen en de timer geactiveerd
  • tot slot volgt een eindeloze loop (while (1) {...})
  • in deze loop wordt de button bediening afgehandeld
  • ondertussen wordt bij elke tik van de timer de functie timer1_isr() uitgevoerd

De exacte instellingen (zoals timerperiode en displayaansturing) variëren per implementatie. Dat is best verwarrend als je vanuit het niets probeert te snappen hoe één en ander werkt door verschillende codes met elkaar te vergelijken. Maar goed. Hieronder een voorbeeld uit één van de beter gedocumenteerde projecten:

#include <mcs51/at89x051.h>
// To compile:
// sdcc -mmcs51 --opt-code-size --code-size 2048 this-file.c

void timer1_isr(void) __interrupt (3) __using (1) { // every 250us
    // ...
}

void main(void) {
    TMOD = 0x20;  // timer 1 in 8-bit auto-reload mode
    TH1 = 0x06;   // count from 0x06 to 0xFF then wrap,
                  // with 12MHz crystal, will interrupt every 250us
    IE = 0x88;    // enable timer 1 interrupts
    TCON |= 0x40; // run timer 1

    while (1) {
        // ...
    }
}

Kant en klaar

Jammer, maar helaas; ik liep vast op meerdere fronten. Het lukte me niet om de bestaande code uit te breiden met de derde button. Ten minste, niet zonder de grens van 2048 byte geheugen te overschrijden.

Met genoeg geduld vond ik een artikel van Ceptimus waarin de zescijferige digitale klok werd ontleed en besproken. Ook had deze (vermoedelijke) Engelsman twee vervangende firmwares geschreven: één met enkel een 24-uurs klok, één met enkel een 12-uurs klok. Beide zijn dimbaar, dat wil zeggen voorzien van een viertraps helderheidsregeling. Daarnaast biedt Ceptimus ook de originele firmware in .hex-formaat als download aan. Deze bevat naast de 24-uurs klok met alarm ook nog een timer, een teller en een stopwatch. Thank you, Ceptimus! Ook voor het uitvoerig commentaar in de broncode van de zelfgeschreven firmwares. Daar kan een onervaren programmeur nog wat van leren :-).

Voeding

Is er dan alles goud wat blinkt? Nee, niet meteen. Toen ik na elkaar de originele Chinese, maar ook de 24-uurs firmware van Ceptimus flashte, gebeurde er iets raars. De seconden tikten netjes voort, de klok op zich werkte naar behoren. Maar zo gauw de buzzer werd geactiveerd (afgaan van het alarm of bevestigingspiep van de helderheids­regeling), werden alle displays donker en bleef de buzzer klinken. Ik moest dan de 9V-batterij afkoppelen om de klok te resetten.

Omdat dit bij zowel de originele als de alternatieve firmware optrad, kon ik de firmware waarschijnlijk uitsluiten en ging op zoek naar een hardware-oorzaak. Na overleg met mijn vader besloot ik om, in plaats van een 9V-batterij, de klok op een 9 Volt netvoeding aan te sluiten. En warempel! Beide firmwares werkten volledig naar behoren; met alle toeters en bellen, oftewel buttons en buzzers.

Het blijkt dat een te lage of inzakkende voedingsspanning, zoals van een oudere batterij, onvoorspelbare gevolgen kan hebben. Zo werden de displays donker, bleef de buzzer piepen en reageerde buttons totaal niet meer. De microcontroller draaide intussen vrolijk door; hij zou nog zelfs bij 2,7 Volt werken (zie ook de datasheet).

Terug naar boven

Inhoudsopgave

Delen

Met de deel-knop van uw browser, of met onderstaande koppelingen deelt u deze pagina via sociale media of e-mail.

Atom-feed van FWiePs weblog

Artikelen


Categorieën

Doorzoek de onderstaande categorieën om de lijst met artikelen te filteren.


Terug naar boven