OK

Při poskytování služeb nám pomáhají soubory cookie. Používáním našich služeb vyjadřujete souhlas s naším používáním souborů cookie. Více informací

Úvodní stránka » GSM » Jak jednoduše na GSM - IV.díl - Ovládání LEDKy SMSkou

Jak jednoduše na GSM - IV.díl - Ovládání (nejen) LEDKy SMSkou

Vážení přátelé, díky za pozitivní ohlasy na minulé díly mého mini seriálu ze života GSM! Z mých poměrně rozsáhlých projektů jsem se rozhodl vykopírovat odzkoušené a stabilní kódy pro práci se SIM800. Dal jsem dohromady jednoduchou úlohu, která čeká v hlavní smyčce na příchod SMSky z Vašeho čísla, poté načte, odkud byla SMS poslána a jaký má obsah, mrkne, zda tomuto obsahu rozumí, provede danou akci a informuje zpětně SMSkou na zdrojové číslo, že akce byla vykonána. Tento kód slouží jako názorná ukázka toho, co bylo řečeno v předchozích dílech a lze jej velmi jednoduše modifikovat např. pro ovládání relé, čtení vstupu a poslání informace SMSkou o dosažení nějakého stavu apod. 

Jak tak koukám po netu, vidím, že je všude plno shieldu s GSM modulem samotným, ale nic přímo použitelného v domácnosti, co by se jen nasunulo na např. UNO nebo DUE a mohli bychom tím přímo něco řídit. Prosím o malou anketku - měli by jste zájem o takový shield? Řekněme 2 relátka, 4 vstupy přes optočleny, 2 analogové vstupy s trimry a samozřejmě s integrovaným SIM800. Budu vděčný za Vaše reakce a náměty, dle toho bych pak tento shield vytvořil.

Tak a pojďme rovnou na kód ....

 

LEDka ON/OFF přes SMS

Níže uvedený kód je napasán pro Arduino DUE, přičemž mám specificky nastavené prostředí tak, že využívám jeho watchdog - v kódu naleznete volání procesu WDT_Restart(WDT); Toto volání můžete směle ignorovat, pokud také watchdog nepoužíváte. Pro aplikace na procesorech AVR (UNO, NANO, MEGA, MINI) lze kód požít také s drobnou modifikací - SIM800 připojte na RX,TX/D2/D3 a definujte si SoftwareSerial jako SIM800 s rychlostí 9600. U MEGA můžete s výhodou použít sériový port např. Serial1, podobně jako u DUE. Pokud si nevíte rady, jak přesně kód zmodifikovat, mrkněte na předchozí díl a transparentní terminál - z toho je jasné, jak se přistupuje k DUE a jak ke zbytku Arduino světa.

Po nahrání sketche doporučuji spustit monitor na sériovém kanále (115200) a koukat, co se děje.

Nejprve provedeme patřičné definice - Reset SIM800 mám na D5 pinu, LEDku vybereme tu vestavěnou na D13, Serial1 přejmenuji na něco smysluplnějšího. Nadefinujeme rychlosti, výstupy, zhasneme LED a jdeme na inicializaci modulu SIM800 zavoláním SIM800Init(); 


#define SIM800 Serial1
#define GSMReset 5
#define LED 13

String GSMsignal;

void setup()
{

  Serial.begin(115200);
  SIM800.begin(115200);
  delay(1000);
  pinMode(LED,OUTPUT);
  digitalWrite(LED,LOW);
  restartSIMHW();
  SIM800Init();
  

}

Hlavní smyčka je primitivnost sama - pouze koukáme co sekundu, zda nám nedošla nějaká ta SMSka.


void loop()
{

  WDT_Restart(WDT);
  delay(1000);
  checkSMS();
}


Inicializujeme SIM800 - vysvětlení k jednotlivým AT příkazům hledejte v předchozích dílech mini seriálu. Snad jen jedno malé specifikum - při inicializaci mažu veškeré SMSky - čistý stůl prostě. Postupně ověřuji registraci k síti, mrknu kolik je hodin u operátora, změřím kvalitu signálu (měli bychom být někde mezi 10 až 30), přečtu, s kým mám tu čest - tedy název operátora, smažu SMSky a jsem připraven nechat program pracovat už jen v hlavní smyčce.



