Fyzikální kabinet FyzKAB

Vernier Go!Temp a Arduino Pro Mini

Dnes již definitivně dokončíme náš projekt zaměřený na vytvoření zobrazovací jednotky pro USB teploměr Vernier Go!Temp.

V minulých článcích jsme se postupně zabývali jednotlivými úskalími připojením USB teploměru Vernier Go!Temp k modulu Arduino, abychom mohli vytvořit jednoduchou zobrazovací jednotku teploty. Postupně jsme vyřešili připojení USB teploměru k modulu Arduino. Dále jsme se zabývali možností načítáním relevantních dat z teploměru i jejich prezentací na zobrazovacím displeji. Posledním krokem návrhu našeho zařízení bylo vyřešení bateriového napájení včetně monitoringu stavu použité baterie.

Výsledkem našeho snažení byl funkční prototyp sestavený z modulu Arduino UNO s USB Host Shield, připojeným OLED displejem a celé to bylo napájené dvojicí AA baterií připojenými přes step-up DC-DC měnič. Z hlediska funkčnosti máme tedy hotovo.

Nyní nám nezbývá nic jiného, než přenést celý projekt na výrazně menší platformu, aby vzniklé zařízení dosáhlo použitelné velikosti, která kupříkladu umožní vestavbu do přijatelně velké krabičky.

Arduino UNO vs. Pro Mini

Pro další vývoj našeho „Go!Temp displeje“ budeme pokračovat na platformě Arduino Pro Mini. Srovnání modulů Arduino UNO a Arduino Pro Mini zobrazuje obrázek č. 1.

Srovnání Arduino UNO a Arduino Pro Mini
Obr. č. 1 – Srovnání standardní desky Arduino UNO a vývojové desky Arduino Pro Mini.

Když už jsme se takto pustili do porovnávání velikostí, jistě se podíváme i na obrázek č. 2, kde vidíme srovnání velikostí USB Host Shieldů pro modul Arduino UNO a Arduino Pro Mini. Oba shieldy jsou navrženy tak, by šly rovnou nasadit na své moduly Arduino. Tomu odpovídají nejen rozměry shieldů, ale především rozmístění pinů. Při zmínce o pinech je dobré zdůraznit, že USB Host Shield Mini je primárně navržen pouze pro modul Arduino (Pro) Mini!

Srovnání USB Host Shield pro UNO a pro Mini
Obr. č. 2 – Srovnání USB Host Shieldu pro desku Arduino UNO a vývojovou desku Arduino Pro Mini.

Pozor na podobnost modulu Arduino Pro Mini s jinými „malými“ Arduiny. Kupříkladu někomu by se mohlo zdát, že modul Micro nebo Teensy na první pohled vypadají stejně. Ale zrada spočívá v jiném rozmístění některých pinů! Je tedy třeba si uvědomit, že v případě použití jiného modulu Arduino pak zapojení není jen záležitost pouhého zasunutí shieldu na modul (resp. modulu na shield).

Na internetu lze pochopitelně najít i zapojení, kde je USB Host Shield Mini použit i na modulu Arduino Micro nebo na modulu Teensy. Motivace je jasná, tyto moduly jsou rozměrově stejné a jsou osazeny USB konektorem s čipem pro programování. To pochopitelně zjednodušuje vývojáři práci. Všechny tyto návody na propojení modulu Arduino Micro nebo modulu Teensy s USB Host Shieldem Mini ale vyžadují úpravu hardwarovou (přepojení některých pinů pomocí drátkového spojení), nebo softwarovou (je třeba zásahu do ovládací knihovny USB Host Shield 2).

To je pro začátek trochu moc! Podobným výstřelkům se můžeme začít věnovat až ve chvíli, kdy zvládneme základ a bravurně pochopíme práci s USB Host Shieldem Mini na modulu Arduino Pro Mini, kam byl původně navržen.

Arduino Pro Mini

Vývojová deska Pro Mini je plně Arduino kompatibilní minimalizovaná vývojová deska s kontrolérem ATmega328. Má stejné funkce jako Arduino UNO a je uzpůsobená pro nepájivá pole nebo pro přímou integraci do vlastního plošného spoje. Deska obsahuje 14 digitálních vstupů/výstupů a 8 analogových vstupů. Na desce je jedna vestavěná LED dioda, která je připojena k digitálnímu pinu 13. Když je pin 13 na hodnotě HIGH, LED dioda svítí, když je pin v hodnotě LOW, je vypnutá. Rozložení a funkce jednotlivých vývodů modulu Arduino Pro Mini znázorňuje obrázek č. 3.

Arduino Pro Mini pinout
Obr. č. 3 – Rozložení pinů vývojové desky Arduino Pro Mini.

