Avtorja: Vladimir Mitrović in Robert Sedak
Email: vmitrovic12@gmail.com
V tem nadaljevanju bomo pokazali, kako si lahko pomagamo, kadar nam na Arduino UNO ploščici zmanjka svobodnih priključkov (Nadaljevanje iz št. 325*)!
Od prvega nadaljevanja vemo, da se na Arduino UNO ploščici nahaja mikrokontroler ATmega328P, ki ima 20 vhodno-izhodnih priključkov: posledično ima tudi Arduino UNO isto število vhodno-izhodnih priključkov. To je bilo več kot dovolj v vseh naših projektih, ni pa si težko zamisliti situacije, v kateri bi nam dobro prišel še kakšen priključek. V takšnem primeru nam bo pomagalo integrirano vezje kot HC595 (s polnim imenom, SN74HC595N) iz Geekcreit kompleta.
HC595
HC595 vsebuje 8-bitni pomični register, ki se bit po bit polni preko serijskega vhoda DATA IN. V trenutku, ko se na SHIFT CLK vhodu pojavi vhodna stopnica clock impulza, se bo trenutna vsebina registra premaknila za eno mesto, da bi se lahko v “osvobojen” bit prebral novi podatek z DATA IN vhoda. Pomični register ima serijski izhod QS (na katerega se lahko poveže naslednji HC595) in 8 paralelnih izhodov, QA-QH). Pomični register ni trajno povezan s paralelnimi izhodi, pač pa se podatek iz njega prenaša na izhode v trenutku, kadar se na LATCH CLK vhodu pojavi vhodna stopnica clock impulza.
V literaturi boste našli različne oznake priključkov HC595 čipa; v tekstu smo uporabili enake tistim na shemi na sliki 53. Shema hkrati kaže, kako lahko HC595 povežemo z Arduino UNO ploščico. Preostala dva krmilna priključka HC595 čipa, output enable (OE) in reset (RST), smo fiksno povezali na GND in VCC.
Ta vsebina je samo za naročnike
Program v mikrokontrolerju mora iz 8-bitnega podatka izločiti bit po bitu in jih postavljati na priključek 7. Za vsak postavljeni bit na priključku 5 mora generirati kratkotrajni pozitivni impulz, da bi HC595 lahko prebral novi bit v svoj pomični register. Po poslanih vseh 8 bitov je na priključku 6 treba generirati kratkotrajni pozitivni impulz, da bi HC595 prenesel 8-bitni podatek iz pomičnega registra na svoje paralelne izhode. Prvi poslani bit bo postavljen na izhod QH, zadnji osmi pa na QA. HC595 je zelo hiter: pri 5V napajalni napetosti je maksimalna clock frekvenca lahko višja od 10 MHz.
Shemo, ki je prikazana na sliki 53, bomo uporabili kot krmilni center za vse programske naloge iz tega nadaljevanja. Sam HC595 bomo namestili na majhno testno ploščico po risbi na sliki 54. Modro obarvane povezave vežemo na istoimenske priključke Arduino UNO ploščice. Zeleno obarvane povezave so izhodni priključki, na katere bomo povezovali ostale komponente, v skladu s postavljenimi nalogami.
Kot ilustracijo uporabe HC595 čipa bomo napravili vezje po shemi na sliki 55: katode osem svetlečih diod smo povezali preko uporov upornosti 1 kΩ na njegove paralelne izhode, medtem ko so njihove anode vezane na pozitivni pol napajalne napetosti. Čez neko LED-ico bo stekel tok in LED-ica bo zasvetila, ko bo pridruženi izhodni priključek v stanju logične ničle.
Risba na sliki 56 kaže, kako lahko postavimo LED-ice in tipke na veliko tiskano ploščico in kako jih povežemo s HC595 čipom in z Arduino UNO ploščico. Z modro barvo so obarvane povezave proti Arduino UNO ploščici, z zeleno pa povezave proti HC595 čipu na mali testni ploščici.
15.programska naloga
Napišite program “premikajoče luči” za vezje na slikah 53-56, a katerim bomo vklapljali LED-ice na naslednji način:
- na začetku programa mora svetiti samo LED-ica L1;
- dokler držimo pritisnjeno tipko T1, se morajo LED-ice vklapljati po vrsti L1>L2>…>L8, in nato ponovno od L1 proti L8;
- dokler držimo pritisnjeno tipko T2, se morajo LED-ice prižigati v obratnem vrstnem redu, od trenutno vklopljene LED-ice proti L1, in nato ponovno od L8 proti L1;
- sprememba prikaza se dogaja enkrat v sekundi.
Arduino rešitev (program Geekcreit_15.ino)
Da bi elegantno rešili to nalogo, bomo napisali lastno funkcijo za vklapljanje LED-ic; poimenovali jo bomo displayLED() in jo namestili na koncu našega programa. Funkciji damo en parameter, led vrste byte, s pomočjo katerega definiramo katero LED-ico je treba vklopiti.
V funkciji najprej definiramo polje LEDS[], v katerem opisujemo vse razporede LED-ic:
void displayLED(byte led) {
// 12345678
const byte LEDS[] = {B01111111, // L1
B10111111, // L2
B11011111, // L3
B11101111, // L4
B11110111, // L5
B11111011, // L6
B11111101, // L7
B11111110}; // L8
Prvi podatek, s indeksom 0, ustreza kombinaciji v kateri je vklopljena dioda L1, podatek z indeksom 1 ustreza kombinaciji, v kateri je vklopljena dioda L2 itd. Nato Arduino priključek, ki je vezan na LATCH CLK vhod HC595 čipa, postavljamo v stanje logične ničle:
- digitalWrite(latchPin, LOW);
- Podatke bomo poslali v pomični register HC595 čipa s pomočjo funkcije shiftOut(), ki sprejme štiri parametre:
- dataPin vrste int – priključek Arduina, ki je vezan na DATA IN vhod HC595 čipa,
- clockPin vrste int – priključek Arduina ki je vezan na SHIFT CLK vhod HC595 čipa,
- bitOrder – določa vrstni red pošiljanja bitov in
- value vrste byte – podatek, ki se pošilja v HC595.
Da bi podatke iz polja LEDS[] uskladili z načinom, na katerega so LED-ice povezane na izhode HC595 čipa, bomo podatke poslali od najmanj važnega bita (parameter bitOrder = LSBFIRST):
shiftOut(dataPin, clockPin, LSBFIRST,
LEDS[led]);
Potem, ko je funkcija shiftOut() poslala vseh 8 bitov, bomo postavili LATCH CLK vhod HC595 v stanje logične enice:
digitalWrite(latchPin, HIGH);
}
Po sprejemu tega signala bo HC595 prenesel podatke iz pomičnega registra na svoje izhode in tako vklopil ustrezno kombinacijo LED-ic.
Poglejmo sedaj, kako je napisan glavni program! Najprej bomo definirali spremenljivke z imeni komponent in ustreznimi priključki, priključke za krmiljenje s HC595 čipom in spremenljivko led, ki predstavlja indeks polja LEDS[]:
const byte T1 = 2;
const byte T2 = 3;
const byte clockPin = 5;
const byte latchPin = 6;
const byte dataPin = 7;
byte led = 0;
V funkciji setup() konfiguriramo priključka, na katera sta vezani tipki T1 in T2, kot vhodne z vklopljenimi pull-up upori in priključki za komunikacijo s HC595 čipom kot izhodne. Še bomo klicali funkcijo displayLED(), da bi “vklopili” začetno kombinacijo vključenih LED-ic:
void setup() {
pinMode(T1, INPUT_PULLUP);
pinMode(T2, INPUT_PULLUP);
pinMode(clockPin, OUTPUT);
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
displayLED(led);
}
V funkciji loop() preverjamo, ali je pritisnjena tipka T1; če je, se bomo premaknili na naslednji podatek iz tabele LEDS[], da bi ga lahko poslali v HC595 čip. Pred tem moramo preveriti, ali je trenutna vrednost indeksa led = 7, v tem primeru jo moramo vrniti na začetno vrednost 0. Novi podatek bomo poslali s pomočjo funkcije displayLED() in nato počakali eno sekundo:
void loop() {
if (digitalRead(T1) == 0) {
if (led == 7) {
led = 0;
} else {
led++;
}
displayLED(led);
delay(1000);
}
Če je pritisnjena tipka T2, delamo podoben postopek, samo sedaj po podatkih iz tabele LEDS[] se pomikamo nazaj. Tu moramo preveriti, ali je vrednost indeksa led = 0, in ga v tem primer vračamo na 7:
if (digitalRead(T2) == 0) {
if (led == 0) {
led = 7;
} else {
led–;
}
displayLED(led);
delay(1000);
}
}
HC595 in 7-segmentni displej
V naslednjem primeru bomo na izhode HC595 čipa povezali 7-segmentni displej (slika 57). Displej iz Geekcreit kompleta, 5161BS, je s skupno anodo, zato je princip vklapljanja posameznih segmentov displeja identičen vklapljanju LED-ic v vezju na sliki 55. Kako se oblikujejo številke na 7-segmentnem displeju, smo podrobno pojasnili v četrtem nadaljevanju (slika 24).
7-segmentni displej, upore in tipke bomo razporediti na veliki prototipni ploščici po risbi na sliki 58. Vsi upori imajo isto vrednost upornosti, zato niso pomembne njihove oznake, vendar pa moramo paziti na razpone priključkov – razponi se razlikujejo odvisno od pozicije posameznega upora. Pri postavljanju 7-segmentnega displeja je potrebno paziti, kako ga obrnete: decimalna pika in oznaka tipa displeja morata biti obrnjeni “proti dol”. Z modro barvo so obarvane povezave proti Arduino UNO ploščici, z zeleno pa povezave proti HC595 čipu na mali testni ploščici.
16.programska naloga
Napišite naslednji program za vezje na slikah 53, 54, 57 in 58:
- na začetku programa mora biti na 7-segmentnem displeju izpisana številka 0;
- dokler držimo pritisnjeno tipko T1 se morajo na displeju po vrsti izpisovati številke 0>1>…>9, in nato ponovno od 0 do 9;
- dokler držimo pritisnjeno tipko T2 se morajo na displeju izpisovati številke v nasprotnem vrstnem redu, od trenutno izpisane številke proti 0, in nato ponovno od 9 do 0;
- v vsakem drugem prehodu je za vsako številko potrebno izpisati tudi decimalno piko;
- sprememba prikaza se dogaja enkrat v sekundi.
Arduino rešitev (program Geekcreit_16.ino)
Rešitev je zelo podobna rešitvi predhodne naloge. Funkcijo za prikaz številk na 7-segmentnem displeju bomo poimenovali displayDigit() in jo namestiti zraven programske kode. Funkciji podamo en parameter, number vrste byte, s pomočjo katerega definiramo, katero število je treba prikazati.
Kombinacije LED-ic, ki ustrezajo številkam 0-9 definiramo v polju DIGIT[]:
void displayDigit(byte number) {
// ABCDEFG.
const byte DIGIT[] = {B00000011, // 0
B10011111, // 1
B00100101, // 2
B00001101, // 3
B10011001, // 4
B01001001, // 5
B01000001, // 6
B00011111, // 7
B00000001, // 8
B00001001, // 9
B00000010, // 0.
B10011110, // 1.
B00100100, // 2.
B00001100, // 3.
B10011000, // 4.
B01001000, // 5.
B01000000, // 6.
B00011110, // 7.
B00000000, // 8.
B00001000}; // 9.
Prvi podatek z indeksom 0 definira, katere LED-ice je potrebno vklopiti za prikaz številke 0, drugi podatek definira izgled številke 1 itd. Prvih 10 podatkov v polju opisuje izgled številk 0-9, nato sledi še 10 podatkov, ki opisujejo iste številke z vključeno decimalno piko. Tako bodo indeksi led = 0 in led = 10 naslavljali opis številke 0, vendar bo v drugem primeru poleg številke vključena tudi decimalna pika. Podatek o naslovu bomo poslali HC595 čipu na isti način kot v predhodni nalogi:
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, DIGIT[number]);
digitalWrite(latchPin, HIGH);
}
V prvem delu glavnega programa bomo definirali spremenljivke z imeni komponent in ustreznimi priključki, priključke za krmiljenje s HC595 čipom in spremenljivko number, ki predstavlja indeks polja LEDS[]:
const byte T1 = 2;
const byte T2 = 3;
const byte clockPin = 5; // SHCP (11)
const byte latchPin = 6; // STCP (12)
const byte dataPin = 7; // DS (14)
byte number = 0;
Vrednost spremenljivke number hkrati določa, katero število je treba prikazati na 7-segmentnem displeju. Funkcija setup() je prav tako enaka predhodnemu programu, samo sedaj za komunikacijo s HC595 čipom uporabljamo funkcijo displayDigit():
void setup() {
pinMode(T1, INPUT_PULLUP);
pinMode(T2, INPUT_PULLUP);
pinMode(clockPin, OUTPUT);
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
displayDigit(number);
}
Dokler je pritisnjena tipka T1 v funkciji loop() štejemo do 19, nato pa bomo nadaljevali šteti od 0:
void loop() {
if (digitalRead(T1) == 0) {
if (number == 19) {
number = 0;
} else {
number++;
}
displayDigit(number);
delay(1000);
}
Če je pritisnjena tipka T2, štejemo nazaj, vendar po 0 nadaljujemo šteti od 19:
if (digitalRead(T2) == 0) {
if (number == 0) {
number = 19;
} else {
number–;
}
displayDigit(number);
delay(1000);
}
}
Opomba: v nekaterih Geekcreit kompletih se nahajajo 7-segmentni displeji s skupno katodo, kot 5161AS ali SMA42056. Ti displeji so pin-kompatibilni z opisanim 5161BS displejem, vendar moramo vseeno napraviti določene spremembe v načinu vezave in v samem programu. Namesto na 5V, na slikah 57 in 58 moramo skupna priključka 3 in 8 povezati na GND. V programu je potrebno invertirati definicije v polju DIGIT[], kakor je prikazano v programu Geekcreit_16_ck.ino
HC595 in LCD
Shema povezave alfanumeričnega displeja z integriranim vezjem HC595 je prikazana na sliki 59, medtem ko risba na sliki 60 kaže, kako lahko postavimo LCD, potenciometer za nastavljanje kontrasta in tipke na veliko prototipno ploščico, in kako jih povežemo s HC595 čipom in z Arduino UNO ploščico. Tudi tukaj so z modro barvo obarvane povezave proti Arduino UNO ploščici, z zeleno pa povezave proti HC595 čipu na mali testni ploščici.ž
17.programska naloga
Napišite program za vezje na slikah 53, 54, 59 in 60, s katerim bomo šteli na naslednji način:
- na začetku programa, se mora na LCD-ju izpisati številka 0;
- dokler držimo pritisnjeno tipko T1, se morajo na LCD-ju po vrsti izpisovati številke 0>1>…>100, in nato od -100 do 100;
- dokler držimo pritisnjeno tipko T2 se morajo na displeju izpisovati številke v nasprotnem vrstnem redu, od trenutno izpisane vrednosti do -100, in nato ponovno od 100 do -100;
- številke se morajo izpisovati v gornji vrstici poravnane v desno;
- sprememba prikaza se dogaja vsakih 50 ms.
Arduino rešitev (program Geekcreit_17.ino)
Obstaja več knjižnic funkcij za krmiljenje alfanumeričnega displeja preko HC595 čipa; mi bomo uporabili knjižnico LiquidCrystal_74HC595 avtorja Mathias Munk Hansen, ker podpira vse funkcije iz originalne knjižnice LiquidCrystal. Zato nam bo uporaba knjižnice “poznana”. Ta knjižnica prav tako omogoča, da poljubno definiramo način, na katerega je LCD povezan s priključki HC595 čipa.
Na začetku programa definiramo uporabo knjižnice LiquidCrystal_74HC595, globalne spremenljivke z imeni komponent in ustreznimi priključki, Arduino priključke za krmiljenje HC595 čipa ter priključke HC595 čipa, ki so vezani na alfanumerični displej:
include <LiquidCrystal_74HC595.h>
const byte T1 = 2;
const byte T2 = 3;
const byte clockPin = 5; // SHCP (11)
const byte latchPin = 6; // STCP (12)
const byte dataPin = 7; // DS (14)
const byte LCD_RS = 1;
const byte LCD_E = 3;
const byte LCD_D4 = 4;
const byte LCD_D5 = 5;
const byte LCD_D6 = 6;
const byte LCD_D7 = 7;
int number = 0;
Spremenljivka number vsebuje število, ki se trenutno prikazuje na displeju. Nato definiramo objekt z imenom lcd in sočasno pridružimo komunikacijske priključke. Opazili boste, da prvi trije parametri opisujejo vezavo Adruina s HC595, ostalih 6 parametrov pa vezavo HC595 z alfanumeričnim displejem:
LiquidCrystal_74HC595 lcd(dataPin,
clockPin, latchPin, LCD_RS, LCD_E, LCD_D4,
LCD_D5, LCD_D6, LCD_D7);
V funkciji setup() konfiguriramo priključke za tipke T1 i T2 kot vhodne z vključenimi ustreznimi pull-up upori, priključke za krmiljenje HC595 čipa kot izhodne, definiramo vrsto alfanumeričnega displeja in zaženemo funkcijo displayNumber() za izpis številke na alfanumeričnem displeju.
void setup() {
pinMode(T1, INPUT_PULLUP);
pinMode(T2, INPUT_PULLUP);
pinMode(clockPin, OUTPUT);
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
lcd.begin(16, 2);
displayNumber(number);
}
Funkcijo displayNumber() bomo opisali kasneje.
Funkcija loop() je zelo podobna tisti iz predhodne naloge, s to razliko ker sedaj preverjamo, ali so dosežene vrednosti -100, oziroma 100 in kličemo funkcijo displayNumber(). Prav tako smo pohitrili štetje in sedaj menjamo prikaz na displeju vsakih 50 ms:
void loop() {
if (digitalRead(T1) == 0) {
if (number == 100) {
number = -100;
} else {
number++;
}
displayNumber(number);
delay(50);
}
if (digitalRead(T2) == 0) {
if (number == -100) {
number = 100;
} else {
number–;
}
displayNumber(number);
delay(50);
}
}
Funkcijo displayNumber() bomo postavili na koncu programa. Posredujemo ji še en parameter, number vrste int, ki določa število za izpis na LCD-ju. Opazili boste, da je v predhodnih nalogah ta parameter bil vrste byte, sedaj mora biti vrste int, ker želimo prikazovati tudi negativne številke.
V funkciji postavljamo kurzor displeja v 13. stolpec prve vrste in preverjamo, koliko praznih mest moramo dodati odvisno od števila številk v spremenljivki number in izpišemo število.
void displayNumber(int number) {
lcd.setCursor(12,0);
if (number > 99 ) {
lcd.print(“”);
} else if (number > 9) {
lcd.print(“”);
} else if (number > -1) {
lcd.print(“”);
} else if (number > -10) {
lcd.print(“”);
} else if (number > -100) {
lcd.print(“”);
}
lcd.print(number);
}
Kako poboljšati svoj Geekcreit komplet?
V tej knjižici smo predstavili Geekcreit UNO R3 starter kit, pokazali kako lahko posamezne komponente povežemo z (Arduino) UNO ploščico in napisali enostavne Arduino programe, s katerimi smo jih “oživeli”. S tem nikakor niso izkoriščene vse možnosti Geekcreit kompleta; enostavno si je zamisliti nove programske naloge, možnosti pa se bodo gotovo povečale, če obogatimo svoj komplet z nekim novim senzorjem ali modulom. Tukaj bomo omenili samo komponente, za katere smo v naših projektih ugotovili, da bi jih bilo koristno imeti tudi v osnovnem kompletu.
Povezovalnih žic nikoli ni dovolj! Poleg tistih iz kompleta si je dobro napraviti kratkostičnike kot tisti, ki smo jih opisali v 1. nadaljevanju (slika 4). Kratkostičniki so posebej uporabni za “kratke” vezave na testnih ploščicah, ko so povezave predolge.
Trimer upornosti 10 kΩ za nastavljanje kontrasta na LCD-ju, o čemer smo največ pisali v 5. nadaljevanju. Pri izbiri trimerja bodite pozorni na debelino in razpored njegovih priključkov. Ni potrebno, da je trimer posebej precizen, vendar so ravno večobratni trimerji z vijakom za nastavljanje na gornji plošči idealni za ta namen, ker imajo igličaste priključke, ki jih lahko enostavno vtaknemo na testno ploščico.
V programski nalogi v 2. nadaljevanju nismo mogli napraviti “pravega” semaforja, ker v kompletu ni rumenih LED-ic. Danes je lahko nabaviti LED-ice različnih barv in oblik. Predlagamo, da svoj Geekcreit komplet obogatite z nekaj LED-icami rumene in bele barve premera 5 mm.
V 4. nadaljevanju smo predstavili multipleksiranje in prikazali nevarnost preobremenitve izhodnih priključkov mikrokontrolerja. Z dodatkom tranzistorja se izhodna moč priključkov večkratno poveča. Slike 61-63 prikazujejo modifikacije vezij na slikah 25 in 27, na katerih smo z dodatkom tranzistorjev dobili možnost uporabe uporov manjših vrednosti upornosti in tako povečali jakost svetilnosti 7-segmentnih displejev. Včasih bi bilo koristno, da bi v kompletu imeli nekaj majhnih NPN in PNP tranzistorjev, kot sta BC547B in BC557B! V shemah na slikah 61-63 smo uporabili upore, ki jih ni v Geekcreit kompletu; dobro bi bilo, da dokupite nekaj uporov različnih vrednosti (npr. 100 Ω, 470 Ω, 2,2 kΩ, 4,7 kΩ, 10 kΩ, …).
Uživajte v programiranju!
Opomba: Programe Geekcreit_15.ino, Geekcreit_16.ino, Geekcreit_16_ck.ino in Geekcreit_17.ino lahko brezplačno dobite od uredništva revije Svet elektronike.
*Zaradi napake v uredništvu je v št. 326 izpadel pričujoči članek, zato ga objavljamo zdaj. Avtorjema in bralcem se opravičujemo!