void SIM800Init() { while (Serial.available() > 0) Serial.read(); Serial.println F("****************************************"); while (sendATcommand("AT","OK",2000) == 0); Serial.println F("SIM800 modul dostupny!"); //otestuj registraci do site while ( (sendATcommand("AT+CREG?", "+CREG: 0,1", 500) || sendATcommand("AT+CREG?", "+CREG: 0,5", 500)) == 0 ); while (Serial.available() > 0) Serial.read(); Serial.println F("SIM800 registrovan do site!"); //nastaveni parametru pro obdrzeni casu ze site while( sendATcommand("AT+CLTS=1", "OK", 500) == 0 ); while( sendATcommand("AT+CENG=3", "OK", 500) == 0 ); while (Serial.available() > 0) Serial.read(); Serial.print("Casova znacka:"); Serial.println(timeStamp()); //CSQ, pozice 4 GSMsignal = sendATcommandResponse("AT+CSQ", "+CSQ:", 1000, 3); Serial.println("GSM signal quality:"+GSMsignal); if (GSMsignal.length()==3) GSMsignal = GSMsignal.substring(1); String providerName = sendATcommandResponse("AT+COPS?","+COPS:",1000,20); uint8_t tempIndex = providerName.indexOf('"'); providerName = providerName.substring(tempIndex+1); tempIndex = providerName.indexOf('"'); providerName = providerName.substring(0,tempIndex); Serial.println("GSM provider:"+providerName); sendATcommand("AT+CMGF=1", "OK", 500); //zakaz indikace SMS sendATcommand("AT+CNMI=0,0", "OK",500); sendATcommand("AT+CLIP=1", "OK", 500); //smaz vsechny SMSky sendATcommand("AT+CMGD=1,4", "OK", 2000); sendATcommand("AT+CMGD=1", "OK", 2000); Serial.println F("Zakladni parametry nastaveny!"); }


Toto jsou obslužné utility pro pohodlné posílání AT příkazů s vyčasováním, není to můj výtvor, kdesi jsem je kdysi našel a jsem s nimi spokojený, takže doporučuji využít a zbytečně do toho nehrabat.


int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout)
{

	//WDT_Restart(WDT);
	uint8_t x = 0,  answer = 0;
	char response[100];
	unsigned long previous;

	memset(response, '\0', 100);    // Initialize the string

	delay(100);

	//clrSIMbuffer();
	SIM800.println(ATcommand);    // Send the AT command
	//WDT_Restart(WDT);

	x = 0;
	previous = millis();

	// this loop waits for the answer
	do
	{
		WDT_Restart(WDT);
		if (SIM800.available() != 0) {
			// if there are data in the UART input buffer, reads it and checks for the asnwer
			response[x] = SIM800.read();
			x++;
			// check if the desired answer  is in the response of the module
			if (strstr(response, expected_answer) != NULL)
			{
				answer = 1;
			}
		}
		// Waits for the asnwer with time out
	}
	while ((answer == 0) && ((millis() - previous) < timeout));

	//clrSIMbuffer();
	return answer;
}


//AT prikaz s ocekavanou odpovedi a zbytkem
String sendATcommandResponse(char* ATcommand, char* expected_answer, unsigned int timeout, unsigned int buf)
{
	//WDT_Restart(WDT);
	uint8_t x = 0,  answer = 0;
	char response[150];
	unsigned long previous;
	String rest;

	memset(response, '\0', 100);    // Initialize the string

	delay(100);

	//clrSIMbuffer();
	SIM800.println(ATcommand);    // Send the AT command


	x = 0;
	previous = millis();
	//WDT_Restart(WDT);
	// this loop waits for the answer
	do
	{
		WDT_Restart(WDT);
		if (SIM800.available() != 0) {
			// if there are data in the UART input buffer, reads it and checks for the asnwer
			response[x] = SIM800.read();
			x++;
			// check if the desired answer  is in the response of the module
			if (strstr(response, expected_answer) != NULL)
			{
				answer = 1;
			}
		}
		// Waits for the asnwer with time out
	}
	while ((answer == 0) && ((millis() - previous) < timeout));

	//p?e?ti zbytek - max 20 byte
	memset(response, '\0', buf);    // Initialize the string
	delay(100);
	for (x = 0; x < buf; x++) response[x] = SIM800.read();
	//clrSIMbuffer();
	for (x = 0; x < buf; x++) rest += char(response[x]);
	delay(100);
	return rest;

}