Všechny vstupy a výstupy jsou na modulu Arduino Pro Mini rozmístěné po obvodu celého modulu. Přesto je třeba zmínit, že se na trhu objevují moduly od různých výrobců. Pokud jde o rozmístění běžných pinů, neměl by hrozit problém s jejich jiným rozmístěním, ale je třeba dávat bedlivý pozor na programovací vývody daného modulu!

Už na první pohled vidíme, že modul Pro Mini neobsahuje USB konektor, je tedy nutné ho programovat pomocí FTDI programátor (USB-UART převodníku). To nám situaci komplikuje!

A ještě než se pustíme do další práce, musíme ohledně modulu Arduino Pro Mini varovat před několika důležitými fakty.

Arduino Pro Mini – 5V/16MHz vs 3,3V/8MHz

Není modul Arduino Pro Mini jako Arduino Pro Mini! Především je třeba si uvědomit, že existují dvě základní varianty a to 5V a 3,3V. Od toho se odvíjí i jejich taktovací frekvence, tedy 16 MHz a 8 MHz. My dále budeme používat modul 3,3V/8MHz, neboť USB Host Shield Mini je pro Arduino Pro Mini pracující na 3,3 V. To je trochu zvláštní, když si uvědomíme, že připojený USB teploměr Go!Temp bude z shieldu napájen a komunikovat na úrovni 5 V, ale je to tak.

Procesor ATmega168 vs. ATmega328P

Aby toho nebylo málo, číhají na nás ještě další nebezpečí! Pro začátek je třeba si uvědomit, že modul Arduino Pro Mini (stejně jako jiné moduly Arduino) může být postaven na několika různých procesorech. Široká nabídka modulů Arduino Pro Mini nám umožňuje zakoupit modul postavený na mikroprocesoru ATmega328, ale i ATmega168. S modulem postaveným na procesoru ATmega168 jsme dále prezentované zapojení nezkoušeli, takže nemůžeme říci, zda bude plně funkční. Je možné, že ano, ale při práci s USB Host Shieldem to s kompatibilitou může být tak trochu „divočina“. Doporučujeme tedy vsadit na moduly založené na procesoru ATmega328, a to (jak dále uvidíme) pouze s typem ATmega328P.

Procesor ATmega328P vs. ATmega328PB

A do třetice všech varování, je třeba ještě zmínit, že na trhu je možné koupit i modul 3,3V/8MHz postavený na novějším (a zcela přepracovaném!) procesoru ATmega328PB. I když prodejci slibují 100% kompatibilitu s modulem postaveným na procesoru ATmega328P, my takovou zkušenost v kombinaci s USB Host Shield Mini rozhodně moc nemáme! Procesor ATmega328PB se neliší jen nějakým písmenkem v názvu, má rozšířené piny pro další I²C, SPI a UART periferie, navíc obsahuje další dva 16bitové časovače, dříve jen analogové piny lze použít jako digitální, je posílena podpora pro Touch IO atd. Aby mohl být tento výkonnější čip použit v destičce Arduino Pro Mini, je svým nastavením trochu „okleštěn“, aby se choval jako slabší ATmega328P. Je otázkou, kde a kteří soudruzi udělali chybu, neboť si s tímto procesorem ne zcela dobře rozumí buď USB Host Shield Mini, nebo knihovna pro tento shield.

Každopádně zařízení postavené na modulu s procesorem ATmega328PB se při základním programování chová vcelku bezproblémově. Aplikace jako blikej LED nebo i ovládání I²C displeje funguje dobře. Ale jakmile jsme začali destičku s ATmega328PB používat s USB Host Shiel Mini, začaly problémy. Použili jsme dva moduly s procesorem ATmega328PB a oba nás trápily stejně! USB shield ne vždy hlásil připravenost, aplikace po několika minutách provozu „zamrzala“ a vůbec se nejednalo o spolehlivý projekt. Zdá se, že asi bude problém s nějakým časováním při komunikaci USB Host Shield-modul Arduino Pro Mini. Naopak při použití modulu Arduino Pro Mini s procesorem ATmega328P vše běželo zcela bezproblémově!

Arduino Mini s ATmega328P vs. ATmega328PB
Obr. č. 4 – Arduino Pro Mini s procesorem ATmega328PB a ATmega328P. Kdo pozná rozdíl?
Závěr z předchozích odstavců je tedy jasný:
Pro dále popsané a námi vyzkoušené zařízení (a jeho bezproblémovou funkčnost) je třeba použít vývojovou desku Arduino Pro Mini 3,3 V/8 MHz s procesorem ATmega328P.
Naopak od modulu s procesorem ATmega328PB (zatím?) ruce pryč!

FTDI programátor

