Difference between revisions of "Arduino - 4-digit LED Segment Display"
(Created page with "===4-Digit Segment Display=== In het vorige project hebben we het 1-digit segment display behandeld. Dit display heeft 9 pootjes die...") |
(→Uitleg) |
||
| Line 173: | Line 173: | ||
In de setup() worden de lijsten weer van waarden voorzien en worden zowel de LEDs[] als de digits[] pins op OUTPUT ingesteld. Ook nu gaat dat weer handig met een for-loop. Dan staan er een paar delen uit (commentaar gemaakt). Hier worden bepaalde patronen op de digits gezet waarmee je kunt testen of alles goed werkt. Ach, het is vooral cool. | In de setup() worden de lijsten weer van waarden voorzien en worden zowel de LEDs[] als de digits[] pins op OUTPUT ingesteld. Ook nu gaat dat weer handig met een for-loop. Dan staan er een paar delen uit (commentaar gemaakt). Hier worden bepaalde patronen op de digits gezet waarmee je kunt testen of alles goed werkt. Ach, het is vooral cool. | ||
| − | Ook hier is de loop() functie relatief eenvoudig. Hij heeft een for-loop waarin de functie doDisplay() wordt aangeroepen met een bepaalde set patronen en een tijdsduur. Deze functie doDisplay() laat het eerste patroon | + | Ook hier is de loop() functie relatief eenvoudig. Hij heeft een for-loop waarin de functie doDisplay() wordt aangeroepen met een bepaalde set patronen en een tijdsduur. Deze functie doDisplay() laat het eerste patroon zien op de eerste digit, het tweede op de tweede digit, het derde op de derde digit en het vierde op de vierde digit. Dit wordt in een for-loop herhaald tot de gewenste display tijd om is. De patronen die de for-loop aan doDisplay() worden meegegeven zijn natuurlijk cijfers uit de lijst patronen[]. De index van de lijst wordt voor elke digit berekend met formules. Hier volgt wat uitleg: |
<pre> | <pre> | ||
[i % 10] // Dit is gewoon i, maar als i groter wordt dan 10 wordt er 10 afgetrokken. | [i % 10] // Dit is gewoon i, maar als i groter wordt dan 10 wordt er 10 afgetrokken. | ||
| Line 182: | Line 182: | ||
Het teken ''%10'' betekent ''modulus''; n%10 is n waarvan zoveel keer 10 is afgetrokken als maar kan (zonder dat de uitkomst negatief wordt). Als i=0 gebruikt de loop dus patronen[0], patronen[1], patronen[2] en patronen[3]. Als i=1 gebruikt de loop patronen[1], patronen[2], patronen[3] en patronen[4]. En als i=9 gaat de modulus zijn werk doen en gebruikt de loop patronen[9], patronen[0], patronen[1] en patronen[2]. | Het teken ''%10'' betekent ''modulus''; n%10 is n waarvan zoveel keer 10 is afgetrokken als maar kan (zonder dat de uitkomst negatief wordt). Als i=0 gebruikt de loop dus patronen[0], patronen[1], patronen[2] en patronen[3]. Als i=1 gebruikt de loop patronen[1], patronen[2], patronen[3] en patronen[4]. En als i=9 gaat de modulus zijn werk doen en gebruikt de loop patronen[9], patronen[0], patronen[1] en patronen[2]. | ||
| − | Dit programma heeft twee nieuwe | + | Dit programma heeft twee nieuwe functies ten opzichte van het vorige. De eerste hebben we al genoemd doDisplay(). De andere is selectDigit() en wordt gebruikt om een patroon op de juiste digit te tonen. De functie selectDigit() heeft als parameter het nummer van de digit dat moet worden geselecteerd; selectDigit(1) zorgt dat de pin die hoort bij digit 1 LOW wordt. De pins van de andere digits worden HIGH zodat geen enkele LED daarvan aan kan gaan. Bedenk dat het hier gaat om de common nul kanten van de LEDs van elk van de digits. De functie doDisplay() krijgt de vier patronen mee als parameters en toont achter elkaar elk van deze patronen op hun respectievelijke digit. Daarvoor wordt selectDigit() aangeroepen en vervolgens showPattern() met het overeenkomstige patroon. Daarna volgt een delay() om ervoor te zorgen dat het patroon ook echt even zichtbaar wordt. Dit moet zich herhalen tot de gewenste displaytijd om is. Daarom zit dit alles ingepakt in een ''do while'' loop en begint de fuinctie met het vastleggen van de startijd. |
Je ziet dat de processor behoorlijk bezig is om dit display goed te laten werken. Er is nauwelijks tijd tussendoor voor metingen, berekeningen of andere belangrijke dingen. Ach, steeds een paar micro-seconden kan er nog wel af, maar als er millisecondes tussen komen ga je dat al snel zien. Ook legt het display een flink beslag op de beschikbare pins. Over beschikbare pins gesproken. Het is je misschien opgevallen dat pins 0 en 1 niet gebruikt zijn. Dat is niet voor niets. Deze pins worden impliciet gebruikt voor de seriele communicatie. Ze zijn prima bruikbaar als elke andere digitale pin, maar als je dat gaat doen kun je geen gebruik meer maken van de seriele communicatie met de PC. Of, als je dat wel doet, doen de pins wat anders dan wat het programma opgeeft. | Je ziet dat de processor behoorlijk bezig is om dit display goed te laten werken. Er is nauwelijks tijd tussendoor voor metingen, berekeningen of andere belangrijke dingen. Ach, steeds een paar micro-seconden kan er nog wel af, maar als er millisecondes tussen komen ga je dat al snel zien. Ook legt het display een flink beslag op de beschikbare pins. Over beschikbare pins gesproken. Het is je misschien opgevallen dat pins 0 en 1 niet gebruikt zijn. Dat is niet voor niets. Deze pins worden impliciet gebruikt voor de seriele communicatie. Ze zijn prima bruikbaar als elke andere digitale pin, maar als je dat gaat doen kun je geen gebruik meer maken van de seriele communicatie met de PC. Of, als je dat wel doet, doen de pins wat anders dan wat het programma opgeeft. | ||
Latest revision as of 13:31, 7 December 2020
Contents
4-Digit Segment Display
In het vorige project hebben we het 1-digit segment display behandeld. Dit display heeft 9 pootjes die aangesloten moeten worden op de Arduino. Als we nu 4 digits zouden willen aansluiten, zien we meteen dat de Arduino daar gewoonweg niet genoeg aanlsuitingen voor heeft; we zouden dan minstens 33 aansluitingen moeten hebben (de common cathode/annode kan worden gecombineerd). Om nu toch met een beperkt aantal pootjes uit te kunnen heeft men een truuk bedacht waarmee de digits snel achter elkaar aangezet kunnen worden. Het 4-digit segment display heeft, net als het 1-digit segment display, een aansluiting voor elk van de LED's a, b, c, d, e, f, g en dp (digital point). Daarnaast is de common cathode (of annode - we gaan nu uit van een common cathode) vervangen door vier aansluitingen: een voor elke digit! Laten we uitgaan van een common cathode. Elke LED heeft twee aansluitingen: de plus en de min kant. De LED brandt alleen als de plus kant hoog is en de min kant laag. In alle andere gevallen brandt de LED niet. Als de min-kant hoog is, kan de plus-kant hoog of laag zijn: de LED brandt niet. Nu heeft elke digit zijn eigen common cathode. Als die common cathode hoog is, is de hele digit uit, ongeacht de situaties van a, b, c, d, e, f, g, en dp. Als de common cathode laag is, branden de LED's van die digit volgens het patroon dat op a, b, c, d, e, f, g, en dp staat. Wat we moeten doen is dus om beurten digits selecteren met het bijbehorende patroon. Natuurlijk is elke digit dan maar een kwart van de tijd aan terwijl de Arduino driekwart van de tijd met de andere digits bezig is, maar dit kan zo snel worden afgewisseld dat de gebruiker er niets van merkt.
| Het 4 segment display met pin aansluitingen |
Net als bij het 1-digit display, heeft elke digit weer 8 LED's: drie horizontale streepjes, twee vertikale streepjes boven, twee vertikale streepjes onder en de punt. De digits zelf hebben nu echter ook een aanlsuiting. Een digit gaat aan als de betreffende aansluiting nul wordt. Een LEDje van de zo geselecteerde digit gaat aan als de betreffende pin hoog wordt.
De schakeling
Extra benodigdheden:
- 1 4-digit segment display met common cathode (= gemeenschappelijke min)
- 8 weerstanden van 180Ω-220Ω
|
| Schakeling voor 4 digit segment display |
Let op, want het zijn een heleboel draadjes die allemaal correct verbonden moeten worden. Het kan een goed idee zijn om steeds twee kleuren om en om te gebruiken: dus bijvoorbeeld blauw af te wisselen met groen. Dan worden de connecties iets minder snel verwisseld.
Een ander belangrijk ding om op te merken is dat de schakeling de pins 0 en 1 van de Arduino niet gebruikt. Op zich zijn deze pins prima bruikbaar, maar op de printplaat van de Arduino gebruikt de seriele communicatie dezelfde pins. Je kunt deze pins dus niet samen met de seriele communicatie gebruiken. Als je het wel probeert zul je merken dat je schakeling vreemde resultaten oplevert.
Het programma
Het volgende programma bevat een paar nieuwe elementen. Upload het eerst maar naar je Arduino. Het wordt hieronder in detail besproken.
byte digits[4]; // lijst met pin-nummers van de 4 digit-common annodes
byte LEDs[8]; // lijst met alle LED-pins a,b,c,d,e,f,g, en de punt
byte patronen[10]; // lijst met bit patronen voor alle cijfers, de punt, en de '-'
byte point=B00000001; // de punt
byte minus=B00000010; // de "-"
void setup()
{
// vul de tabel met aan/uit patronen voor elk van de cijfers
// "B" is de "binary formatter": B10000010 => alleen het eerste en een-na-laatste bit staan aan
// het eerste bit is voor de "a" LED, het tweede voor de "b" LED, enz. Het laatste is voor de punt
// pattern = Babcdefgp;
patronen[ 0]=B11111100;
patronen[ 1]=B01100000;
patronen[ 2]=B11011010;
patronen[ 3]=B11110010;
patronen[ 4]=B01100110;
patronen[ 5]=B10110110;
patronen[ 6]=B10111110;
patronen[ 7]=B11100000;
patronen[ 8]=B11111110;
patronen[ 9]=B11110110;
// specify pins for the common anodes (-)
digits[0] = 5;
digits[1] = 4;
digits[2] = 3;
digits[3] = 2;
// specify pins for LED cathodes (+)
LEDs[0] = 13;
LEDs[1] = 12;
LEDs[2] = 11;
LEDs[3] = 10;
LEDs[4] = 9;
LEDs[5] = 8;
LEDs[6] = 7;
LEDs[7] = 6;
// set all used pins in output mode
for (byte i=0; i<4; i++)
pinMode(digits[i], OUTPUT);
for (byte i=0; i<8; i++)
pinMode(LEDs[i], OUTPUT);
/*
// cool test patroon - met tijdmeting
unsigned long tijd=millis();
for (unsigned long i=0; i<20; i++)
{
byte patroon = B10000000;
for (byte j=0; j<6; j++)
doDisplay(patroon >> j,patroon >> j,patroon >> j,patroon >> j,50,255);
}
tijd = millis() - tijd;
Serial.begin(9600);
delay(10);
Serial.print("20 rondes kostte: ");
Serial.print(0.001*tijd);
Serial.println(" seconden");
*/
/*
// make a light go round
doDisplay(B10000000,B00000000,B00000000,B00000000,50);
doDisplay(B00000000,B10000000,B00000000,B00000000,50);
doDisplay(B00000000,B00000000,B10000000,B00000000,50);
doDisplay(B00000000,B00000000,B00000000,B10000000,50);
doDisplay(B00000000,B00000000,B00000000,B01000000,50);
doDisplay(B00000000,B00000000,B00000000,B00100000,50);
doDisplay(B00000000,B00000000,B00000000,B00010000,50);
doDisplay(B00000000,B00000000,B00010000,B00000000,50);
doDisplay(B00000000,B00010000,B00000000,B00000000,50);
doDisplay(B00010000,B00000000,B00000000,B00000000,50);
doDisplay(B00001000,B00000000,B00000000,B00000000,50);
doDisplay(B00000100,B00000000,B00000000,B00000000,50);
doDisplay(B10000000,B00000000,B00000000,B00000000,50);
*/
doDisplay(B11111111,B11111111,B11111111,B11111111,500); // turn all LEDs on for some time
doDisplay(0,0,0,0,500); // turn off all LEDs for some time
}
void loop()
{
// doDisplay(patronen[0], patronen[1] | point, patronen[2], patronen[3], 500);
// de loop
for (byte i=0; i<10; i++)
doDisplay(patronen[i % 10], patronen[(i+1)%10] | point, patronen[(i+2)%10], patronen[(i+3)%10], 500);
// "patronen[i] | point" also turns on the point for the given pattern by doing a bit-wise OR
}
void selectDigit(byte d)
{
for (byte i=0; i<4; i++)
{
if (i==d)
{
digitalWrite(digits[i], LOW); // LOW allows the flow of electrical current
}
else
{
digitalWrite(digits[i], HIGH);
}
}
}
void showPattern(byte patroon) // deze functie toont het gegeven LED patroon
{
// set all LEDs individually, depending on the bits in the given pattern
for (byte i=0; i<8; i++)
{
// "&" performs a bitwise AND on the numbers
// >> shifts 10000000 a number of bits to the right (so "10000000 >> 2" makes "00100000")
digitalWrite(LEDs[i], patroon & (B10000000>>i) );
}
}
void doDisplay(byte d0,byte d1,byte d2,byte d3,long int duration)
{ // duration in milli seconds
unsigned long start=millis();
do
{
// display all 4 patterns in quick succession
selectDigit(0);
showPattern(d0);
delay(1);
selectDigit(1);
showPattern(d1);
delay(1);
selectDigit(2);
showPattern(d2);
delay(1);
selectDigit(3);
showPattern(d3);
delay(1);
}
while (millis()-start<duration);
}
Uitleg
Het programma lijkt erg op dat van het vorige project. We hebben weer de twee lijsten voor de 8 pin-connecties van de plus-uiteindes van de LED's (byte LEDs[8];) en die voor de patronen van de 10 cijfers byte patronen[10];. Nieuw is dat we hier ook een lijst maken van de pin-connecties van de common nul-zijden van de LED's, elk voor een van de vier digits. Deze lijst heet dan ook digits[4]. Een digit staat sowieso helemaal uit als zijn common nul HIGH is. Vervolgens definieren we een paar vaste patronen, een voor de punt, een voor het minus teken, een waarbij alle LED's van een digit aan staat en een waarvoor alles uit staat.
In de setup() worden de lijsten weer van waarden voorzien en worden zowel de LEDs[] als de digits[] pins op OUTPUT ingesteld. Ook nu gaat dat weer handig met een for-loop. Dan staan er een paar delen uit (commentaar gemaakt). Hier worden bepaalde patronen op de digits gezet waarmee je kunt testen of alles goed werkt. Ach, het is vooral cool.
Ook hier is de loop() functie relatief eenvoudig. Hij heeft een for-loop waarin de functie doDisplay() wordt aangeroepen met een bepaalde set patronen en een tijdsduur. Deze functie doDisplay() laat het eerste patroon zien op de eerste digit, het tweede op de tweede digit, het derde op de derde digit en het vierde op de vierde digit. Dit wordt in een for-loop herhaald tot de gewenste display tijd om is. De patronen die de for-loop aan doDisplay() worden meegegeven zijn natuurlijk cijfers uit de lijst patronen[]. De index van de lijst wordt voor elke digit berekend met formules. Hier volgt wat uitleg:
[i % 10] // Dit is gewoon i, maar als i groter wordt dan 10 wordt er 10 afgetrokken. [(i+1) % 10] // Dit is i+1, maar als i+1 groter wordt dan 10 wordt er 10 afgetrokken. [(i+2) % 10] // Dit is i+2, maar als i+2 groter wordt dan 10 wordt er 10 afgetrokken. [(i+3) % 10] // Dit is i+3, maar als i+3 groter wordt dan 10 wordt er 10 afgetrokken.
Het teken %10 betekent modulus; n%10 is n waarvan zoveel keer 10 is afgetrokken als maar kan (zonder dat de uitkomst negatief wordt). Als i=0 gebruikt de loop dus patronen[0], patronen[1], patronen[2] en patronen[3]. Als i=1 gebruikt de loop patronen[1], patronen[2], patronen[3] en patronen[4]. En als i=9 gaat de modulus zijn werk doen en gebruikt de loop patronen[9], patronen[0], patronen[1] en patronen[2].
Dit programma heeft twee nieuwe functies ten opzichte van het vorige. De eerste hebben we al genoemd doDisplay(). De andere is selectDigit() en wordt gebruikt om een patroon op de juiste digit te tonen. De functie selectDigit() heeft als parameter het nummer van de digit dat moet worden geselecteerd; selectDigit(1) zorgt dat de pin die hoort bij digit 1 LOW wordt. De pins van de andere digits worden HIGH zodat geen enkele LED daarvan aan kan gaan. Bedenk dat het hier gaat om de common nul kanten van de LEDs van elk van de digits. De functie doDisplay() krijgt de vier patronen mee als parameters en toont achter elkaar elk van deze patronen op hun respectievelijke digit. Daarvoor wordt selectDigit() aangeroepen en vervolgens showPattern() met het overeenkomstige patroon. Daarna volgt een delay() om ervoor te zorgen dat het patroon ook echt even zichtbaar wordt. Dit moet zich herhalen tot de gewenste displaytijd om is. Daarom zit dit alles ingepakt in een do while loop en begint de fuinctie met het vastleggen van de startijd.
Je ziet dat de processor behoorlijk bezig is om dit display goed te laten werken. Er is nauwelijks tijd tussendoor voor metingen, berekeningen of andere belangrijke dingen. Ach, steeds een paar micro-seconden kan er nog wel af, maar als er millisecondes tussen komen ga je dat al snel zien. Ook legt het display een flink beslag op de beschikbare pins. Over beschikbare pins gesproken. Het is je misschien opgevallen dat pins 0 en 1 niet gebruikt zijn. Dat is niet voor niets. Deze pins worden impliciet gebruikt voor de seriele communicatie. Ze zijn prima bruikbaar als elke andere digitale pin, maar als je dat gaat doen kun je geen gebruik meer maken van de seriele communicatie met de PC. Of, als je dat wel doet, doen de pins wat anders dan wat het programma opgeeft.
Beetje spelen
We hebben al aardig wat uit de kast gehaald om deze display goed aan het werk te krijgen in een overzichtelijk programmaatje (je zou eens op Internet moeten neuzen om te zien wat voor onhandelbare programma's anderen aanbieden ter demonstratie van dit display). Als ik dit display op mijn slaapkamer zou gebruiken als klok kom ik er achter dat het display 's nachts wel erg helder is. Terwijl het overdag best helder mag zijn heb ik het 's nachts liever wat gedimd. Zouden we zo'n dim-feature ook kunnen toevoegen? Dan kunnen we ook een lichtsensor laten bepalen hoe helder de display moet zijn om hem goed te kunnen zien.
Denk er even over na hoe je dat zou doen. Ik stel me voor dat dit wat lastig is, dat vond ik ook, maar uiteindelijk heb ik wel een oplossing bedacht. Als je het leuk vind kun je ff kijken.
