logo_elektromys.eu

/ Krátký kurz o I2C na STM8 pro studenty SPSE |

Základní informace o I2C protokolu najdete v tomto článku.

/ Použití knihovny SWI2C |

  1. Stáhněte si aktuální knihovnu SWI2C pro STM8 ze sekce knihovny
  2. Nakopírujte soubory swi2c.h a swi2c.c do složky s vaším projektem
  3. Pokud pracujete v STVD, tak vlevo v okně "workspace" klikněte pravým tlačítkem na název vašeho projektu a zvolte add files to project. Nastavte cestu k oběma souborům a potvrďte. Oba soubory teď uvidíte zařazené v projektu.
  4. Zvolte si na které piny připojíte signály SDA a SCL (můžete připojit na libovolné dva piny mikropočítače).
  5. Zapište tuto informaci v souboru swi2c.h do čtveřice maker (SCL_GPIO, SCL_PIN, SDA_GPIO, SDA_PIN)
  6. Někde na začátku programu (typicky v main() před while()) zavolejte "inicializační" funkci swi2c_init()
  7. Vysvětlivky ke všem funkcím jsou v komentářích před každou z nich (v souboru swi2c.c)
  8. 7bitové slave adresy se všem funkcím předávají zarovnané VLEVO. Tedy má-li zařízení adresu například 0b1001000, funkcím se předává jako 0b10010000, nebo v čitelnější podobě (0b1001000<<1). A úplně nejlepší je použít makro, například #define SLV_ADDR (0b1001000<<1)
  9. Nastudujte si datasheet zařízení se kterým chcete komunikovat

/ Ukázka komunikace se teploměrem LM75 |

LM75A je široce používaný digitální teploměr s funkcí termostatu. Má "běžnou" přesnost (chyba pod +-2°C v rozsahu -25 až 100°C) a rozlišení 1/8 °C. Lze ho provozovat s napětím v rozsahu 2.8-5.5V. Komunikuje po I2C a má nízkou spotřebu. Existují různé varianty jako například:

LM75 má tři piny A0,A1,A2, které slouží ke konfiguraci slave adresy. 7-bitová slave adresa je ve formátu 1001_A2_A1_A0. Připojíte-li všechny tři piny na GND, bude adresa 1001000 a naopak připojíte-li všechny tři piny na VCC, bude adresa 0b1001111. Tímto způsobem můžete volit jednu z osmi adres, takže můžete připojit až 8 teploměrů LM75. Případně využít tuto možnost pro vyřešení kolize adres s jiným I2C obvodem. Viz tabulka 4 v datasheetu (Table 4. Address table)

Způsob komunikace se senzorem je "typický" - tedy obdobný pro řadu jiných I2C zařízení. Obvod má v sobě několik bytů paměti do kterých lze zapisovat nebo z nich číst. Funkce každé paměťové buňky je v datasheetu popsaná v tabulce 5 (Table 5. Register table) a každá má svou adresu (nezaměňovat se slave adresou) a v datasheetu ji nazývají "pointer value". Vidíme, že teplota je jen ke čtení (což je logické), tvoří ji dva bajty a je na adrese 0. Na adrese 1 je "konfigurační" registr, kterým lze nastavovat různé funkce obvodu. Adresy 2 a 3 slouží k nastavení parametrů termostatu (který ale nevyužíváme). Pro nás tedy budou zajímavé jen dvě operace. Zápis do konfiguračního registru a čtení teploty. Začneme čtením teploty.
Pro vyčtení použijeme funkci swi2c_read_buf(), konkrétní volání bude vypadat následovně:

#define LM75_SLVADDR (0b1001000<<1)
uint8_t data[2], err;
err=swi2c_read_buf(LM75_SLVADDR,0,data,2);

Makro LM75_SLVADDR slouží k čitelnému zadávání "slave adresy". Můj teploměr má piny A0,A1,A2 připojené na GND. Proměnná err slouží ke čtení návratové hodnoty funkce a nesouvisí nijak s teploměrem. Díky ní víme zda se při I2C komunikaci něco nepokazilo. Pole data[] pak slouží k uložení hodnot přečtených z LM75 a obsahuje dva byty, protože teplota je dvojbajtová. Průběh komunikace je v datasheetu zakreslen ve Fig 9. A můžete si ho prohlédnout i na oscilogramu.