Pokud jsme si ujasnili, že další stavba bude pokračovat na spojení modulu Arduino Pro Mini (3,3 V/8 MHz; procesor ATmega328P) a USB Host Shield Mini, budeme ještě potřebovat FTDI programátor. Ve své podstatě se jedná o doplnění chybějícího USB konektoru a obvodu pro programování desky Arduino Pro Mini. Tento modul se bude připojovat k pinům na jedné z kratších stran (vzdálenější od tlačítka Reset) modulu Arduino Pro Mini. Obrázek č. 5 a tabulka 1 znázorňuje propojení desky Arduino Pro Mini a programátoru „LaskaKit CH9102 Programmer“. Ale díky rozdílnému pořadí pinů různých programátorů (a někdy i různých desek Arduino Pro Mini!), je vždy třeba kontrolovat významy jednotlivých pinů a než obrázkem č. 5 se spíše se řídit tabulkou č. 1.

Arduino Mini a FTDI programátor LaskaKit CH9102 Programmer
Obr. č. 5 – Připojení Arduino Pro Mini k FTDI programátoru LaskaKit CH9102 Programmer.
Arduino Pro Mini   FTDI programátoru
DTR DTR
TXO RX
RXI TX
VCC VCC
GND GND
Tabulka č. 1 – Propojení pinů Arduino Pro Mini a FTDI programátoru.

Úprava USB Host Sheild Mini

Pokud si myslíme, že nyní stačí nasadit Arduino Pro Mini na USB Host Shield Mini (podobně jako vidíme na obrázku č. 6), propájet jednotlivé piny a máme vše konečně připravené ke stavbě, tak se asi dočkáme určitého zklamání.

Arduino Mini a USB Host Shield Mini
Obr. č. 6 – Spojení Arduino Pro Mini a USB Host Shield.
(USB Host Mini je dole, modul Arduino Pro Mini nahoře)

Jak již bylo naznačeno dříve, USB Host Shield Mini komunikuje s modulem Arduino Pro Mini na napěťových úrovních 3,3 V, ale připojovaný USB teploměr Vernier Go!Temp potřebuje pro svoji funkci napětí 5 V. Naštěstí se s podobnou situací již při návrhu USB Host Shield Mini asi počítalo, tak naši situaci dokáže zachránit „drobný chirurgický zákrok“.

Zatímco pin 3,3V přivádí na USB Host napětí 3,3 V, pin RAW přivádí potřebné napětí 5 V. Napájecí napětí na USB konektor je na desce plošného spoje shieldu přivedeno přes zabudovaný rezistor 2K2. Toto spojení musíme vyřadit. Na některých shieldech od „lepších“ výrobců jsou pro tento účel dokonce připravené propojovací body, které stačí propájet nebo naopak cín odsát. Ale na většině levných shieldů se takového komfortu nedočkáme. Asi nejlepší variantou je tedy přeškrábnutí vodivé cesty na plošném spoji v místě mezi rezistorem 2K2 a USB konektorem. Tím USB konektor zcela odpojíme od napájecího napětí. Nyní je třeba na USB konektor připojit požadovaných 5 V. S tímto zákrokem se tak trochu asi počítalo i na levnějších shieldech, neboť vodivá cesta je dobře přístupná a hned vedle USB konektoru je připraven pájecí bod pro možné připájení vodiče s novým napájecím napětím pro USB konektor. Tady jen opět drobné varování před různými výrobci USB Host Shieldu Mini. U některých shieldů to může vypadat trochu jinak, než na zde uvedeném obrázku č. 7. Je dobré si nejdříve celou oblast kolem rezistoru 2K2 a USB konektoru dobře prohlédnout!

Po přerušení napájecího přívodu k USB konektrou propojíme pin RAW (5V) s napájecím bodem pro USB konektor pomocí drátku (například na spodní straně plošného spoje shieldu). Celé řešení zobrazuje obrázek č. 7. Obrázek uvádí i piny, přes které modul Arduino Pro Mini komunikuje s USB Shieldem Mini. To je dobré vědět, abychom například při rozšiřování možností našeho zapojení nezkoušeli na tyto piny připojovat jiné periférie nebo čidla.

úprava USB Host Shield Mini
Obr. č. 7 – Úprava USB Host Shield Mini pro napájení USB zařízení napětím 5 V.
(nahoře schéma úpravy, dole pak její reálná realizace)

Až nyní máme vše hardwarově připravené!

Teď už nezbývá než modul Arduino Pro Mini osadit vhodným konektorem pro připojení FTDI programátoru a propájet piny spojující Adruino s USB Host Shield Mini. Asi lepší bude osadit oba moduly pinovým konektory a propojit obě desky vzájemným zasunutím – stavíme prototyp, tak určitá rozebiratelnost a možnost výměny jednotlivých částí by nebyla na škodu. 😉

Schéma zapojení

Schéma zapojení zobrazovací jednotky pro USB teploměr Vernier Go!Temp zobrazuje blokové schéma na obrázku č. 8. Napětí z dvou AA baterií je přivedeno na step-up DC-DC měnič, který vytváří napětí 5 V jednak pro modulu Arduino (které si z něj pak opět dělá potřebných 3,3 V) ale především pro napájení USB portu a k němu připojených periférií (zde USB teploměr Vernier Go!Temp). Zároveň je napětí baterií přivedeno na analogový vstup A1 modulu Arduino Pro Mini. Načítání napětí na bateriích slouží pro monitoring jejich stavu, který je pak zobrazován na OLED displeji.