Tak a tady máme tu proceduru, kterou voláme v hlavní smyčce - koukám, zda dorazila SMSka a pak se patřičně zachovám. Využívám příkazu AT+CMGR=1 a pokud mi SIM800 vrátí OK, proceduru opouštím, protože žádná nová SMSka nedorazila. Pokud dostanu jinou odpověď tak ji podrobím analýze.


//Receive SMS
void checkSMS()
{
	
	char g;
	String gcmd;
	String number;
	uint8_t gindex;
	clrSIMbuffer();
	SIM800.println("AT+CMGR=1");
	delay(100);
	//potla?en? echa
	while(SIM800.available()>0)
	{
		g=SIM800.read();
		gcmd += g;
		if (g=='\n')
		{
			gcmd = "";
			break;
		}
	}

	//na?ti prvn? ??dek odpov?di
	while(SIM800.available()>0)
	{
		g=SIM800.read();
		gcmd += g;
		if (g=='\n')
		{
			
			if (gcmd.substring(0,2)=="OK") return;
			if(gcmd.substring(0,5)=="+CMGR")
			{
				//Serial.println(gcmd);
				Serial.println("Nova SMSka!!!!");
				//prvni + "+CMGR"
				gindex = gcmd.indexOf('+');
				if(gindex < 0) return;
				//odsekni prvn? +
				gcmd = gcmd.substring(gindex+1);
				//Serial.println(gcmd);
				//dal?? + - obsahuje ??slo odes?latele
				gindex = gcmd.indexOf('+');
				number = gcmd.substring(gindex+4,gindex+13);
				Serial.println("Od:" + number);
				//precti obsah SMS
				gcmd = "";
				delay(50);
				while (SIM800.available()>0)
				{
					g=SIM800.read();
					gcmd += g;
					if (g=='\n')
					{
						gcmd = gcmd.substring(0,gcmd.length()-2);
						Serial.println("Obsah SMS:" + gcmd);
						SMSparser(gcmd);
						sendSMS(number,"Vykonano!");
						gcmd = "";
						sendATcommand("AT+CMGD=1", "OK", 1000);
						sendATcommand("AT+CMGD=1,4", "OK", 1000);
						Serial.println("SMS smazana z pameti.");
						return;
					}
				}
				gcmd="";
				sendATcommand("AT+CMGD=1", "OK", 1000);
				sendATcommand("AT+CMGD=1,4", "OK", 1000);
				return;
			}
			
			
		}
	}
}

Touto procedurou posílám SMSku na dané číslo (number) a s daným obsahem (sms). Asi není co dodat, pouze si všimněte, že pro poslání SMSky je potřeba sekvenci po AT příkazu CMGS ukončit znakem Ctrl+Z, tedy vnutit do terminálu char 26.


//Send SMS
void sendSMS(String number, String sms)
{
	Serial.println("SMS pro:"+number);
	Serial.println("Obsah:"+sms);
	delay(500);
	clrSIMbuffer();
	//number = "+420"+number;
	SIM800.println ("AT+CMGS=\""+number+"\"");
	delay(200);
	//toSerial();
	SIM800.println (sms);        // message to send
	delay(100);
	SIM800.write ((char) 26);	//CTRL+Z
	delay(100);
	SIM800.println();
	delay(100);
	sendATcommand("AT+CMGD=1", "OK", 2000);
	sendATcommand("AT+CMGD=1,4", "OK", 2000);
	delay(500);
	clrSIMbuffer();
	Serial.println("SMS odeslana!");
}

