V prvem nadaljevanju smo predstavili programske knjižnice za Bascom-AVR, s pomočjo katerih lahko na enostaven način nek ATtiny mikrokontroler pretvorimo v I2C slave.
Prav tako smo predstavili I2C slave modul z ATtiny85 mikrokontrolerjem in RGB diodo in za njega napisali ustrezen komunikacijski program. V tem nadaljevanju bomo opisali kako realizirati I2C slave modul z ATtiny mikrokontrolerjem iz Arduino IDE, in nato bomo predstavili ustrezne master programe za razvojni sistem Shield-A za obe platformi.
Avtorja: Vladimir Mitrović in Robert Sedak
E-pošta: vmitrovic12@gmail.com
2022-304-51
Arduino I2C slave
Arduino IDE ne podpira ATTiny takoj po instalaciji, ampak moramo instalirati dodatno podporo. Obstaja več projektov z odprto kodo. Projekt ATTinyCore avtorja Space Konde se je pokazal kot stabilen, ukazi so kompatibilni z originalnim Arduino IDE. Na strani[1] se nahajajo navodila za instalacijo. Možno je uporabiti več načinov programiranja ATTiny mikrokontrolerja: brez bootloadera ali z Optoboot ali Micronucleus bootloaderjema, ki zavzemata del spomina mikrokontrolerja. Predlagamo uporabo Arduino Uno kot ISP za programiranje ATTiny, da ne bi bilo potrebno programirati bootloader v ATTiny.
ATTinyCore ima knjižnico Wire ki uporablja USI in dela zelo zanesljivo.
Ta vsebina je samo za naročnike
Arduino rešitev programske naloge
Programska logika Arduino IDE rešitve je identična kot v Bascom-AVR. Ukaze, ki ne obstajajo v Arduino IDE, bomo napisali kot makro ukaze.
Program ATtiny85_RGB_slave_1.ino
Na začetku programa definiramo, da bomo uporabljali knjižnico Wire:
#include <Wire.h>
definiramo makro ukaze RED, GREEN in BLUE in v njih shranimo informacijo, katere priključke bomo uporabljali:
#define RED PB1
#define GREEN PB3
#define BLUE PB4
Za bolj pregleden program definiramo makro ukaz vključevanja in izključevanja zelene LEDice in Timerja0,
#define GREEN_OFF (PORTB &= ~(1 << GREEN))
#define GREEN_ON (PORTB |= (1 << GREEN))
#define STOP_TIMER0 (TCCR0B &=
~((1<<CS00)|(1<<CS01)))
#define START_TIMER0 (TCCR0B |=
(1<<CS00)|(1<<CS01))
definiramo I2C naslov “0b1111000” za ATTiny, polje v katerem bomo shranili vrednosti, ki nam jih je poslal master in katero verzijo RGB LED uporabljamo (s skupno katodo ali skupno anodo):
byte I2C_addr = 0b1111000;
volatile byte i2c_rcv_byte[3] = {0, 0, 0};
const char rgb_common_ac = ‘a’;
V funkciji setup() konfiguriramo Timer0 tako, da šteje impulze, ki jih dobi z deljenjem osnovne frekvence (16 MHz) s faktorjem 64, postavimo registre OCR0A in OCR0B v začetni strani in vključimo prekinitve:
void setup() {
cli();
TCCR0A = 0;
TCCR0B = 0;
START_TIMER0;
TCCR0B |= (1<<CS00)|(1<<CS01);
CLKPR |= (1 << CLKPCE);
CLKPR = 0;
TIFR |= (1 << OCF0A) | (1 << OCF0B);
TIMSK |= (1 << OCIE0A) | (1 << OCIE0B);
OCR0A = 0;
OCR0B = 255;
TCNT0 = 0;
sei();
Namen vsakega od teh ukazov lahko izveste iz priloženega programa, kjer je večina ukazov izdatno komentirana.
Sedaj inicializiramo I2C protokol, dodelimo I2C slave naslov zapisan v spremenljivki I2C_addr in definiramo, da se bo izvršila funkcija receiveEvent(), ko knjižnica Wire ugotovi, da I2C master pošilja podatke:
Wire.begin(I2C_addr);
Wire.onReceive(receiveEvent);
Moramo še definirati priključke, ki so vezani na RGB LEDico in izvršimo začetni demo program:
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(BLUE, OUTPUT);
rgb_demo();
} // end setup()
Ker uporabljamo funkcije prekinitve, v funkciji loop() nam ni treba imeti niti enega ukaza:
void loop() {
{
Opomnimo, da se to bistveno razlikuje od Bascom-AVR rešitve, v kateri se je I2C komunikacija spremljala v glavni programski zanki. Za krmiljenje z zeleno LEDico uporabljamo dve prekinitvi vezani na Timer0. Prva prekinitev vključuje LEDico ko timer doseže v OCR0B vpisano vrednost 255, druga prekinitev izključuje LEDico ko timer doseže vrednost vpisano v OCR0A. S spremembo vrednosti OCR0A vplivamo na trajanje stanja “vključeno” in s tem na intenziteto zelene barve.
ISR (TIMER0_COMPA_vect) {
GREEN_OFF;
} // end ISR (TIMER0_COMPA_vect)
ISR (TIMER0_COMPB_vect) {
GREEN_ON;
} // end ISR (TIMER0_COMPB_vect)
V funkciji receiveEvent() prevzemamo podatke z I2C vodila in jih shranimo v polje i2c_rcv_byte[], in nato zaženemo funkcijo execute_i2c_command():
void receiveEvent(int howMany) {
i2c_rcv_byte[0] = Wire.read();
i2c_rcv_byte[1] = Wire.read();
i2c_rcv_byte[2] = Wire.read();
execute_i2c_command();
}
// end receiveEvent(int howMany)
V funkciji execute_i2c_command() najprej preverjamo ali imamo RGB LED s skupno anodo ali katodo. Pri RGB LEDcah s skupno katodo shranjene vrednosti v polju i2c_rcv_byte[] lahko direktno uporabimo; za rdečo in modro barvo bomo uporabili ukaz analogWrite() in vrednosti iz i2c_rcv_byte[0] in i2c_rcv_byte[2], medtem ko bomo za zeleno LED vrednost iz i2c_rcv_byte[1] vpisovali v OCR0A register Timerja0. Kot tudi v Bascom-AVR rešitvi, na ta način ni možno v popolnosti izključiti zelene barve in bomo, kadar je uporabljena vrednost 0, “ročno” zaustavili Timer0 in izključili zeleno LEDico. Če uporabljamo RGB LED s skupno anodo, moramo vrednosti, ki jih dobimo od masterja, pred uporabo komplementirati, tako da shranjeno vrednost v polju i2c_rcv_byte[] odštejemo od 255:
void execute_i2c_command(){
if (rgb_common_ac == ‘a’) {
analogWrite(RED, 255-i2c_rcv_byte[0]);
if (i2c_rcv_byte[1] == 255) {
STOP_TIMER0;
GREEN_ON;
} else {
OCR0A = 255-i2c_rcv_byte[1];
START_TIMER0;
}
analogWrite(BLUE, 255-i2c_rcv_byte[2]);
} else {
analogWrite(RED, i2c_rcv_byte[0]);
if (i2c_rcv_byte[1] == 0) {
STOP_TIMER0;
GREEN_OFF;
} else {
OCR0A = i2c_rcv_byte[1];
START_TIMER0;
}
analogWrite(BLUE, i2c_rcv_byte[2]);
}
} // execute_i2c_command()
Funkcija rgb_demo() je identična kot v Bascom-AVR rešitvi: program menja intenzivnost vseh treh barv od najmanjše do največje in nato nazaj do najmanjše, kot signal, da je RGB slave modul pripravljen. Ko naredi to animacijo, funkcija nima nobenega vpliva na delo modula in je tukaj ne bomo analizirali, saj bo modul pravilno funkcioniral tudi, če jo popolnoma izpustimo. Tukaj moramo poudariti, da funkcija for v C jeziku ne bo delovala dobro, če uporabljamo 8-bitni števec in kot mejno vrednost postavimo 255 (ali 0, kadar zanka šteje navzdol). Takšno zanko moramo “ročno” dodelati, kot v funkciji rgb_demo() v priloženem programu.
Program Attiny85_RGB_slave s softversko podporo za I2C
V Adruino IDE okolju trenutno ne obstaja uradna knjižnica, ki bi podpirala softverski I2C slave način dela (knjižnica “SoftWire” podpira samo master). Zato nimamo svobodne izbire priključkov za I2C komunikacijo, ampak smo omejeni na priključke, ki so povezani z USI vezjem. S komunikacijskega vidika to ne bo predstavljalo problema, ker je hardverska rešitev hitrejša in zanesljivejša od softverske emulacije. Vendar pa lahko nekaj izgubimo na nekem drugem nivoju: tako smo v našem primeru zaradi navedene omejitve izgubili možnost hardverskega generiranja enega od treh PWM signalov.
Arduino I2C master
Kot I2C master smo uporabili razvojni sistem Shield-A postavljen na Arduino UNO. “Master” programi, ki jih bomo predstaviti, so pisani za takšno okolje, katerega shema je prikazana na sliki 5. Oznake posameznih komponent prihajajo iz Shielda-A, modro pobarvane oznake pa ustrezajo oznakam z Arduino Uno ploščice. Enako dobro bo služil kateri koli podobni razvojni sistem ali vezje, bazirano na nekem ATmega mikrokontrolerju, seveda z ustreznimi spremembami programa.
Slika 6 pokazuje kako povežemo Shield-A z RGB modulom. Na sliki so simbolično prikazane komponente Shielda-A, ki jih uporabljamo za interaktivno nastavljanje barv: alfanumerični displej, tipki SW1 in SW2 ter potenciometer RV1. S tipko SW1 izberemo barvo, s potenciometrom nastavimo njeno intenzivnost svetenja in s tipko SW2 pošljemo ustrezen ukaz RGB modulu.
Slika 7 vizualizira izbiro na alfanumeričnem displeju: oznake v gornji vrstici displeja označujejo rdečo, zeleno in modro barvo, triznakovne številke pod temi oznakami pa trenutno intenzivnost posamezne barve. Četrta številka v spodnji vrstici je odvisna od položaja potenciometra RV1; z vrtenjem njegove osi od enega do drugega skrajnega položaja, se prikazana vrednost menja v razponu 0-255, prav tako kot nam ustreza za intenzivnost ene od barv.
Barvo, katere intenzivnost nastavljamo, izberemo s pomočjo tipke SW1z naslednjim vrstnim redom:
niti ena -> rdeča -> zelena -> modra -> vse tri -> niti ena
To je na sliki 7 prikazano z rdečimi puščicami, oznaka trenutno izbrane barve je na displeju izpisana z velikimi črkami. Ko izberemo eno od barv in s potenciometrom nastavimo želeno intenzivnost, ga s pritiskom na tipko SW2 vpišemo pod oznako barve (to je na sliki 7 prikazano z modrimi puščicami) in preko I2C vodila pošljemo ustrezen ukaz RGB modulu. Strukturo teh ukazov smo opisali v predhodnem nadaljevanju. Z vrtenjem osi potenciometra RV1 lahko po volji nastavljamo intenzivnost izbrane barve, vendar se bo prikaz na LCDju spremenil in ukaz RGB modulu poslal šele po pritisku na tipko SW2.
Če držimo tipko SW2 pritisnjeno dalj od ene sekunde, se program prestavi v avtomatski način dela (spodnja vrstica na sliki 7): v gornjem desnem vogalu displeja se izpisuje oznaka “auto”, program pa vsakih 50 ms prebere napetost na drsniku potenciometra RV1, ga preračuna v intenzivnost, ažurira intenzivnost izbrane barve (ali vseh barv) in pošlje ustrezen ukaz RGB modulu. Obračanje osi potenciometra RV1 se odrazi v trenutni spremembi prikaza na LCDju in barve RGB diode na RGB modulu. V “ročni” način dela se vračamo s kratkim pritiskom na tipko SW2.
Bascom-AVR rešitev: program Shield-A_RGB_master.bas
Program uporablja naslednje spremembe:
- Rd, Gn in Bl vsebujejo trenutno intenzivnost rdeče, zelene in modre barve.
- Adc_value vsebuje trenutno branje A/D pretvornika
- Rgb_value služi za oblikovanje prikaza numeričnih vrednosti na LCDju
- Rgb_index določa izbrano barvo in prikaz na LCDju (0 = nobena barva, 1 = rdeča, 2 = zelena, 3 = modra, 4 = vse barve)
- Auto_flag določa način dela (0-100 = ročni, >100 = avtomatski)
Na začetku programa definiramo I2C naslov slave mikrokontrolerja, kateremu bo master pošiljal sporočila
Const I2c_address = &B11110000
in nato tudi hitrost I2C komunikacije ter SCL in SDA priključke:
$lib “i2c_twi.lbx”
Config Twi = 100000 ‘SCL = 100kHz
Config Sda = Portc.4
Config Scl = Portc.5
I2cinit
S tem, ko smo vključili I2C_TWI.lbx knjižnico, smo Bascom-AVRju omogočili da namesto standardne softverske emulacije uporablja TWI vezje ATmega328P mikrokontrolerja. Njegova SDA in SCL priključka sta priključena na priključke PC4 in PC5, in smo to morali upoštevati v konfiguracijskih ukazih. Izbrali smo standardno hitrost komunikacije 100 kHz.
A/D pretvornik bomo konfigurirati tako, da kot referenčno napetost uporablja napetost napajanja:
Config Adc = Single , Prescaler = Auto ,
Reference = Avcc
Zato se bo polni razpon A/D pretvorbe (0-1023) pokril z vrtenjem osi potenciometra RV1 od enega do druge skrajnega položaja. Še bomo na običajni način konfigurirali LCD in vhodne priključke PC1 in PC2, nakar vstopimo v glavno Do-Loop zanko. V njej vsakih 50 ms preverjamo stanja tipka SW1 in SW2 ter izvršujemo podprogram Disp_adc in če je izbran avtomatski način dela, tudi podprogram Disp_send:
Do
Debounce Pinc.1 , 0 , Sw1_sub , Sub
Debounce Pinc.2 , 0 , Sw2_sub , Sub
Gosub Disp_adc
If Auto_flag > 100 Then
Gosub Disp_send
End If
Waitms 50
Loop
V podprogramu Disp_adc merimo napetost drsnika potenciometra RV1, delimo izmerjeno vrednost s 4 (tako smo dobili razpon vrednosti 0-255), in jo prikazujemo na LCDju:
Disp_adc:
Adc_value = Getadc(0)
Adc_value = Adc_value / 4
Locate 2 , 13
Rgb_value = Str(adc_value)
Rgb_value = Format(rgb_value , “000”)
Lcd Rgb_value
Return
Odvisno od vsebine spremembe Rgb_index, v podprogramu Disp_send najprej ažuriramo intenziteto trenutno izbrane barve ali barv,
Disp_send:
If Rgb_index = 1 Then
Rd = Adc_value
Elseif Rgb_index = 2 Then
Gn = Adc_value
Elseif Rgb_index = 3 Then
Bl = Adc_value
Elseif Rgb_index = 4 Then
Rd = Adc_value
Gn = Adc_value
Bl = Adc_value
End If
in nato naslavljamo RGB modul in mu pošljemo trenutno nastavljene intenzitete vseh treh barv:
I2cstart
I2cwbyte I2c_address
‘ Waitms 1
I2cwbyte Rd
I2cwbyte Gn
I2cwbyte Bl
‘ Waitms 1
I2cstop
Waitms ukazi so potrebni samo če slave potrebuje več od 2 µs za obdelavo naslova oziroma podatkov, ki mu jih je master poslal. Program našega RGB modula je dovolj hiter, zato so Waitms ukazi zakomentirani. Bascom-AVR postavlja sistemski Err bit, če je prišlo do napake v komunikaciji (npr., če slave ni odgovoril z ACK po vsakem prejetem bajtu). Preverili bomo Err bit in če je detektirana napaka, bomo izpisali ustrezno sporočilo:
If Err = 1 Then
Locate 2 , 1
Lcd “Err ”
Waitms 250
Err = 0
End If
Na koncu podprograma bomo na LCDju izpisali trenutne intenzitete barv in se vrnili v glavno zanko:
Gosub Disp_rgb
Return
Isti podprogram kličemo tudi ko program detektira da je pritisnjena tipka SW2,
Sw2_sub:
Gosub Disp_send
nato merimo, kako dolgo je tipka bila pritisnjena:
For Auto_flag = 0 To 100
If Pinc.2 = 1 Then Exit For
Waitms 10
Next
Če je tipka bila pritisnjena več kot 1 s, bo vrednost števca Auto_flag bila 101 in program gre v avtomatski način dela; če je pritisnjena krajši čas, se program vrača v ročni način dela. Sporočilo o trenutno veljavnem načinu dela se izpisuje na LCDju, nakar se program vrača v glavno zanko:
Locate 1 , 13
If Auto_flag > 100 Then
Lcd “auto”
Else
Lcd “”
End If
Return
Kot smo prej pokazali, se vrednost spremembe Auto_flag preverja tudi v glavni zanki in se, če je avtomatski način dela aktiviran, RGB modulu pošlje sporočilo vsakih 50 ms. V nasprotnem primeru se bo sporočilo poslalo samo kadar pritisnemo tipko SW2, tako, kot je v programski nalogi tudi predvideno.
Podprogram Sw1_sub se izvršuje vsakič, ko pritisnemo tipko SW1. V njemu menjamo vrednost spremembe Rgb_indeks v razponu od 0 do 4, in s tem izberemo novo barvo v skladu s programsko nalogo in prikazom na sliki 7. Ta podprogram in druge dele master programa, ki nimajo direktnega stika z osnovnim namenom, tukaj ne bomo analizirali.
Program Shield-A_RGB_master.ino
Uporabili bomo identične spremembe in programsko logiko kot v Bascom-AVR rešitvi.
Na začetku programa definiramo knjižnice, ki jih bomo uporabljali in deklariramo funkcijo debounce(), ki jo bomo kasneje tudi definirali.
#include <Wire.h>
#include <LiquidCrystal.h>
void debounce(byte, byte, void (*)());
Definiramo objekt s pomočjo katerega krmilimo LCD in potrebne spremembe:
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
byte rd, gn, bl, rgb_index, auto_flag;
const byte I2c_address = 0b1111000;
int adc_value;
V funkciji setup() bomo vključili osvetlitev ozadja s pomočjo tranzistorskega stikala T2, definirali priključke tipke, zagnali I2C komunikacijo, definirali kateri LCD displej uporabljamo, definirali začetno vrednost spremembe rgb_index in zagnali funkcijo sw1_function() da bi prikazali vrednosti spremenljivk na displeju.
void setup() {
pinMode(17, OUTPUT);
digitalWrite(17, HIGH);
pinMode(A1, INPUT_PULLUP);
pinMode(A2, INPUT_PULLUP);
Wire.begin();
lcd.begin(16, 2);
rgb_index = 4;
sw1_function();
} // end setup()
V funkciji loop() vsakih 50 ms preverjamo stanja tipk SW1 in SW2 in izvršujemo podprogram disp_adc(). Če pa je izbran avtomatski način dela, pa tudi podprogram disp_send():
void loop() {
debounce(A1, 0, sw1_function);
debounce(A2, 0, sw2_function);
disp_adc();
if (auto_flag > 100) disp_send();
delay(50);
} // end loop()
V funkciji disp_adc() merimo napetost drsnika potenciometra RV1, delimo izmerjeno vrednost s 4 (tako smo dobili razpon vrednosti 0-255), in jo prikažemo na LCDju:
void disp_adc(){
adc_value = analogRead(A0)/4;
lcd.setCursor(12,1);
if (adc_value < 100) lcd.print(“0”);
if (adc_value < 10) lcd.print(“0”);
lcd.print(adc_value);
} // end disp_adc()
V funkciji disp_send(), odvisno od vsebine spremembe rgb_index, najprej ažuriramo intenziteto trenutno izbrane barve ali barv,
void disp_send(){
switch(rgb_index){
case 1:
rd = adc_value;
break;
case 2:
gn = adc_value;
break;
case 3:
bl = adc_value;
break;
case 4:
rd = adc_value;
gn = adc_value;
bl = adc_value;
break;
}
disp_rgb();
send_rgb();
} // end disp_send()
nato prikažemo vsebino barv na displeju s pomočjo funkcije disp_rgb()
void disp_rgb(){
lcd.setCursor(0,1);
if (rd < 100) lcd.print(“0”);
if (rd < 10) lcd.print(“0”);
lcd.print(rd);
lcd.setCursor(4,1);
if (gn < 100) lcd.print(“0”);
if (gn < 10) lcd.print(“0”);
lcd.print(gn);
lcd.setCursor(8,1);
if (bl < 100) lcd.print(“0”);
if (bl < 10) lcd.print(“0”);
lcd.print(bl);
} // end disp_rgb()
in pošljemo podatke preko I2C protokola s pomočjo funkcije send_rgb():
void send_rgb(){
Wire.beginTransmission(I2c_address);
Wire.write(rd);
Wire.write(gn);
Wire.write(bl);
Wire.endTransmission();
} // end send_rgb()
Ko program detektira, da je pritisnjena tipka SW2, najprej merimo, kako dolgo je tipka bila pritisnjena:
void sw2_function(){
for (auto_flag = 0; auto_flag <= 100; auto_flag++){
if (digitalRead(A2) == 1) {
break;
}
delay(10);
}
Če je tipka bila pritisnjena več kot 1 s, bo vrednost števca auto_flag biti 101 in program preide v avtomatski način dela; če je pritisnjena krajši čas, se program vrača v ročni način dela. Sporočilo o trenutno veljavnem načinu dela se izpisuje na LCDju, nakar se program vrača v glavno zanko:
lcd.setCursor(12,0);
if (auto_flag > 100) {
lcd.print(“auto”);
} else {
lcd.print(“”);
}
disp_send();
} // end sw2_function()
Funkcija sw1_function() se izvršuje vsakič, ko pritisnemo tipko SW1, algoritemsko je identična rešitvi za Bascom-AVR in je tukaj ne bomo analizirali.
Za tiste, ki želi vedeti več
Arduino IDE okolje nima definirane funkcije debounce(), zato jo bomo sami napisali po opisu iz dokumentacije za Bascom-AVR. Funkcija v razmaku 25 ms dvakrat preveri, ali je tipka pritisnjena, da bi odstranila “lažno” branje zaradi nepopolnosti mehanskih stikal. Funkcija prav tako spremlja, če je tipka spuščena in bo pridruženo funkcijo naslednjič izvršila šele, ko spustimo in ponovno pritisnemo tipko.
V našem programu spremljamo dve tipki, SW1 in SW2, ki sta povezani na Arduino priključke A1 (= 15) i A2 (= 16). Zaradi enostavnosti bomo napisali funkcijo, ki je uporabna samo za priključke A1-A5:
void debounce(byte pin, byte pin_state, void (*function)()){
static uint8_t allpinsstate = 0;
uint8_t pinshift = pin-14;
if (digitalRead(pin) == pin_state) {
delay(25);
if (digitalRead(pin) == pin_state) {
if (!((allpinsstate & (1 << pinshift)) >> pinshift)){
function();
allpinsstate |= (1<< pinshift);
}
}
} else {
delay(25);
if (digitalRead(pin) != pin_state) {
allpinsstate &= ~(1 << pinshift);
}
}
}
Tako napisana debounce() funkcija v popolnosti ustreza postavljenim zahtevam vendar poudarjamo, da ne bo primerna za digitalne priključke 0-13!
* * *
Slika 8 potrjuje, da opisani programi delajo tudi v realnosti :)! No, ko že vse tako dobro dela, moramo še preveriti, kaj se bo zgodilo, če s Shielda-A snamemo alfanumerični displej in namesto njega povežemo I2C LCD (slika 9)! Takrat v Bascom-AVR programu delamo konfiguracijo displeja na naslednji način:
Config Lcd = 16 * 2
$include “I2CLCD.sub”
Lcd$init &B1111
Standardni konfiguracijski ukazi LCDa, Config Lcdbus in Config Lcdpin, nam niso več potrebni, z vključenjem knjižnice I2CLCD.sub smo vse Bascomove ukaze za delo z LCDjem preusmerili I2C LCDju. Konstanta &B1111 v Lcd$init ukazu ustreza I2C LCD modulu s PCF8574A čipom in vsi trije naslovni priključki v stanju “1” (slika 9 zgoraj desno). Knjižnica I2CLCD.sub je funkcionalno identična knjižnici PCF8574_LCD$SE.sub, o kateri smo podrobno pisali v Svetu elektronike 262, v okviru Arduino serije.
V Arduino IDE je možno za krmiljenje I2C LCDjem instalirati knjižnico “LiquidCrystal I2C”. Ta knjižnica ima iste ukaze kot tudi knjižnica “LiquidCrystal” in zato bomo imeli samo nekaj sprememb v programu. Za instaliranje knjižnice je potrebno izbrati padajoči meni “Tools->Manage Libraries…” kot je prikazano na Sliki 10. Z izborom padajočega menija se prikaže dodatno okno “Library Manager” (slika 11). V gornjem desnem polju vpisujemo ključne besede “liquidcrystal i2c” za filtriranje spiska knjižnic. Iskano knjižnico bomo našli na sredini spiska; postavimo kazalnik miške na trak z opisom knjižnice in kliknemo na virtualno tipko “Install”. Po instalaciji zapremo okno s klikom na virtualno tipko “Close”.
Program bomo začeli z navajanjem knjižnic, ki jih bomo uporabljali:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
Za razliko od Bascom knjižnice, knjižnica LiquidCrystal_I2C ustvari zasebne objekte in zato ni možno definirati I2C naslova LCDja v spremenljivki, da bi z njeno pomočjo krmilili z LCDji. Zato bomo definirali objekt za LCD in ga poimenovali “lcd”:
LiquidCrystal_I2C lcd(0x27,16,2);
Sočasno smo navedli tudi kateri I2C naslov uporabljamo za ta objekt in vrsto displeja. Ostane nam še, da v funkciji setup() inicijaliziramo objekt lcd, in vključimo osvetlitev ozadja s pomočjo funkcije backlight():
lcd.init();
lcd.backlight();
S temi ukazi smo zamenjali “standardne” ukaze za konfiguracijo LCDja in vklop osvetlitve ozadja s pomočjo tranzistorskega stikala T2, in zato jih več ne potrebujemo:
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
…
pinMode(17, OUTPUT);
digitalWrite(17, HIGH);
…
lcd.begin(16, 2);
Ostali ukazi so identični.
Opomba: Programe ATtiny85_RGB_slave_1.ino, Shield-A_RGB_master.bas, Shield-A_RGB_master.ino, Shield-A_RGB_master_2.ino in knjižnico I2CLCD.sub lahko brezplačno dobite od uredništva revije Svet elektronike!
Viri:
https://github.com/SpenceKonde/ATTinyCore
ATtiny85_RGB_slave_1