Pro zobrazování naměřené teploty a stavu baterie je použit I²C OLED displej s rozlišením 128×64 px. Pro větší efekt byl použit modrý displej se žlutým zobrazovacím pruhem v horní části. Oblast žlutého zobrazování slouží jako stavový řádek, kde jsou zobrazovány stavové informace – např. stav baterie. Velká modrá plocha pak slouží pro zobrazení naměřené teploty jako hlavní informace.

Využití I²C displeje výrazně zjednodušuje propojení s modulem Arduino, neboť nám pak postačí pouze dva datové signály (SDA, SCL). Použitý OLED displej je napájen napětím 3,3 V, které je na displej přivedeno z pinu VCC modulu Arduino Pro Mini. Datová komunikace mezi displejem a modulem Arduino probíhá na 3,3 V logice, stejně jako komunikace mezi modulem Arduino Pro Mini a jeho USB Host Shield Mini.

schéma zapojení
Obr. č. 8 – Schéma zobrazovací jednotky (Arduino Pro Mini) pro USB teploměr Go!Temp.

Úprava programu pro Arduino Pro Mini

V předchozích článcích Displej pro Vernier Go!Temp pomocí modulu Arduino a Vernier Go!Temp + Arduino na 2 tužkové baterie, jsme si dokončili program projektu zobrazovací jednotky pro USB teploměr Vernier Go!Temp, který fungoval na modulu Arduino UNO. Jelikož jsme nyní použili modul Arduino Pro Mini, který je založen na stejném procesoru a má podobné funkce pinů, nemusíme v programu skoro nic měnit. Pochopitelně při překladu programu v prostředí Arduino IDE je třeba zvolit cílovou desku Arduino Pro Mini místo původního Arduino UNO!

Jediným důležitým rozdílem mezi programem pro Arduino Pro Mini a Arduino UNO je nastavení výchozích hodnoty pro monitoring napětí baterie, neboť Arduino UNO načítá analogovou hodnotu v rozmezí 0–5 V, modul Arduino Pro Mini v napěťovém rozmezí 0–3,3 V. Tato změna však vyžaduje drobnou změnu kódu na samotném začátku programu úvodních definicích. Tuto část nám znázorňuje následujcí ukázka kódu.

// stav baterie je nacitan analogovym pinem
#define ANALOGIN A1

// napajeci pro vypocet stavu baterie
#define UCC 3.21      // pro UNO 5.0 a pro MINI 3.3
#define BAT_MAX 3.0
#define BAT_MIN 0.7
//----------------------

Poznámky:
Jak již v minulém článku bylo upozorněno, v případě, že chceme měřit vstupní napětí na analogovém pinu „aspoň trochu“ přesně, doporučuje se na pinu Vcc daného modulu změřit voltmetrem skutečnou hodnotu napájecího napětí a dosadit ji v programu do definice UCC. Problém modulů Arduino spočívá v použití levných napěťových stabilizátorů, které jsou poměrně nepřesné – zvolené napětí sice stabilizují přesně na dané hladině, ale ta hladina nemusí být vždy přesně požadovaných 5 V, resp. 3,3 V. Zde například byla hodnota na Vcc naměřena jako 3,21 V.
Pozorný čtenář si jistě všiml ještě jedné změny oproti minulému programu. Tou je změna definice ANALOGIN. V minulém článku ve výpisu programu byl za vstupní pin načítající stav baterie zvolen analogový pin A0, zde (až při psaní tohoto článku jsme si všimli) je na modulu Arduino Pro Mini použit A1. Celé to vzniklo díky tomu, že obě tyto zapojení vznikala na sobě nezávisle a volba vstupního analogového pinu byla zcela na autorovi daného zapojení. Ne nadarmo se říká: „Když dva dělají totéž…“ 😒

Softwarová část

Po možná trochu rozpačitém začátku s výběrem desku Arduino Pro Mini a úpravě shieldu USB Host Mini opravdu nyní stačí pomocí FTDI programátoru nahrát níže uvedený program do modulu Arduino Pro Mini a mělo by vše běžet stejně jako na modulu Arduino UNO.

Princip programu je stejný jako v předešlých článcích. Jeho základní algoritmus vychází z vývojového diagramu zobrazeném na obrázku č. 9. Základní smyčka programu vyvolá dotaz na obsluhu USB, poté v pracovní smyčce čeká na asynchronní odpověď. V rámci této pracovní smyčky se, dokud USB zařízení nezahlásí připravenost, vykreslují na displeji čekací znaky vyhledávání. Jakmile čidlo odpoví, je zkontrolováno jeho ID a kód výrobce. Pokud se tyto parametry shodují s USB teploměřem Vernier Go!Temp, vyčkává se na stav READY, který udává, že jsou dostupná data z USB čidla. V případě dostupnosti jsou data načtená. Načtená teplota je porovnána s předešlou hodnotou, pokud se hodnoty shodují, není třeba informaci na displeji aktualizovat.