A tady máme jednoduchý parser - tedy proceduru, která bdí nad vykonávanými příkazy. Implementoval jsem pro jednoduchost pouze příkaz LED:ON - rozvítí LEDku a LED:OFF - zhasne LEDku. Zde máte v podstatě aplikační pool, kde ke každému příkazu, který si vymyslíte dopíšete svou proceduru nebo volání na nějakou složitější funkci. Nechávám zde prostor pro úvahy, bastlení, cokoliv, co Vás napadne.


void SMSparser(String command)
{
	if (command == "LED:ON")
	{
		digitalWrite(LED,HIGH);
		return;
	}
	if (command == "LED:OFF")
	{
		digitalWrite(LED,LOW);
		return;
	}
	Serial.println("Neznamy prikaz!");

}


A zde už jen podpůrné prkotiny - čtení časové značky, zacommentovány mám parsing do tzv. časového razítka - time stamp, kdyby se někomu hodil, tedy jiná interpretace toho, co obdržíme ze SIM800 napřímo. Pak ještě procedurka pro HW restart SIM800 - tedy zatahání za D5 - zkuste třeba do SMS parseru definovat příkaz RESET a vyvolat tuto proceduru - pak musíte si 10 sekund počkat na korektní přihlášení modulku SIM800 ke GSM síti. No a konečně poslední procedurku využívám pro promazávání nesmyslů, které ze SIM800 přijdou a které mně až tak nezajímají.


String timeStamp()
{
	String ts="";
	ts = sendATcommandResponse("AT+CCLK?", "+CCLK: \"", 1000, 20);
	//13/11/04,15:23:19+04
	//return ("20"+ts.substring(0,2)+ts.substring(3,5)+ts.substring(6,8)+ts.substring(9,11)+ts.substring(12,14)+ts.substring(15,17));
	return ts;
}
void restartSIMHW()
{
	//HW restart
	digitalWrite(GSMReset,LOW);
	delay(400);
	digitalWrite(GSMReset,HIGH);
	delay(400);
}
void clrSIMbuffer()
{
	while(SIM800.available()>0)
	{
		delay(1);
		SIM800.read();
	}
}


Funguje-li vše jak má, pak na sériovém kanále budete odměněni takto:


SIM800 modul dostupny! SIM800 registrovan do site! Casova znacka:15/10/16,21:12:33+08 GSM kvalita signalu: 23 GSM operator:T-Mobile CZ Zakladni parametry nastaveny! Nova SMSka!!!! Od:739822476 Obsah SMS:LED:ON SMS pro:739822476 Obsah:Vykonano! SMS odeslana! SMS smazana z pameti.


Celý sketch pro Arduino DUE si můžete stáhnou zde. Pokud to někdo zmodifikujete na UNO nebo něco podobného, pošlete to, zveřejním to. A nezapomeňte na mou mini anketu, díky!!!

PF

Přidat komentář

Zvýrazněné položky jsou povinné.

