Zbyšek Voda
Vytvořené odpovědi
-
AutorPříspěvky
-
Zbyšek VodaSprávce
Dobrý den,
nejsem si teď úplně jistý, ale tento modul komunikuje přes sériovou linku, že?On je problém v tom, že nahrávání programu do Arduina probíhá také přes sériovou linku a když je na ní připojeno ještě něco dalšího, bývá problém s tím, že připojená věc ruší komunikaci na lince.
U desky Arduino Mega máte výhodu, že má vícero hardwarových sériových linek (Označené RX0, TX0, RX1, TX1, …). Programování Arduina probíhá přes RX0 a TX0. Probém můžete vyřešit tím, že WiFi Modul připojíte na jinou sériovou linku, než RX0 a TX0. Pak musíte také upravit program, ale to by mělo být jednoduché 🙂
Zbyšek VodaSprávceNemáte jiný rozměr vytvářeného pole, než uvádíte v hranatých závorkách?
Podobný error hlásí iint x[2][2] = {{1,2},{2,3},{3,4}};
Když to nepomůže, pošlete kód 🙂
Zbyšek VodaSprávceNení zač, ať se daří. Jsem rád, že program funguje 🙂
Zbyšek VodaSprávceJe tam více problémů.
Jeden problém je v tzv. scope – česky tuším rozsah platnosti proměnných.
Na začátku si vytvoříte pole diody, které je globální – můžete k němu přistupovat ve všech funkcích. Potom si třeba ve funkci a vytvoříte pole diody, které je pro tuto funkci lokální. A tím zastíníte globální pole diody. Dále dojde k zavolání funkce zobraz(), ale ta nevidí to lokální pole z funkce a, ale globální pole diody definované na začátku.Kdyby se nejednalo o pole, stačilo by odebrat klíčové slovo boolean ve funkcích a pak už by se měnila hodnota globální proměnné. U pole to ale tak jednoduché není, protože nejde napsat ve funkci
diody[3][3] = {{1,1,1},{1,0,1},{1,1,1}};
.Napadají mě dvě cesty, jak to řešit.
První možnost:
Vytvoříte si několik globálních polí, která budou obsahovat požadované sekvence
Třeba:boolean v1[3][3] = {{1,1,1},{1,0,1},{1,1,1}};
a potom v jednotlivých funkcích překopírujete obsah požadovaného pole do pole diody.
memcpy(diody, v1, 9 * sizeof(boolean));
O memcopy viz zde: http://www.cplusplus.com/reference/cstring/memcpy/Druhá možnost:
Funkci zobraz() přidáte parametr typu pole, přes který vždy předáte pole do funkce zobraz. To pak můžete nechat kód tak, jak máte (lokální pole v tomto případě nevadí), jen přidáte zavolání funkce s parametrem pole: zobraz(diody).
Globální pole diody pak můžete zahodit. Tato cesta je asi schůdnějšíZbyšek VodaSprávcePošlete celý kód, takhle se nikam neposuneme.
Zbyšek VodaSprávceDobrý den, v C název proměnné nezměníte.
Můžete ale udělat dvojrozměrné pole.Místo
boolean dio1[] = {1,1,1}; boolean dio2[] = {1,0,1}; boolean dio3[] = {1,1,1};
zapište
boolean dio[3][3] = {{1,1,1}, {1,0,1}, {1,1,1}}
a potom už můžete indexovat tak, jak jste to zamýšlel:
třeba:dio[j][i]
Zbyšek VodaSprávceJestli je to opravdu problém s nepodepsanými ovladači (instalace hlásí „The third-party INF does not contain digital signature information“, nebo něco na ten způsob), tak by mohl pomoci tento postup: http://forum.arduino.cc/index.php/topic,94651.msg727588.html#msg727588
Pokud vím, tak se tento problém objevoval na Win8 a Win10. Vy máte ale Win7, ne?
Zbyšek VodaSprávceKdyž chcete vstup pro heslo, tak použijete
<input type="password" ... >
Potom se místo zanků zobrazí hvězdičky.Zbyšek VodaSprávceVe článku Programování webových rozhraní pro Arduino je v sekci Ovládání LED napsáno, jak se dá získat data z GET požadavku.
V můžete udělat HTML formulář a zvolit jako metodu přenášení dat právě GET. A potom už je to stejné, jak popisuji ve článku, jen nečtete jeden znak, ale více.
Jak udělat formulář s metodou get je popsáno třeba zde. Jen zaměníte vstup input za textarea.
Zbyšek VodaSprávceJsem rád, že se zadařilo 🙂
K tomu zápisu:
const char* json = “{\”TaskName\”:\”Voda\”,\”Temp-voda\”:21.81}”;
V C/C++ se řetězce zapisují třeba takto:
char *s = "Ahoj Karle!";
Kdybyste ale chtěl v rámci řetězce mít znak uvozovek, nemůžete to zapsat takto:
char *s = "Ahoj "Karle!"";
kompilátor by totiž měl při analýze problém a v kódy by se nevyznal.Musíte mu proto pomoct, a to právě napsáním zpětného lomítka před znak uvozovek. Tomuto se říká escapování a je díky němu možné zpasat znaky, které normálně zapsat nelze – třeba i znak s hodnotou 0 zapíšete \0. Dále jsou to třeba znak tabulátor -\t, nový řádek – \n a další – viz https://en.wikipedia.org/wiki/Escape_sequences_in_C.
Zbyšek VodaSprávceNení zač, kdyžtak se ozvěte 🙂
K té knihovně je dokumentace zde: https://bblanchon.github.io/ArduinoJson/doc/index.html
popřípadě kdybyste chtěl zabrousit i do kódu, tak mrkněte sem:
https://github.com/bblanchon/ArduinoJson/tree/master/src/ArduinoJson
ale to už je celkem zběsilé.Zbyšek VodaSprávceJeště bych doplnil Vojtu.
Funkce client.read() vrátí jeden byte (tedy i znak), který přečte z dat, které klientovi přicházejí. Vy chcete dosáhnout toho, že budete tyto přečtené znaky postupně načítat a někam ukládat.
K tomu se hodí právě pole – to je vyhrazené místo v paměti, ve kterém je možné se pohybovat pomocí indexu, tedy čísla v hranatých závorkách.
Definici pole v kódu máte:
char c[1024];
říká – v paměti bude pole složené z datového typu char a bude mít 1024 položek.Když chcete nastavit hodnotu počátečního znaku pole, provedete to následovně:
c[0] = 30;
popřípadě
c[0] = 'A';
– tímto do pole uložíte znak A (ve skutečnosti jeho číselnou hodnotu v ASCII tabulcePozor, pole v jazyce C jsou indexované od 0, tedy první prvek pole má index 0, druhý 1 a v tomto případě poslední znak má index 1023.
Pomocí cyklu while tedy budete číst znaky přicházející klientu a ukládat je do pole c. Podmínka client.available() platí, dokud jsou nějaké znaky k přečtení. Po každém průchodu navýšíte počitadlo i o jedna, tedy v dalším průchodu budete zapisovat na následující pozici v poli. Dovolil jsem si rozšířit Vojtův návrh:
int i = 0; while (client.available()) { c[i] = client.read(); i++; } c[i] = '\0' Serial.println(c); i = 0;
Na konec načtených dat jsem ještě přidal znak nula. Tímto jsem z načteného pole znaků vytvořil řetězec, tedy text. Řetězce jsou způsob, jak se dá uložit v kódu text. V jazyku C/C++ jsou uložené jako pole znaků, která jsou ukončená znakem nula. Potom funkce jako Serial.println() ví, kdy přestat s vypisováním (vypisují znak po znaku, dokud nenarazí na 0). Je možné, že i ten JSON parser, který používáte vyžaduje na vstupu validní řetězec a ten musí být ukončený nulou.
Také by možná bylo dobré do cyklu přidat podmínku, aby došlo k načtení maximálně 1023 znaků – více by se nevešlo do pole (poslední znak je právě 0). Také by bylo rozumné zvětšit velikost pole.
Napadlo mě, že budete mít ještě asi problém s HTTP hlavičkou. Přijatá data totiž neobsahují pouze JSON, který chcete parsovat, ale také HTTP hlavičku. Ta vypadá třeba takto:
HTTP/1.x 200 OK Transfer-Encoding: chunked Date: Sat, 28 Nov 2009 04:36:25 GMT Server: LiteSpeed Connection: close
Po hlavičce následují dva znaky zalomení řádku a až poté obsah web stránky – ve vašem případě pravděpodobně právě JSON. S tím se taky budete muset vypořádat 🙂
Zbyšek VodaSprávceVy přečtete znak pomocí client.read() a uložíte ho na nultý index pole c. Takto ale zapisujete všechny přečtené znaky na index 0. Nechcete spíše ten index posouvat? 🙂
Zbyšek VodaSprávceVojta má s tím prostředníkem dobrý postřeh. PHP se tu celkem nabízí.
Mohlo by to fungovat třeba tak, že po připojení ESP ke stránce s PHP skriptem by se tento skript dotázal meteostanice a dostal by JSON s informacemi. Tento JSON by se vhodně přetransformoval (na čtení jsonu je v PHP myslím přímo utilita) a do ESP už by se odeslala data v daleko jednodušší podobě – například „25;-60;1.8“.
Výhodou tohoto řešení je ulehčení zátěže procesoru. Na druhou stranu, pokud jste s PHP nikdy nedělal, asi bych se touto cestou nevydával. Můžou se totiž objevit další problémy.
Na druhou stranu, když říkáte, že programujete ESP a navíc v této poměrně jednoduché aplikaci – asi by mi nevadilo použití té JSON knihovny, kterou využíváte. U Arduina bych váhal, ale ESP má o poznání více výkonu 🙂
Měl jsem na mysli, že by JSON vypadal třeba následovně:
{ "System": { "Build": 145, "Unit": 2, "Uptime": 139, "Free Ram": 26472 }, "Sensors": { "Temp-voda": 50, "WiFi": -60, "spiral": 1.00 } }
Potom by získání jedné hodnoty ze senzoru bylo jednodušší, protože by odpadlo indexování v rámci pole.
Zbyšek VodaSprávcePodle JSON je položka „Sensors“ pole, takže vám chybí ještě jedna indexace.
root["Sensors"][0]["Temp-voda"]
Ještě je otázkou, jestli bude pořadí senzorů v poli vždy takovéto, nebo se bude měnit. V tom případě byste musel nějakým způsobem projít celé pole a najít tu položku, která má atribut „Temp-voda“.
Napadá mě jedno zlepšení – nemůžete změnit tvar toho JSON objektu? Takto je to trochu krkolomné. Mohl by vypadat třeba takto a práce s ním by byla jednodušší:
{ ... Sensors: { Temp-voda: 25, WiFi: -60, ... } }
Potom už by přečtení položky Temp-voda vypadalo tak, jak to máte v kódu.
Pokud by přidání indexu nepomohlo, máte ještě možnost projít JSON jen jako text, najít výskyt řetězce – například „Temp-voda“ a potom víte, že za dva znaky začíná hodnota.
Také by možná byla možnost se JSONu úplně vyhnout. Pokud víte, kolik celkem bude senzorů a nepotřebujete jejich počet nějak dynamicky měnit, mohl byste postupovat tak, že si určíte přesné pořadí, v jakém budete hodnoty odesílat a oddělíte je třeba středníkem. Jakmile odešlete všechny hodnoty, tak je zakončíte znakem nového řádku.
Tedy jedna sada měření může vypadat třeba následovně:
25;-60;1.80
a vy budete vědět (předem si určíte), že první hodnota odpovídá teplotě vody, druhá wifi, třetí spiral. Také budete vědět, že první dvě hodnoty jsou typu int, takže he vyčtete funkcí parseInt, třetí float, použijete tedy funkci parseFloat.
Pravděpodobně vám ale JSON chodí někde z webu, takže si tvar vybírat.
Jaký projekt stavíte? 🙂
-
AutorPříspěvky