Další částí programu je kontrola přítomnosti čidla. Může se stát, že USB teploměr někdo v průběhu měření odpojí. Z tohoto důvodu je kontrolována nejen hodnota teploty, ale sleduje se i pořadové číslo naměřené hodnoty. Dokud se pořadové číslo mění, znamená to, že je USB teploměr připojený. Jakmile se hodnota nemění po dobu delší než 2 s, je situace vyhodnocena jako nepřítomnost čidla.

Poslední částí, která však ve vývojovém diagramu není zakreslena, je monitoring stavu baterie a jeho prezentace v pravém horním rohu displeje. Stav baterie je načítán vždy při překreslování displeje, obslužná procedura vrací napětí na bateriích převedené na procenta vzhledem k zadané dolní a horní mezi (0,7–3 V). Hodnoty vyššího napětí než 3 V jsou prezentovány stále jako 100 %. Napětí 0,7 V a nižší, kdy již dochází k selhávání činnosti napájecího step-up měniče, jsou již vyhodnoceny jako 0 %. Pochopitelně je opět dobré dolní mez napětí, kdy dochází k přerušení činnosti zařízení z důvodů vybití baterie, nastavit podle použitého konkrétního step-up DC-DC měniče. Tato hodnota je pak v programu nastavena opět v úvodní části deklarace konstat, konkrétně konstantou BAT_MIN (viz výpis kódu dále).

vývojový diagram programu
Obr. č. 9 – Vývojový digram programu zobrazovací jednotky pro USB teploměr Vernier Go!Temp.
Kód programu

/*
Nacitani USB teplomeru Vernier Go!Temp
(c) N.P.C. 2023
---------------------------------------
verze: BETA-4_OLED
*/

#define VERZE "1.10"
// kalibracni konstanty, Teplota = (hodnota z cidla) / SKLON - POSUN
#define SKLON 130.19
#define POSUN 0.899
// stav baterie je nacitan analogovym pinem
#define ANALOGIN A1
// napajeci pro vypocet stavu baterie
#define UCC 3.21    // pro UNO 5.0 a pro MINI 3.3
#define BAT_MAX 3.0
#define BAT_MIN 0.7
//----------------------

// knihovny pro USB Host Shield
#include <usbhid.h>    // knihovna kvuli USB Shieldu
#include <hiduniversal.h> // knihovna kvuli HID komunikaci s USB
// #include <SPI.h>    // pridani knihovny je nadbytecne, protoze si ji knihovny pro USB HOST zavolaji samy
#include "U8glib.h"    // knihovna kvuli OLED displeji

U8GLIB_SSD1306_128X64 oled(U8G_I2C_OPT_NONE);    // inicializace OLED displeje

// nasledujici cast GoTemp.h a GoTemp.cpp je prevzata z ovladace joysticku a upravena dle potreby
// (zdokomentovane jsou jen zmeni oproti originalu)
// ------ GoTemp.h --------------
struct GoTempData {      // struktura pro nacitani hodnot z USB
  uint8_t Ready;    // 1. Byte je stav 0/1 urcujici, zda je cidlo jiz ready
  uint8_t cisloVzorku;    // 2. Byte je poradove cislo vzorku (0-255)
  uint16_t Temp_RAW;    // 3. a 4. Byte jsou LO a HI hodnota odpovidajici teplote
  // zbyle Byte jsou ignorovany (nejsou pro nas potreba)
};

class GoTempEvent {
  public:
   virtual void OnGoTempChanged(const GoTempData *evt);
   static GoTempData mostRecentEvent;
};

#define RPT_GOTEMP_LEN sizeof(GoTempData)/sizeof(uint8_t)

class GoTempReportParser : public HIDReportParser {
  GoTempEvent   *GoTempEvents;
  uint8_t oldTemp[RPT_GOTEMP_LEN];
  public:
   GoTempReportParser(GoTempEvent *evt);
   virtual void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};

// ------ GoTemp.cpp --------------
GoTempReportParser::GoTempReportParser(GoTempEvent *evt) :
  GoTempEvents(evt) {}

void GoTempReportParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
  bool match = true;

  // Checking if there are changes in report since the method was last called
  for (uint8_t i=0; i    if( buf[i] != oldTemp[i] ) {
    match = false;
    break;
   }
  }
  // Calling Game Pad event handler
  if (!match && GoTempEvents) {
   GoTempEvents->OnGoTempChanged((const GoTempData*)buf);

   for (uint8_t i=0; i   }
}

GoTempData GoTempEvent::mostRecentEvent;    // (asi) potreba pro pristup z hlavniho programu (bez tohoto to nejde)