Přehled komentářů

  1. SIM800 (Jaro, 17.10.2015 8:25:35) Odpovědět

    Ahoj! Perfektní článek a seriál vůbec, díky. Proč někdy používáš přímý zápis do SIM800 a ne ten přes procedury pro poslání AT příkazů?

  2. GSM modul (Robert, 20.10.2015 20:00:55) Odpovědět

    Takový štít bych bral, úplně super by bylo pokud by to přes GPRS dokázalo ještě přenášet seriovou komunikaci .např. UNO se GSM štítem na chatě s možností ovládání přes aplikaci v Androidu.
    Nebo přenášet seriovou komunikaci z EZS (alarmu)
    Děkuji za návody.

  3. Boží (Roman, 22.10.2015 19:53:39) Odpovědět

    Zdar, naproto boží seriál... jsem v arduinu zatím nováček, jen mi tu leží nas tole UNO, které předevčírem přišlo z číny. Shield bych bral. Já vytvořím následující pitominku: PIR Senzor, pri pohybu poslu SMS - jako hlidac do garáže... to je zatím můj malý cíl... jdu objednat z číny ten GSM Modul...

  4. Díky (maraou, 2.11.2015 6:27:14) Odpovědět

    Ahoj, seriál je výborný. Mě by asi nejvíc zajímalo, jak z toho poslat email pres GPRS, nebo nějakým jiným způsobem dostat data na server, kde by se logovali? Např. každou hodinu posílat aktuální data z meteostanice. Budu se těšit na další díl.

    Admin:
    Ahoj, jj GPRS bude v dalším pokračování seriálu, není to nic složitého. Momentálně pracuji nad GPRS shieldem skoro dle popisu v článku a pak s tímto shiledem budou následovat nějaké příklady i na GPRS. Obecně lze tyto věci řešit přes HTTP GET/POST.

  5. PDU vs text mode (RDP, 14.11.2015 15:14:36) Odpovědět

    Dobrý den, děkuji za skvělý článek. Snažím se Váš příklad rozchodit na Duelaminove a tak procházím řádek po řádku. Ze začátku v setupu nastavujete text mode AT+CMGF=1 a o něco níže čistíte SMSky pomocí kódů pro PDU AT+CMGD=1,4, přičemž při textovém modu bych očekával DEL READ a DEL UNSET nebo rovnou vse ne? DEL ALL. Tohle funguje nezávisle na zvoleném módu?

    A ještě druhá otázka, máte 2x pod sebou:
    sendATcommand("AT+CMGD=1,4", "OK", 2000);
    sendATcommand("AT+CMGD=1", "OK", 2000);
    jaké je tady očekávané chování, protože volba 1,4 je zvolena výše a na druhém řádku je již pouze volba 1. Děkuji za odpovědi.

    Admin:
    Dobrý den,
    Ad1) hmmm, tak to ale není, prostudujte datasheet k SIM800L, resp. nevyvracím, že máte pravdu, ale používám to takto a je to funkční - 1 = první zpráva, 4 = delete all a myslím, že je jedno, zda jsem v PDU nebo ASCII módu. Nepřu se, ale v aplikacích mi to takto funguje.

    Ad2) Vyplynulo ze zkušeností - ne vždy se mi ta zpráva podařila napoprvé korektně smáznout - opět: takto jsem to časem vylaboroval, aby to bylo chodivé. Když jdeme na ty příkazy sekvenčně a nejsme ničím rušení - např. obsluhou od přerušení timeru, apk to může fungovat na první šup. Já ale na něco jdu sekvenčně málokdy - snad jen tady v examplech a byl jsem líný překopávat něco, o čem vím, že chodí. Ale Arduino apod. je pro experimenty, takže experintujme a sdílejme to.

    Díky za komenty!

    PF

  6. Prázdné body (RDP, 14.11.2015 15:56:31) Odpovědět

    Ještě jsem narazil na problém s prázdným tělěm zprávy:

    Nova SMSka!!!!
    +CMGR: "REC READ","+420731011200","","15/11/14,15:54:27+04"

    Od:731***200
    Obsah SMS:
    Neznamy prikaz!
    SMS smazana z pameti.


    A mělo by to vypadat takto:
    AT+CMGR=1
    +CMGR: "REC READ","+85291234567",,"07/02/18,00:05:10+32"
    It is easy to read text messages via AT commands.

    OK

    Admin:
    Dobrý den,
    takto na dálku se mi to špatně posuzuje, nicméně bych doporučil nejprve natáhnou sketch transparentního terminálu, který popisuji ve 3. díle a odzkoušet si chod příkazů přímou interakcí. Pak budete mít jistotu, zda s Vámi modulek komunikuje dle očekávání - tedy očekávání programu. Co používáte za modul SIM800L nebo SIM900 - skoro se neliší, ale drobné nuance tam jsou, zejména v prezentaci příchozího čísla. Ale nemělo by to mít zásadní vliv. Zkuste ten transparentní terminál a dejte info.
    PF

  7. Prázdné body (RDP, 14.11.2015 19:53:20) Odpovědět | Zobrazit odpovědi

    Tak už vím,

    já zprávu dostanu takto:

    +CMGR: "REC READ","+420731011200","","15/11/14,16:21:21+04"
    telo sms zpravy

    a tady je iterace:
    //na?ti prvn? ??dek odpov?di
    while(SIM800.available()>0)
    {
    g=SIM800.read();
    gcmd += g;
    if (g=='\n')
    {

    kde \n je nový řádek, takže už to vlastně nečeká na druhý řádek kde je to telo zprávy a proto se nevypíše.

    1. Re: Prázdné body (mukos, 28.5.2017 14:18:16) Odpovědět

      Ahoj, jak to tedy má být aby to fungovalo?

  8. tady sketch pro UNO (Roman Simku, 21.11.2015 23:12:57) Odpovědět

    tady je mirne upraveny sketch pro Arduino UNO...
    https://drive.google.com/a/simku.cz/file/d/0BxbJwXbjFqU-ekVWMEVIQ3RGcEk/view?usp=sharing

    Admin:
    Díky! To je přesně úprava pro Atmega328p, kterou jsem měl na mysli. Další díly už pak pracují s knihovnou, která je již přizpůsobená přesně v tomto duchu pro UNO, neboť je využíván Arduinotech GSM Shield právě pro UNO.

  9. Nespracuje (Karol, 21.3.2016 19:48:51) Odpovědět

    Caute

    Uoraveny program mi spracuje len 1 sms dalsiu uz nespracuje. Kde by mohol byt problem? Dakujem

    Admin:
    Lidi, čtěte 10. díl - troubleshooting - buffer, buffer, buffer ... a ještě jednou buffer na 128 byte, jinak se s tim nedomluvíte.

    PF

  10. control led with uno (sat ray, 22.6.2016 10:39:35) Odpovědět

    Hi
    Thanks for your article.
    I want apply this project with arduino UNO. But I do not know what changes to the program should be created. Can you help me how I can this problem?
    Thanks for your attention.

  11. John (Smithd232, 2.10.2016 21:22:09) Odpovědět

    Wow, superb blog layout! How long have you been blogging for? you made blogging look easy. The overall look of your website is wonderful, let alone the content! kgeccccfkdafeefa

  12. SIM900 (Laco, 2.9.2017 14:06:11) Odpovědět

    Zdravim vsetkych a hlavne Admina, velka pochvala za vsetky clanky tu, je to tu super popisane a zrozumitelne, ale ja sa znazim tento kod rozbehat na SIM900 a mega328p, uz som si kopu veci potrepisoval podla vlastnych predstav ale co sa mi nedari rozchodit je checkSMS(), po odkomentovani riadnu na zaciatku clrSIMbuffer() mi program vypise toto :

    Nova SMSka!!!!
    CMGR: "REC READ","+421XXXXXXXXX","","17/09/02,13:45:51+08"

    Od:XXXXXXXXX
    Obsah SMS:
    Neznamy prikaz!
    SMS vymazana z pameti.

    tak sa mi zda ze nevie precitat druhy riadok koli tomu ze je to SIM900 a asi ma mat inac napisane parametre pre citanie druheho riadku, niekedy sa pomyli a vypise to takto:

    Nova SMSka!!!!
    CMGR: "REC READ","+421XXXXXXXXX","","17/09/02,13:55:42+08"

    Od:XXXXXXXXX
    Obsah SMS:CMGR: "REC READ","+421XXXXXXXXX","","17/09/02,13:55:42+08"
    Neznamy prikaz!
    SMS vymazana z pameti.

    este jedna vec ma napadla, musel som prepisat aj riadkny sendATcommand a sendATcommandResponse:

    int8_t sendATcommand(const char* ATcommand, const char* expected_answer, unsigned int timeout)
    String sendATcommandResponse(const char* ATcommand, const char* expected_answer, unsigned int timeout, unsigned int buf)

    musel som tam dopisat const lebo mi to vyhadzovalo vybu, ci nahodov tam nie je problem, viete mi poradit ako sa pohnut dalej ? vopred dakujem za odpoved


TOP produkty

Arduino MEGA2560

Arduino MEGA2560
424 Kč s DPH

NodeMCU s ESP8266

NodeMCU s ESP8266
350 Kč s DPH

Kontakt

Ing. Petr Foltýn
Kunčice pod Ondřejníkem 814, 73913
TOPlist