mylms

... web o elektronice


Komunikace s čidlem přes I2C bez použití knihovny

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í specializovaných a jednoúčelových 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.

 

arduino-i2c-sensor-4

Takto může vypadat načítání z čidel přes sběrnici I2C – čas a datum, teplota, vlhkost, intenzita osvětlení



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.

 

arduino-i2c-sensor-6

Schéma sběrnice I2C

 

arduino-i2c-sensor-7

Zapojení I/O sběrnice I2C

 

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).

 

arduino-i2c-sensor-5

 

 

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.

 

arduino-i2c-sensor-1

Adresace čidla

 

//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();
}

 

 

Dále se vytvoří jedna funkce, jejíž návratová hodnota bude intenzita osvětlení. V té bude nutné začít komunikovat na zadané adrese. Čidlu se odešle konfigurace, počká se, než dojde ke změření intenzity osvětlení. Jak je vidět na obrázku níže, lze čidlo konfigurovat několika příkazy. Lze si vyžádat různé náměry (podle přesnosti se mění doba měření) a lze změnit i čas měření. Instrukce jsou ve dvojkové soustavě, pro přehlednost je dobré si je převést na hexadecimální tvar (lze k tomu použít kalkulačku ve Windows, přepnutou do programátorského režimu). Kód pro jedno přečtení informace v H-Res Mode2 by byl 0×21.

 

arduino-i2c-sensor-2

 

Po změření intenzity osvětlení je nutné si data stáhnout. Čidlo odpovídá dvěma bajty podle obrázku níže.

 

arduino-i2c-sensor-3

 

Je tedy nutné:

  1. Zahájit komunikaci na zvolené adrese (u tohoto čidla 0×23)
  2. Odeslat konfiguraci (zde 0×21 pro přečtení kóduv H-Res mode2)
  3. Ukončit komunikaci
  4. Počkat, dokud nebudou k dispozici data. Měření trvá cca 120 ms, max. 180 ms (čidlo odpovídá dvěma 8b bajty)
  5. Přečíst data a převést je na vhodný formát
  6. 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:

 

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
}

 

 Funkce je hotová. Lze ji tedy kdykoliv zavolat. Lze si samozřejmě měnit adresu a parametr načítání. Ale v praxi ani není potřeba ho často měnit. Tím se ušetří část kódu, který musí v knihovně být. Program pro načítání dat z čidla a jeho odesílání na sériový port by mohl vypadat takto..

//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
}

 

 Komunikace s jinými čidly je v podstatě stejná. Podle datasheetu se zjistí jaké příkazy je nutné odesílat a v jakém formátu data chodí. Pokud jde o větší čísla, nebo čísla s desetinnými místy je nutné je převést. Doporučuji si projít článek o proměnných, abyste věděli jaké číslo lze do jaké proměnné vložit. Také bude dobré si přečíst článek o bitovém posunu.



Napsal Petan před třemi týdny v kategorii Elektronika. Připojeno 0 komentářů.
Přečteno 135x.

Na programy zde poskytované není žádná záruka na funkčnost (viz licence). Jednotlivé články, stejně jako celý obsah stránek není návodem a slouží pouze k studijním účelům. Zapojení výše mají pouze informativní charakter! Vždy se řiďte originálním návodem k použití! Na elektrickém (vyhrazeném) zařízení smí pracovat pouze osoba s příslušnou kvalifikací dle vyhlášky 50/78 Sb! Vše tedy děláte na vlastní nebezpečí! Autor stránek nebere žádnou zodpovědnost za případné újmy na zdraví, životě, majetku a jiné!

Jakékoliv části webu je zakázáno bez svolení autora a uvedení zdroje publikovat! Některé části článků mohou obsahovat texty, případně obrázky ze stránek Wikipedia a Wikimedia Commons. Tyto části jsou dostupné pod původní licencí Creative Commons.



Doposud nebyl připojen žádný komentář. Buďte první!

Připojte váš komentář!

* Hvězdičkou jsou označena povinná pole. Autor stránek odpovídá vždy do komentáře.