void GoTempEvent::OnGoTempChanged(const GoTempData *evt) {
  // ulozeni struktury evt, aby byla pristupna stylem: GoTempEvent::mostRecentEvent.JMENO (DULEZITE!)
  mostRecentEvent = *evt;
}

// ------ GoTemp.ino --------------
// hlavni cast programu
USB    Usb;
HIDUniversal    Hid(&Usb);
GoTempEvent    GoTempEvents;
GoTempReportParser    GoTemp(&GoTempEvents);

float Teplota = 999;    // teplota, dokud se nenacte poradna hodnota musi but stejna jako Teplota_old
float Teplota_old;    // predchozi teplota, pro kontrolu zmeny teploty
int cm;    // cislo mereni - to hlasi cidlo
int cm_old = -1;    // predchozi cislo mereni, slouzi pro sledovani zmeny cisla mereni (tj. zda je pripojen Teplomer)
int w;    // pocitadlo zobrazenych znaku pri cekani na cidlo
String LCD_vystup;    // pomocna promenna pro zaokrouhleni teploty na 1. des. misto
String hlaska[] = {"Detekce USB ...","USB nenalezeno!"};    // pokud se nedetekuje cidlo, ceka se a stridaji se dve hlasky
char znak[] = {'.',' '};    // znaky pro vykreslovani znaku pri cekani
char CekaciTecky[9];    // znakove pole pro zobrazeni tecek pri cekani
int ocasek, odraz;    // promenne pro zarovnani teploty na stred radky
int ukazatel;    // promena, ktera ukazuje do predchozich poli, co se ma zobrazovat
long int WatchDog;    // koncovy cas, po kterem (pokud se nebude měnit cm) je odpojen Teplomer
int wdInt = 2000;    // hodnota casu (2 sekundy), behem ktere se musi poradove cislo menit, jinak nekdo vytahl USB teplomer
bool logo = true;    // promenna pro zobrazeni uvodniho loga (jen prvne)

void NormalFont() {
  oled.setFont(u8g_font_unifontr);    // nastaveni znakove sady
  oled.setFontPosTop();    // nastaveni vychozich souradnic textu
}

void BigFont() {
  oled.setFont(u8g_font_fur25n);    // nastaveni velke znakove sady
  oled.setFontPosTop();    // nastaveni vychozich souradnic textu
}

void Error(String Hlaska) {
  oled.firstPage();    // zacatek naplnovani bufferu pro OLeD
  do {
   oled.setScale2x2();    // 2x zvetseni textu (i souradnic)
   oled.drawStr(9, 11, "Chyba!");    // vypis hodnoty teploty
   oled.undoScale();    // nastaveni puvodniho velikosti a rozliseni
   oled.drawStr(0, 0, Hlaska.c_str());    // vypis hlasky do nadpisu
   } while (oled.nextPage());
}

void InitSetting() {
  memset(CekaciTecky, ' ', 8);    // pole CekaciTecky jsou same mezery prazdne;
  ukazatel = 0;    // ukazatele do pole nabidky nastaven na vychozi
  w = 0;    // pocitadlo znaku pro zobrazovani cekacich znaku
  Teplota_old = 999;    // vychozi je schvalne nesmysl, aby po nacteni Teploty doslo ihned k zapisu na LCD
  GoTempEvent::mostRecentEvent.Ready = 0;    // nastavim priznak neaktivniho cidla, ono ji USB pak prepise
}

int StavBaterie() {
  float a = 100 / (BAT_MAX - BAT_MIN);
  float b = BAT_MIN * a;
  int stavBat = 0;
  int Suma = 0;
  for (int i = 1; i <= 10; i++ ) {
   int analog_value = analogRead(ANALOGIN);
   float input_voltage = (analog_value * UCC) / 1024;
   stavBat = round(a * input_voltage - b);
   if (stavBat < 0){ stavBat = 0; }
   if (stavBat > 100){ stavBat = 100; }
   Suma += stavBat;
  }
  stavBat = round(Suma / 10);
  return stavBat;
}

// =============================================== SETUP ===============================================
void setup() {
  NormalFont();
  // vypsani uvodniho loga
  oled.firstPage();    // zacatek naplnovani bufferu pro OLED
  do {
   oled.setScale2x2();    // 2x zvetseni textu (i souradnic)
   oled.drawStr(10, 9, "N.P.C.");    // logo NPC
   oled.undoScale();    // nastaveni puvodniho velikosti a rozliseni
   oled.drawStr(0, 52, "TINKERER PROJECT");    // logo maly radek
   oled.drawFrame(0, 16, 128, 33);    // ramecek
   oled.drawStr(0, 0, "Firmware");    // vypis nadpisu verze
   oled.drawStr(67, 0, "-");
   oled.drawStr(78, 0, "v.");
   oled.drawStr(96, 0, VERZE);
  } while (oled.nextPage());
  delay(1500);

  if (Usb.Init() == -1) {
   Error("USB Shield:");
   while(1);    // nekonecna smycka, ktera zastavi dalsi beh programu beh
  }

  delay(200);

  if (!Hid.SetReportParser(0, &GoTemp)) {    // nastaveni pro cteni USB ve stylu HID
   Error("HID parser:");
   while(1);    // nekonecna smycka, ktera zastavi dalsi beh programu beh
  }

  InitSetting();    // uvodni nastaveni
}