Hodnoty na oscilogramu jsou vyjádřeny hexadecimálně. Adresa 0x48 tedy odpovídá 0b1001000. Surová hodnota přečtené teploty je 0x1640 (5696)
Tabulka 9 a 10 v datasheetu ukazuje jak jsou data o teplotě formátovaná. Abychom teplotu převedli na znaménkové 16bitové číslo, uděláme dva kroky. Nejprve oba bajty složíme do jednoho 16bitového čísla. Podle fig.9 z datasheetu víme že první přijatý bajt je "horní" (MSB) a druhý je "dolní" (LSB). Horní bajt tedy nejprve přetypujeme na 16bit číslo a teprve pak ho rotujeme o 8 bitů vlevo. K němu pak "přioříme" dolní bajt a vznikne 16bitové číslo přesně v podobě v jaké je v datasheetu v tabulce 9. Teplota sama o sobě je 11bitové číslo zarovnané v 16bit čísle doleva. Pro mě je ale příjemnější pracovat s číslem zarovnaným vpravo a proto ho rotuji o 5 bytů doprava.

int16_t raw_temp;
raw_temp = (((int16_t)data[0])<<8) | (int16_t)data[1];
raw_temp = raw_temp>>5;  

Teď je v raw_temp číslo, které vyjadřuje "počet osmin stupně Celsia". Já například přečetl hodnoty data[0]=22 a data[1]=192. Po složení jsem dosal hodnotu 22*256+192=5824. A po rotaci (zarovnání vpravo) hodnotu 181. Tedy 181 osmin a to odpovídá 181/8=22.625 °C. S takto vyjádřenou teplotou už můžu komfortně pracovat (sčítat, odečtítat, porovnávat atp.). Dejme tomu, že ale chcete teplotu třeba vypsat na displej, pak se vám tato podoba nehodí - uživateli bude asi prd platná informace o tom že teplota je "181 osmin °C". Takže si ji převedeme do desetinné podoby.

int16_t teplota;
teplota = (10*raw_temp+4)/8;

Po této operaci je v proměnné teplota číslo vyjadřující "počet desetin stupně Celsia". Konkrétně v našem případě (raw_temp=181) je to teplota = (10*181+4)/8 = 226. A 226 desetin °C je přece 22.6°C. Takto formátované číslo je už mnohem vhodnější pro výpis na displej. Pamatujte že celočíselné dělení neprovádí správně zaokrouhlení (zbytek po dělení se prostě zahodí). Tento problém napravuje "kouzelné" přičtení "4" v našem výpočtu. Obecně je potřeba přičíst polovinu dělence (tedy v našem případě polovinu 8).

A teď se podívejme na to jak může vypadat zápis do teploměru. Podívejte se do datasheetu na tabulku 8, kde je rozepsán význam všech bitů konfiguračního registru. Dejme tomu že chci teploměr vypnout a snížit tak jaho spotřebu. K tomuto účelu je zde bit SHUTDOWN. Zápisem hodnoty 1 se aktivuje spánek a teploměr přestane měřit teplotu. Zápisem hodnoty 0 se teploměr probudí a bude opět měřit teplotu. Ostatní bity teď nebudeme komentovat a zapíšeme do nich nulu. Shrnu-li to, potřebujeme na adresu 1 (konfigurační registr) zapsat hodnotu 1 nebo 0. Provedeme to následovně:

data[0] = 1; // shutdown zapnutý
err=swi2c_write_buf(LM75_SLVADDR, 1, data, 1); // zapsat

Příkazem swi2c_write_buf() zapisujeme 1 bajt z pole data na adresu 1 v teploměru. Do prvního bytu pole data jsme si připravili hodnotu 1, což znamená že se čip má uspat. Někoho z vás možná znervózní, proč funkci předáváme "pole" když si převezme jen jednu hodnotu. Můžeme tedy postupovat i takto:

uint8_t x = 1; // obsah conf registru, který chceme odeslat v proměnné typu byte
err=swi2c_write_buf(LM75_SLVADDR, 1, &x, 1); 

V této podobě funkci swi2c_write_buf() předáme adresu proměnné x, ve které jsou uložena data k odeslání. Funkce je napsaná tak, že vždy potřebuje adresu, ne hodnotu proměnné - a to proto aby byla schopná odesílat pole. Probudit teploměr pak můžeme stejným způsobem s tím rozdílem, že data pro konfigurační registr budou mít hodnotu 0, respektive jejich nejnižší bit bude nulový.

/ troubleshooting |

Home
| V1.10 1.6.2024 /
| By Michal Dudka (m.dudka@seznam.cz) /