Ovládáme Arduinotech GSM Shield Otestování HW Arduinotech GSM shieldu Poměrně značná část je věnována také otestování I2C sběrnice s OLED displejem, na který si posílám informace o jednotlivých stavech při testování. Pokud OLED displej nepoužíváte, pak funkci miniPrint() jednoduše nahraďte Serial.println(); nebo ji upravte takto a výpisy budou chodit na sériák: void miniPrint(String text) { Serial.println(text); return; /* zbytek věcí zakomentujte */ }
Celý sketch i s funkcemi pro OLED display (mimochodem s celkem povedeným terminálem pro výpis provozních stavů - právě tvořený funkcí miniPrint) je ke stažení zde. K samotnému sketchi:
Do sketche je také přidána knihovna U8glib.h, která obsluhuje OLED display, můžete ji tedy vynechat, pokud si zmodifikujete funkci miniPrint a OLED displej nebudete používat. #include <SoftwareSerial.h> #include #define #define #define #define #define #define #define #define
RESET 4 LED 7 RELE1 8 RELE2 9 IN1 5 IN2 6 RX 2 TX 3
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK); //U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_FAST); uint8_t lineCounter = 0;
String lineTerminal[5]; SoftwareSerial SIM800(RX,TX); char g,s;
Zde nadefinujeme vstupy/výstupy a provedeme nějaké akce s LED a relátky. Upozorňuji, že pro přitažení relé je potřeba mít připojené napájení 12V do napájecího konektoru Arduino UNO. Jinak neuslyšíte přitažení - cvaknutí relé. void setup() { SIM800.begin(9600); Serial.begin(9600); lineCounter = 0; u8g.setFont(u8g_font_7x14); miniPrint("GSM Shield Test"); pinMode(LED, OUTPUT); pinMode(RESET, OUTPUT); pinMode(RELE1, OUTPUT); pinMode(RELE2, OUTPUT); pinMode(IN1,INPUT); pinMode(IN2,INPUT); digitalWrite(LED,HIGH); digitalWrite(RELE1, LOW); digitalWrite(RELE2, LOW); digitalWrite(RESET, LOW); miniPrint("Rele OFF"); delay(500); miniPrint("SIM800 ON"); digitalWrite(LED,LOW); digitalWrite(RESET, HIGH); digitalWrite(RELE1, HIGH); digitalWrite(RELE2, HIGH); miniPrint("Rele ON"); delay(1000); digitalWrite(RELE1, LOW); digitalWrite(RELE2, LOW); digitalWrite(LED,HIGH); miniPrint("Rele OFF"); }
Hlavní smyčku jsem tentokrát omezil pouze na 2 věci: sériový transparentní terminál tak a pak pravidelné čtení vstupů pro jejich otestování, obě procedury asi nepotřebují zvláštní komentář. // the loop function runs over and over again forever void loop() { if(Serial.available()>0)
{
g = Serial.read(); SIM800.print(g);
} if (SIM800.available()>0) { s = SIM800.read(); Serial.print(s); } if ((digitalRead(IN1) == false) || (digitalRead(IN2) == false)) { digitalWrite(LED,LOW); if ((digitalRead(IN1) == false)) miniPrint("IN1 LOW"); if ((digitalRead(IN2) == false)) miniPrint("IN2 LOW"); delay(200); } else digitalWrite(LED,HIGH); }
Pokud vše pracuje, jak má, pak po natažení sketche a správně připojeném napájení 12V se nejprve rozsvítí LED, vypnou se obě relé, pak za půl sekundy zhasne LEDka a na jednu sekundu přitáhnou obě relé, poté se rozvití LED a vypnou obě relé. Od této chvíle můžete využít transparentní terminál pro AT příkazy a otestovat také vstupy - můžete uzemnit katodu LED diody jednotlivých optočlenů - zhasne LED dioda na shieldu. Otestovali jsme HW a je-li vše OK, pak se můžeme rovnou vrhnout na slibovaný praktický příklad.
Ovládání Arduino GSM shieldu prakticky Níže uvedený sketch používá stejné definice, jako sketch předchozí - testovací. Opět kvůli zjednodušení nebudu již uvádět a komentovat většinu pasáží, které jsou nutné pro správné fungování sketche a správnou interakci se shieldem, ale omezíme se na samotnou logiku hlavní smyčky. Pochopitelně celý funkčí sketch se všemi nezbytnostmi je ke stažení zde. Vynechejme tedy vše, co již bylo řečeno a podívejme se rovnou na hlavní smyčku a funkce v ní: void loop() { //mrkni na příchod SMS checkSMS(); //mrkni na vstupy checkInput(); //opkuj co 1s delay(1000);
}
V hlavní smyčce tedy kontrolujeme 2 věci - zda došla nějaká SMSka s příkazem a nebo zda se nezměnily poměry na vstupech. Dále se již podíváme, na 3 jednotlivé funkce, resp. podrobněji pouze na 2 protože funkci checkSMS. V podstatě celá logika je jen ve 2 funkcích - parseSMS(), kterou po přečtení SMS ze SIM800 volá checkSMS() funkce a checkInput(), která po vyhodnocení stavu vstupů pošle SMS nebo-li zavolá funkci sendSMS(). void SMSparser(String command) { //ovládaní relé přes SMS if (command == "RELE1:ZAP") { digitalWrite(RELE1, HIGH); sendSMS(number, "RELE1 zapnuto!"); rele1Status = true; return; } if (command == "RELE1:VYP") { digitalWrite(RELE1, LOW); sendSMS(number, "RELE1 vypnuto!"); rele1Status = false; return; } if (command == "RELE2:ZAP") { digitalWrite(RELE2, HIGH); sendSMS(number, "RELE2 zapnuto!"); rele2Status = true; return; } if (command == "RELE2:VYP") { digitalWrite(RELE2, LOW); sendSMS(number, "RELE2 vypnuto!"); rele2Status = true; return; } //dotaz na stav Relé a vstupů if (command == "Info") { String tempMessage; tempMessage = "Rele1:"; if (rele1Status == true) tempMessage += "ZAP"; else tempMessage += "VYP"; tempMessage += ",RELE2:"; if (rele2Status == true) tempMessage += "ZAP"; else tempMessage += "VYP"; tempMessage += ",IN1:"; if(digitalRead(IN1) == true) tempMessage += "1"; else tempMessage += "0";
tempMessage += ",IN2:"; if (digitalRead(IN2) == true) tempMessage += "1"; else tempMessage += "0"; sendSMS(number, tempMessage); return; } Serial.println F("Neznamy prikaz!"); }
SMS parser je napsán pro obsluhu několika příkazů:
RELE1:ZAP a RELE1:VYP
RELE2:ZAP a RELE2:VYP
Info
K prvním dvěma příkazům asi není co dodat - pošlete SMSku s obsahem RELE1:ZAP - za cca 4 až 6 sekund (trvání odeslání a příjmu SMS) uslyšíte cvaknutí relátka. Doporučuji mít spuštěný sériový kanál a monitorovat, co na něj chodí. Pokud pošlete SMSku s obsahem RELE1:VYP relé se vypne. O každé aktivitě vám bude odeslána SMSka zpět. Opět neřeším bezpečnost čísla, ale posílám SMSku tam, odkud jsem přijal povel.Na téma bezpečnost napíšu později určitě nějaký doplněk do sketche. Totéž funguje pro RELE2. Funguje-li vše, jak má, pak na sériovém monitoru objevíte toto: Nova SMSka!!!! Od:739822476 Obsah SMS:RELE1:ZAP SMS pro:739822476 Obsah:RELE1 zapnuto! SMS odeslana! **************************************** SMS smazana z pameti. **************************************** Nova SMSka!!!! Od:739822476 Obsah SMS:RELE1:VYP SMS pro:739822476 Obsah:RELE1 vypnuto! SMS odeslana! **************************************** SMS smazana z pameti. **************************************** Nyní zkuste odeslat SMS s obsahem Info. Parser tento příkaz vyhodnotí, mrkne v jakém stavu viděl naposledy relátka a přečte aktuální stav vstupů (je to jen příklad, chtělo by to čtení trochu
více zrobustnit, ale nechci ten kód v příkladu dělat nepřehledný). Z těchto informací poskládá obsah SMSky a odešle. Je-li vše OK, pak obdržíte SMSku a na sériovém monitoru se objeví toto: Nova SMSka!!!! Od:739822476 Obsah SMS:Info SMS pro:739822476 Obsah:Rele1:VYP,RELE2:ZAP,IN1:1,IN2:1 SMS odeslana! **************************************** SMS smazana z pameti. **************************************** Jak již bylo zmíněno ve IV.dílu - parser může být tak bohatý, jak si je napíšete a zařízení tedy může být tak vymakané, jak vymakaný budete mít parser. Takže neváhejte experimentovat a vymýšlejte své kombinace a příkazy.
void checkInput() { String tempMessage; bool sendIt = false; tempMessage = "Zmena stavu"; //při změně stavu vstupu odešli SMS if (digitalRead(IN1) != IN1Status) { tempMessage += " IN1:"; //počkej 200ms a přečti ještě jednou - mohl to byt jen zákmit delay(200); if (digitalRead(IN1) != IN1Status) { if (IN1Status == true) { tempMessage += "0"; IN1Status = false; } else { tempMessage += "1"; IN1Status = true; } sendIt = true; } else {
tempMessage = "Zmena stavu"; sendIt = false;
} } if (digitalRead(IN2) != IN2Status)
{
tempMessage += " IN2:"; //počkej 200ms a přečti ještě jednou - mohl to byt jen zákmit delay(200); if (digitalRead(IN2) != IN2Status) { if (IN2Status == true) { tempMessage += "0"; IN2Status = false; } else { tempMessage += "1"; IN2Status = true; } sendIt = true; } else sendIt = false;
} //pokud již modul pracoval s nějakým číslem, tak ho použij //pokud ne, pak použij definované číslo SERVIS_NUMBER if (sendIt == true) { sendIt = false; if (number.length() < 9) number = SERVIS_NUMBER; sendSMS(number, tempMessage); } }
Funkce checkInput() bdí nad změnou stavů obou vstupů a jakmile by jeden z nich přešel z 1 na 0 nebo opačně, odešle o této skutečnosti SMSku. Pokud jste si již s SMSkami hráli, pak si do paměti uloží Vaše číslo, v opačném případě je potřeba do definice SERVICE_NUMBER zapsat číslo ručně, jinak budou chodit SMSky výlučně na mé číslo :-), pakliže začnete s testováním od vstupů a relátka necháte na později. Je-li vše OK, pak při "zatahání" za katodu diody v optočlenu se objeví na sériovém kanálu následující: **************************************** SMS pro:739822476 Obsah:Zmena stavu IN2:0 SMS odeslana! **************************************** SMS pro:739822476 Obsah:Zmena stavu IN2:1 SMS odeslana! **************************************** A ve vašem telefonu přistanou dvě SMSky s obsahem Zmena stavu IN2:0 a Zmena stavu IN2:1.
S největší pravděpodobností vznikne pro Arduinotech GSM shield samostatná knihovna, kde budete ušetřeni podrobností s posíláním AT příkazů apod. a budou nejspíše zpřístupněny funkce typu sendSMS, checkSMS, inicializace pak přes nějaký shieldInit(), callNumber(), holdCall() apod. Mám to v plánu, ale pro účely podrobnějšího pohledu, jak to vlastně všechno vevnitř pracuje jistě není na škodu si takový sketch trochu rozebrat a pochopit, jak se věcí mají.