// =============================================== LOOP ===============================================
void loop() {
  Usb.Task();    // probehne asynchronni pozadavek na USB
  if (GoTempEvent::mostRecentEvent.Ready != 0) {    // USB cidlo se uz ozvalo, muzeme merit
   // nacteni hodnot z reportu USB
   logo = false;    // uz to zacalo merit, takze logo pryc a uz nikdy vice
   // cm odpovida cislu vzorku
   cm = GoTempEvent::mostRecentEvent.cisloVzorku;
   // teplota je vypocitana z hodnot HI a LO pomoci kalibracnich konstant
   Teplota = GoTempEvent::mostRecentEvent.Temp_RAW / SKLON - POSUN;

   if (Teplota != Teplota_old) {    // zmenila se hodnota teploty, je teba ji zmenit na LCD
    LCD_vystup = String(Teplota,1);    // priprava teploty ve stavru s 1 des. mistem
    LCD_vystup.replace('.', ',');

    int stavBA = round(StavBaterie()/10);

    oled.firstPage();    // zacatek naplnovani bufferu pro OLED
    do {
     BigFont();    // nastaveni velke znakove sady
     // vypocet odraz a konecnik pro zarovnani na stred a pridani znacky C
     odraz = 15*LCD_vystup.length();    // odhad velikost textu
     ocasek = odraz;    // zakladni souradnice pro znacku C
     odraz = odraz + 38;    // pridani mista pro C do delky textu
     odraz = 128 - odraz;    // okraje kolem textu
     odraz = trunc( odraz / 2);    // jeden okraj textu
     ocasek = ocasek + odraz + 16;    // pripocitani odrazu k umisteni C
     ocasek = trunc( ocasek / 2);    // prepocet na 2x vetsi Scale
     // velke cislice
     oled.drawStr(odraz, 24, LCD_vystup.c_str());    // vypis hodnoty teploty
     // znacka stupnu C
     NormalFont();    // nastaveni normalni znakove sady
     oled.setScale2x2();    // 2x zvetseni textu (i souradnic)
     oled.drawStr(ocasek + 3, 13, "C");    // vypis znacky C
     oled.undoScale();    // nastaveni puvodniho velikosti a rozliseni
     oled.drawCircle(2*ocasek, 32, 2);    // vnitrni kolecko pro znak stupne
     oled.drawCircle(2*ocasek, 32, 3);    // vnejsi kolecko pro znak stupne
     // maly nadpis
     oled.drawStr(0, 0, "TEPLOTA");    // vypis nadpisu
     // stav baterie
     oled.drawStr(86, 0, "BAT");    // popisek
     oled.drawFrame(115,2,12,10);    // oramovani
     oled.drawFrame(113,4,2,6);    // cudlik
     if (stavBA > 0) { oled.drawBox(126-stavBA,2,stavBA,10); }    // stav baterie
    } while (oled.nextPage());    // vypis bufferu na OLED

    Teplota_old = Teplota;    // ulozeni teploty pro pristi zjisteni zmeny
   }

   if (cm != cm_old) {    // pokud se meni cislo mereni, cidlo bezi a nastavuje se WatchDog
   WatchDog = millis() + wdInt;    // stale se posouva hranice, do kdy musi prijit dalsi mereni
   cm_old = cm;    // ulozeni cisla mereni pro test zmeny
   } else {    // cislo mereni je stejne jako minule, je treba otestovat, jak dlouho to jiz trva
    if ( WatchDog < millis() ) {    // cislo mereni se nemeni dele nez je zdravo - nekdo vytahl teplomer z USB
    // GoTempEvent::mostRecentEvent.Ready = 0;    // nastavim tedy priznak neaktivniho cidla a spustim cekacku jako na zacatku
    InitSetting();    // uvodni nastevni jako na zacatku - zacne uvodni hledani cidla
    }
   }

  } else {    // cidlo zatim vraci stav Ready = 0 - bud tam neni, nebo se jeste neinicializovalo

   // Test pripojeneho USB
   if( Usb.getUsbTaskState() == USB_STATE_RUNNING ) {    // uz bezi pripojene USB
    byte rcode;
    USB_DEVICE_DESCRIPTOR buf;
    rcode = Usb.getDevDescr( 1, 0, 0x12, ( char *)&buf );    // nacti jeho udaje
    if ((buf.idVendor != 2295)||(buf.idProduct != 2)) {    // ID vyrobce: Vernier -> 2295, ID cidla: Go!Temp -> 0002
     // je to pripojene jine cidlo, tak se merit nebude
     oled.firstPage();    // zacatek naplnovani bufferu pro OLED
     do {
      oled.setScale2x2();    // 2x zvetseni textu (i souradnic)
      oled.drawStr(4, 11, "Go!Temp");    // vypis hodnoty teploty
      oled.undoScale();    // nastaveni puvodniho velikosti a rozliseni
      oled.drawStr(20, 0, "Na USB neni");    // vypis nadpisu
      oled.drawLine(105, 1, 106, 0);    // carka na i
     } while (oled.nextPage());
     delay(1000);
     // GoTempEvent::mostRecentEvent.Ready = 0;
     InitSetting();
    }
   } else {    // ceka se, az se USB ozve
   CekaciTecky[w]= znak[ukazatel];
   w++;    // zapocita poradove cislo znaku
   if (w >= 9) {    // pokud se dolni radka zaplnila, zmeni se znak a jeden se znova zleva
    ukazatel = -ukazatel + 1;    // zmena ukazatele do pole nabidky
    w = 0;    // znova pocitame znaku
    logo = false;    // uvodni logo pryc, vypis hlasku problemu
   }
   if (!logo) {    // pokud se na zacatku nezorazuje logo, tak pis tecky
    oled.firstPage();    // zacatek naplnovani bufferu pro OLED
    do {
     oled.setScale2x2();    // 2x zvetseni textu (i souradnic)
     oled.drawStr(0, 10, CekaciTecky);    // vypsani pole cekacich znaku
     oled.undoScale();     // nastaveni puvodniho velikosti a rozliseni
     oled.drawStr(4, 0, hlaska[ukazatel].c_str());    // vypsani stridajici se hlasky pri cekani na cidlo
    } while (oled.nextPage());    // vypis bufferu na OLED
   }
   delay(80);    // cekacka, aby zobrazovani tecek nebyl takovy fofr
   }
  }
}

