Zbyšek Voda
Vytvořené odpovědi
-
AutorPříspěvky
-
Zbyšek VodaÚčastník
Dobře, díky. Původně jsem myslel, že jde o konflikt pinů, ale tím to asi není.
Kód pro ten enkodér mi přijde podivný, ale jestli vám to takto funguje samotné, tak OK.Problém bude v tom, že funkce knihovny pro obsluhu displeje (u8g.firstPage(), draw()…) vždy nějakou dobu trvají. Ony si vlastně seberou procesor pro sebe a ten pak nezjišťuje, jestli melete enkodérem – to zjišťuje až ve chvíli, kdy přijde řad na funkce digitalRead() apod..
Vy tedy musíte nějak zajistit, aby procesor změny na pinech z enkodéru neignoroval. Pro tento účel se používá tzv. přerušení (anglicky interrupt) – na pinech, na kterých máte enkodér připojený si nastavíte přerušení a při změně těchto pinů dojde k donucené obsluze tohoto přerušení – takže pohyby enkodérem procesor nebude přehlížet.
O přerušeních se můžete dočíst více zde. Musíte si dát pozor na to, abyste použil piny, které přerušení podporují – u UNO jsou to piny 2 a 3. Také pozor na to, že se přerušení nastavují pomocí jejich čísla a ne čísla pinu. Ke správnému zjištění čísla přerušení z čísla pinu slouží funkce digitalPinToInterrupt(interruptPin).
Potom samotné použití přerušení s enkodérem je popsáno zde – hledejte sekci Interrupt Example (the Encoder interrupts the processor). Uses both Interrupt pins.
Zbyšek VodaÚčastníkAle klon jaké desky? 🙂 UNO, Leonardo…?
Zbyšek VodaÚčastníkDobrý den, jakou Arduino desku máte?
Zbyšek VodaÚčastníkNapadá mě použití jiného způsobu odečítání, než přes měření AC.
Mohlo by dobře fungovat počítání otáček motoru tak, že na osu si nalepíte odrazku a pak IR diodou a IR fototranzistorem budete odečítat, kolikrát došlo k „průchodu“ odrazky před senzorem. Viz například http://www.instructables.com/id/Measure-RPM-DIY-Portable-Digital-Tachometer/?ALLSTEPS.
Podobně by mohl fungovat magnet s hallovou sondou.
Jen nevím, jestli ve vašem případě lze připevnit odrazku či magnet na osu motoru nebo jinou pohyblivou část.
Zbyšek VodaÚčastníkDobrý den, určitě by to nějak šlo.
Třeba tady http://www.instructables.com/id/Air-Conditioning-web-controlled-by-Arduino/?ALLSTEPS o tom píšou.Zbyšek VodaÚčastníkCo je připojeno na pinech 8 a 9?
Zkusím vás nasměrovat 🙂 Přidejte si ještě jednu proměnnou, ve které budete uchovávat, jestli je žaluzie zatažená, nebo roztažená.
Potom budete zkoumat:
-je hodnota nad určitou hodnotu a je roztaženo? -> zatáhni
-je hodnota pod určitou hodnotu a je zataženo? -> roztáhniTaké nesmíte zapomenout nastavit aktuální hodnotu proměnné po zatažení či roztažení.
PS. Asi v kódu myslíte analogový pin A0, ne jenom 0 🙂
Zbyšek VodaÚčastníkDobrý den, je to krásná práce 🙂
Je super, když je projekt i vizuálně zajímavý a to se povedlo! 🙂
Plánujete i nějakou šasi?Zbyšek VodaÚčastníkDobrý den, problém je v tom, že attachInterrupt očekává jako druhý parametr referenci na funkci bez parametru. Metody objektů jsou ale implementovány tak, že jako první parametr mají „skrytě“ referenci na třídu, ke které patří. To vám vlastně říká i chybová hláška:
cannot convert 'Pokus::Privatna' from type 'void (Pokus::)()' to type 'void (*)()'
Problém řeší i s navrženými řešeními zde:
Zbyšek VodaÚčastníkZkuste postupovat například pomocí tohoto návodu: http://www.instructables.com/id/Arduino-Tutorials-part-3-17-Tutorial-Pack/step6/Arduino-and-RF-Transmitter-MX-FS-03V-and-Receiver-/ ?
Zbyšek VodaÚčastníkDíky za upřesnění.
Jaká serva používáte?Zbyšek VodaÚčastníkTo „dosažení zadané pozice“ podle mě znamená to, že vy pošlete do SSC32:
„nastav servo 1 na úhel 100°“
Není ale možné, aby servo bylo okamžitě z 0° nastaveno na 100°, takže řídící elektronika s určitou rychlostí odesílá „nastav 1°“, „nastav 2°“, …, „nastav 50°“, …, „nastav 100°“ a v tento moment dojde k potvrzení, že je servo na požadované pozici.To je ale pouze potvrzení, že řídící elektronika odeslala servu, aby se nastavilo na 100°. Jestli tam ale servo skutečně je, to nikdo neví. Většinou ale na těch 100° skutečně je.
Podle původní otázky jsem myslel, že chcete mít skutečnou informaci o poloze serva (zjištěnou například nějakým senzorem). Teď to ale vypadá, že se jenom ptáte, jak získat z SSC32 informaci, že už servo bylo nastaveno na zadanou pozici. Jak to tedy myslíte?
Zbyšek VodaÚčastníkPokud chcete mít přehled o poloze serva, musíte mít servo, které je na to přizpůsobené a má na sobě například nějaký přídavný senzor. Třeba na tomhle servu: https://www.adafruit.com/product/1404 je vyvedený potenciometr, takže měřením analogové hodnoty máte přehled, kam až servo dojelo.
I kdyby šla informace o nastaveném úhlu z desky SSC32 získat zpátky (což myslím nejde), bude tato informace stejně irelevantní, jako kdybyste si jenom pamatoval hodnotu, kterou jste na servu nastavil – neměl byste reálný feedback o poloze serva, ale jenom domnělou hodnotu, kterou si SSC32 myslí, že servo má nastaveno.
Zbyšek VodaÚčastníkZbyšek VodaÚčastníkTo vypadá moc pěkně 🙂
Neplánujete i vytvořit třeba různé „tachometry“ a podobné?
Pak by se mohl z grafů a „tachometrů“ poskládat docela pěkný dashboard.Zbyšek VodaÚčastníkTo, že pin „obsahuje“ přerušení znamená, že umí přerušení vyvolat – že řekne programu „teď se zastav a dělej něco úplně jiného“.
Piny 2 a 3 jsou tedy piny, které mohou způsobit vyvolání hardwarového přerušení. Obslužná funkce tohoto přerušení se na ně připojuje pomocí funkce attachInterrupt().Na pinech 4 a 5 přerušení nevyvoláte (ve smyslu toho hardwarového přerušení).
Ve vašem programu ale pravděpodobně hardwarové přerušení vůbec nechcete. Vy jenom chcete například reagovat na koncový spínač apod. Tomu sice asi říkáte „přerušení“, ale s přerušením ve smyslu interrupt toto vůbec nesouvisí.
Zbyšek VodaÚčastníkProblém bude v nesprávné interpretaci „přerušení“ 🙂
K přerušení dojde, když program v reakci na nějakou událost „odskočí“ na chvilku ze standardního běhu a rychle se provede něco jiného. Přerušení může být vyvolané například vnitřním časovačem, nebo také změnou napětí na pinu – to vás asi zmátlo. Obsloužení přerušení probíhá tak, že pomocí funkce attachInterrupt() řeknete, co se má stát v reakci na jakou událost. Více o přerušeních na https://www.arduino.cc/en/Reference/AttachInterrupt a https://www.arduino.cc/en/Reference/Interrupts.Vy ale vlastně ani přerušení nepotřebujete. Problém v programu je ten, že pokud použijete funkci delay(), dojde k čekání programu po určitou dobu. V té době program nereaguje na koncové spínače, ani neobsluhuje posun motorů.
Navrhuji místo tohoto „pasivního“ čekání použít funkci millis(), která vrací dobu v milisekundách od začátku běhu programu. Tento problém je popsaný v https://bastlirna.hwkitchen.cz/arduino-zaklady-blikani-bez-funkce-delay/.
Jestli to dobře chápu, používáte delay kvůli tomu, že ventil musí určitou dobu běžet, než je zasunutý/vysunutý. Pokud ale stačí pro každý ventil mít jenom dva stavy – vysunutý/zasunutý a nepotřebujete nic mezi, to čekání vlastně vůbec nepotřebujete.
Stačí vytvořit podmínku ve stylu: pokud je koncový vypínač 1 rozepnutý, nech ventil zapnutý, jakmile se k. vypínač sepne, vypni ventil. Chápeme se? 🙂Zbyšek VodaÚčastníkDobrý den, můžete sem prosím nasdílet váš program? Děkuji
Zbyšek VodaÚčastníkKdybyste pole naplnil pomocí cyklu, místo memset, jak to dopadne?
Zbyšek VodaÚčastníkDobrý den,
kód je naprosto v pořádku. Asi bych zkusil buďto přeinstalovat prostředí a když ani to nepomůže, tak vyzkoušet nějakou starší verzi 🙂Zbyšek VodaÚčastníkDobrý den, napadá mě, že by problém mohl být v porovnání:
heslo !=""
Jazyk C++ má totiž řetězce implementované jako objekty – vy používáte objekt String. A u nich je potíž, že nejdou jednoduše porovnávat jako primitivní datové typy. Dojde totiž k porovnání jejich refenrencí a ne jejich hodnot (aspoň myslím).Takže u
String s1 = "A"; String s2 = "A";
myslím neplatí rovnost s1 == s2.
Vy tedy porovnáváte objekt heslo, který je typu String s prázdným řetězcem „“. Dojde k porovnání referencí (něco jako adresa v paměti). Ty dva se ve vašem případě nikdy rovnat nebudou, tedy bude podmínka
heslo !=""
vždy true.K porovnávání hodnot řetězců se používá metody equals – viz https://www.arduino.cc/en/Reference/StringEquals
Tento problém s porovnáváním řetězců tam pak máte několikrát.
Snad to pojede 🙂
Zbyšek VodaÚčastníkDobrý den,
máte dobře nastavenou rychlost komunikace v sériovém monitoru?
Kdyžtak sem prosím nasdílejte kód a zkusíme to nějak pořešit.Zbyšek VodaÚčastníkDobrý den,
asi nejjednodušší je pomocí mikrofonu zjišťovat hlasitost přehrávané hudby a podle toho blikat – odkáži vás například sem. Čtení „hlasitosti“ probíhá na na analogových pinech.Nebo můžete analyzovat frekvence, které vaše přehrávaná hudba obsahuje a podle toho blikat ledkami apod. To můžete udělat například pomocí nějaké knihovny implementující FFT. Zkuste se podívat na google, určitě něco najdete 🙂
Zbyšek VodaÚčastníkUž jsem to jednou k vašemu příspěvku psal Aleši, ale napíšu to znovu.
Logické úrovně 5V a 3.3V (a další) není dobré míchat dohromady. Některé piny mohou být tolerantní, ale může se také stát, že najednou zapojení přestane fungovat, protože to daný pin už prostě nevydrží a dá docela práci odhalit, že nějaký pin odešel.
Takže ano, zapojení většinou funguje, ale není to dobrá praktika…7.7.2016 v 22:09 odpověď na: Jak po stisku tlačítka zapsat a odentrovat hodnotu do serial boxu. #7575Zbyšek VodaÚčastníkDobrý den,
moc nerozumím vašemu popisu.
Jestli chcete odeslat „X100“, za kterým následuje nový řádek, tak stačí napsat:
Serial.println("X100");
Když to dáte dohromady s tím tlačítkem, v nejjednodušším případě vypadá kód takto:if (digitalRead(11) == LOW){ Serial.println("X100"); }
Zbyšek VodaÚčastníkDobrý den, tento problém je trochu zapeklitý.
Hlavní příčinou problému je to, že funkce, kterou připojujete pomocí
attachInterrupt()
nesmí mít žádný parametr. Vaše funkcevoid mmT25::_irqHandler();
sice viditelně žádný parametr nemá, ale jelikož je metodou objektu, je jí automaticky předávám parametr, který je instancí objektu, ke kterému náleží.Odtud pochází také error, který při kompilaci váš kód hlásí:
cannot convert ‚mmT25::_irqHandler‘ from type ‚void (mmT25::)()‘ to type ‚void (*)()‘
neboli nemůžu překonvertovat funkci, která má jeden parametr – instanci objektu mmT25 – na funkci, která nemá žádný parametr.Přiznám se, že neznám řešení vašeho problému, ale na tomto fóru: https://forum.arduino.cc/index.php?topic=41713.0 problém řeší a zjevně i úspěšně 🙂
Zbyšek VodaÚčastníkTo vytvoření pole přes
Bounce bouncer[5];
jsem také zkoušel, ale nějak to kompilátor nebral. Přitom by to takto mělo C++ podporovat.
Proto jsem šel tou cestou přes malloc().Zbyšek VodaÚčastníkDobrý den, pošlu vám celý kód určený pro LEDky ze článku.
class LED{ private: int pin; boolean stav = LOW; //výchozí stav LED je vypnuto void nastav(boolean); public: LED(int); void zapni(); void vypni(); void prepni(); boolean vratStav(); }; LED::LED(int p){ pin = p; pinMode(pin, OUTPUT); digitalWrite(pin, stav); } void LED::zapni(){ nastav(HIGH); } void LED::vypni(){ nastav(LOW); } void LED::prepni(){ nastav(!stav); //nastaví LED na obrácenou hodnotu (0->1, 1->0) } void LED::nastav(boolean s){ stav = s; Serial.print("Nastavuji "); Serial.print(stav); Serial.print(" na pinu "); Serial.println(pin); digitalWrite(pin, stav); } boolean LED::vratStav(){ return stav; } #define NO_OBJECTS 6 LED *LEDS = (LED*)malloc(NO_OBJECTS * sizeof(LED)); void setup() { Serial.begin(9600); for(int i = 0; i < NO_OBJECTS; i++){ LEDS[i] = LED(i); } for(int i = 0; i <= 10; i++){ LEDS[2].prepni(); delay(500); } } void loop() { }
Důležité části jsou:
#define NO_OBJECTS 6
Řekne programu, že bude celkem 6 LEDEK/TLAČÍTEK…LED *LEDS = (LED*)malloc(NO_OBJECTS * sizeof(LED));
Vytvoří se ukazatel na datový typ LED. Funkce malloc alokuje v paměti prostor pro budoucí pole – potřebuje vědět, jak bude velké. Proto se jí jako parametr předá velikost jednoho objektu LED (sizeof) ponásobená počtem objektů v poli. Funkce malloc vrací datový typ void*, takže je potřeba ho ještě před uložením do LEDS přetypovat na LED*. Dále už se dá s LEDS pracovat jako s normálním polem.Nevím, jestli je toto nejjednodušší cesta, ale nenapadla mě jednodušší.
for(int i = 0; i < NO_OBJECTS; i++){ LEDS[i] = LED(i); }
Do pole LEDS poukládá objekty LED na daných pinech.
for(int i = 0; i <= 10; i++){ LEDS[2].prepni(); delay(500); }
Postupně bliká ledkami.
Snad to je pochopitelné. Kód by měl jednoduše jít předělat pro vaše potřeby. Pole by mohlo vypadat takto:
RBD::Button *pole = (RBD::Button*)malloc(NO_OBJECTS * sizeof(RBD::Button));
Jeho naplnění potom:
for(...){ pole[i] = RBD::Button(i); }
Zbyšek VodaÚčastníkTak si to musíte nějak podmínit. Když to je přímo v loopu, tak ten se spouští pořád dokola. Potom se „impulz“ vysílá pořád dokola.
Nevím, jak přesně to má fungovat. Ale třeba na stisknutí tlačítka může reagovat takto (zjednodušeno).
void setup(){ pinMode(2, INPUT); pinMode(3, OUTPUT); } void loop(){ if(digitalRead(2) == HIGH){ digitalWrite(3, HIGH); delay(500); digitalWrite(3, LOW); delay(1000); } }
Zbyšek VodaÚčastníkDobrý den. Krátký impulz uděláte tak, že na výstup „nastavíte“ HIGH a po malé chvilce zase LOW.
Takže třeba
digitalWrite(pin, HIGH); delay(500); digitalWrite(pin, LOW);
Nastaví na půl sekundy výstup do logické 1.
Zbyšek VodaÚčastníkDobrý den, jestli se nepletu, tak knihovna WiFi.h je určena pro oficiální WiFi shield.
ESP je možné ovládat pomocí AT příkazů, které budete posílat přes sériovou linku, např:
Serial.println("AT");
-
AutorPříspěvky