Pokud používáte Arduino máte k dispozici nepřeberné množství knihoven. Knihovna k displeji, knihovna k termistoru, knihovna k tlačítku, … Přitom se někdy jedná o poměrně jednoduché kusy kódu. Výhoda použití knihoven je jejich snadné používání – naimportuje se knihovna a pak např. pomocí jednoho řádku kódu čtete požadované parametry z čidla. Problém nastane, pokud máte třeba Arduino Micro, Nano, apod., které má menší paměť. Knihovna musí (měla by být) „blbuvzdorná“, může obsahovat funkce, které nepotřebujete apod. A onen „blbuvzdorný“ a nadbytečný kód samozřejmě zabírá část paměti.
Výhodou může potom také být, že přesně víte jak program funguje. Může se stát, že importujete několik knihoven – každá samostatně funguje, ale pokud je použijete zároveň, některá z nich nemusí fungovat. A nelze jednoduše zjistit proč.
V tomto článku bych chtěl pouze za pomoci knihovny Wire.h (knihovna pro komunikaci I2C) vyčíst data z čidla BH1750, což je čidlo intenzity osvětlení komunikující po sběrnici. Výstup z čidla je přímo intenzita osvětlení v Luxech.
Fyzická vrstva
Díky použití knihovny Wire.h není nutná přesná znalost sběrnice I2C. Jen v krátkosti vysvětlím, že se jedná o dvoudrátovou multi-masterovou sběrnici. Na vodičích SDA (data) a SCL (hodiny) je v klidovém stavu kladné napětí udržované pull-up rezistory. Oba vodiče jsou připojeny k procesoru, který hlídá napěťovou úroveň na vodiči a v případě potřeby (vysílání) je schopný vodič přes tranzistor vyzkratovat proti zemi a tím snížit jeho napětí na 0 V. V případě modulů pro Arduino jsou již potřebné rezistory integrovány přímo na modulech. To by mohl být problém při připojení více modulů ke sběrnici. Mohlo by docházet k přetěžování tranzistoru – obvod by nebyl schopný napěťovou úroveň snížit. Při použití více modulů je tedy dobré vypájet kromě jednoho ze všech modulů pull-up rezistory.
Zařízení na sběrnici jsou adresovaná. Takže master zahájí komunikaci vysláním adresy a potřebných dat. Když se v síti nachází zařízení s požadovanou adresou, tak zařízení odpoví. Adresa zařízení je udaná v datasheetu (někdy si lze zvolit mezi dvěma adresami). Na sběrnici může být až 127 zařízení, některé adresy jsou vyhrazeny pro speciální účely.
Hardware
K otestování čidla bude potřeba Arduino (je v podstatě jedno jaké) a čidlo BH1750 (doporučuji si projít datasheet), jehož cena je cca $1. Arduino s čidlem propojíme pomocí vodičů Vcc (napájení 3 až 5 V; deska obsahuje stabilizátor na 3,3 V), GND (napájení -; ke GND se vztahuje potenciál na datových vodičích), SDA a SCK. Datové vodiče se nekříží! Pull-up rezistory není třeba osazovat, modul je má již integrované – na fotce níže jsou to ty dva 10k (nápis 103).
Software
Ke komunikaci pomocí sběrnice je nutné importovat knihovnu Wire.h. Je to základní knihovna, takže by s ní neměl být problém. Knihovnu je nutné inicializovat. Dále si přidám globální proměnnou (je ji možné použít kdekoliv v programu), do které se bude ukládat intenzita osvětlení v Luxech. Vytvořím si definici pro adresu zařízení.
Adresa zařízení by měla být v datasheetu. U tohoto konkrétního čidla lze adresu změnit přivedením log. 1, nebo log. 0 na vstup ADDR.
Kód: Vybrat vše
//import knihovny pro komunikaci I2C
#include <Wire.h>
#define BH1750_ADDRESS 0x23 //adresa zařízení 23hex = 35dec (možné je použít 0x5C, nebo jiné podle datasheetu)
uint16_t lightLevel; //intenzita osvětlení v Luxech
void setup(void) {
//Inicializace knihovny
//Pokud se zadá s parametrem, je zařízení přidělena adresa
Wire.begin();
}
Po změření intenzity osvětlení je nutné si data stáhnout. Čidlo odpovídá dvěma bajty podle obrázku níže.
Je tedy nutné:
- Zahájit komunikaci na zvolené adrese (u tohoto čidla 0×23)
- Odeslat konfiguraci (zde 0×21 pro přečtení kóduv H-Res mode2)
- Ukončit komunikaci
- Počkat, dokud nebudou k dispozici data. Měření trvá cca 120 ms, max. 180 ms (čidlo odpovídá dvěma 8b bajty)
- Přečíst data a převést je na vhodný formát
- Vrátit načtenou intenzitu osvětlení
Ve funkci se definuje šestnáctibitová proměnná result. Ta má ve výchozím nastavení hodnotu 00000000 00000000 (pro přehlednost rozdělena mezerou). Prvním přečtením Wire.read(); se do proměnné uloží první, horní bajt do dolní poloviny. Řekněme, že se načtou data 11001101. Proměnná result bude mít tedy hodnotu 00000000 11001101. Poté následuje bitový posun o 8 pozic vlevo. Výsledek bude vypadat takto: 11001101 00000000. Horní bajt je v horní polovině. Je možné tedy přečíst dolní bajt. Bude přečteno třeba 11100011. Výsledek v proměnné result bude tedy 11001101 11100011. hodnota proměnné je 52707. Ta se nakonec ještě vydělí číslem 1,2 a výsledek bude 43922 (proměnná je typu integer, neukládá se desetinná část). Samotná funkce na čtení z čidla by tedy mohla vypadat takto:
Kód: Vybrat vše
uint16_t GetLightLevel() {
uint16_t result; //interní proměnná pro měření 16b proměnná
Wire.beginTransmission(BH1750_ADDRESS); //zahájení kominikace na požadované adrese
Wire.write(0x21); //odeslání příkazu k měření H-Res Mode2
Wire.endTransmission(); //ukončení komunikace
Wire.requestFrom(BH1750_ADDRESS, 2); //požadavek na dva bajty od zařízení s adresou BH1750_ADDRESS
uint32_t timeout = millis() + 180; //proměnná pro timeout - max. 180 ms
while (Wire.available() < 2) {
//dokud nejsou přijata data opakuj
if ((millis() - timeout) > 0) {
//pokud vypršel časový limit ukonči funkci a vrať číslo 0
return 0;
}
}
result = Wire.read(); //přečtení dat (horní bajt)
result <<= 8; //bitový posun o 8 bitů vlevo
result += Wire.read(); //přičtení dat (dolní bajt
result /= 1.2; //vydělení výsledku 1,2
return result; //navrácení výsledku
}
Kód: Vybrat vše
//import knihovny pro komunikaci I2C
#include <Wire.h>
#define BH1750_ADDRESS 0x23 //adresa zařízení 23hex = 35dec (možné je použít 0x5C, nebo jiné podle datasheetu)
uint16_t lightLevel; //intenzita osvětlení v Luxech
void setup() {
//Inicializace knihovny
//Pokud se zadá s parametrem, je zařízení přidělena adresa
Wire.begin();
//komunikace po sériovém portu
Serial.begin(9600);
}
void loop(){
lightLevel = GetLightLevel(); //načtení hodnoty
Serial.print(lightLevel); //vypsání na sériový port
delay(5000); //zpoždění 5 sekund před dalším načtením
}
uint16_t GetLightLevel() {
//načtení intenzity osvětlení z čidla BH1750 pouze s knihovnou Wire.h
uint16_t result; //interní proměnná pro měření 16b proměnná
Wire.beginTransmission(BH1750_ADDRESS); //zahájení kominikace na požadované adrese
Wire.write(0x21); //odeslání příkazu k měření H-Res Mode2
Wire.endTransmission(); //ukončení komunikace
Wire.requestFrom(BH1750_ADDRESS, 2); //požadavek na dva bajty od zařízení s adresou BH1750_ADDRESS
uint32_t timeout = millis() + 180; //proměnná pro timeout - max. 180 ms
while (Wire.available() < 2) {
//dokud nejsou přijata data opakuj
if ((millis() - timeout) > 0) {
//pokud vypršel časový limit ukonči funkci a vrať číslo 0
return 0;
}
}
result = Wire.read(); //přečtení dat (horní bajt)
result <<= 8; //bitový posun o 8 bitů vlevo
result += Wire.read(); //přičtení dat (dolní bajt
result /= 1.2; //vydělení výsledku 1,2
return result; //navrácení výsledku
}