Konstrukční část

Výsledek našeho projektu můžeme vidět na obrázku 10 a to ještě ve verzi vývojového „krysího hnízda“. Na obrázku č. 11 je již celé zapojení zabudováno v krabičce (9×7×3 cm), která byla navržena přímo pro zabudování tohoto konkrétního zapojení a byla za tímto účelem zkušebně vytištěna na 3D tiskárně.

Návrh krabičky pro 3D tisk zde neuvádíme, neboť se zatím jedná o pracovní prototyp, který zatím nejen vyžaduje zapracování několika vylepšení, ale především ani není nikterak designově zdařilý. Jak vidíme, v krabičce je docela dost volného místa, což nás vede k novému celkovému rozložení jednotlivých částí. Stejně tak nás může napadnout, že zobrazovací jednotka na hlavním panelu by asi zasloužila větší displej…

Ale to je již práce pro designera. Pro nás, coby návrháře elektronické části, hlavní úkol právě skončil!

Vernier GoTemp a Arduino Pro Mini
Obr. č. 10 – Náhled na zapojení zobrazovací jednotky pro USB teploměr Vernier Go!Temp.
Zbudování zapojení do krabičky
Obr. č. 11 – Zabudování zapojení zobrazovací jednotky USB teploměr Go!Temp do vhodné krabičky

Závěr

Během několika předchozích článků věnovaných návrhu a realizaci zobrazovací jednotky pro USB teploměr Vernier Go!Temp jsme si na praktickém projektu ukázali, jak lze načítat USB výstup teploměru Go!Temp modulem Arduino. Rovněž jsme se zaměřili na to, jak lze načtené hodnoty zobrazovat na displeji, i jaká úskalí nás mohou potkat, pokud se rozhodneme náš Arduino projekt napájet z baterií.

V dnešním článku jsme vše završili tím, že jsme si ukázali, jak lze přenést daný projekt na rozměrově menší desku platformy Arduino, a to zejména jaké problémy při této cestě nás mohou potkat a co musíme vyřešit. Na obrázek č. 12 vidíme fotografii vzniklého prototypu, který je výsledkem našeho vývoje a který postupně vznikal společně touto sérií článků.

Hotové zařízení zabudované do krabičky
Obr. č. 12 – Fotografie hotového zařízení při připojení k USB teploměru Vernier Go!Temp.

Snad, kromě ukázky jedné konkrétní aplikace, jsme Vám ukázali, že je možné se pustit do jakéhokoliv elektronického projektu, který svému tvůrci aspoň trochu dává smysl. A že to někdy může být docela dlouhá, ale třeba také zajímavá práce.

Koneckonců přesně to je posláním celé vývojové platformy Arduino.

Autor článku: Miroslav Panoš

Článek je součástí následující série článků:
UPOZORNĚNÍ:
Nesouhlasíme s vyřazením Newtonových zákonů, Ohmova zákona a zákona zachování energie z učiva fyziky základních škol v České republice!