Im vorhergehenden Teil dieser Reihe wurde erklärt, wie man mit einem Arduino Uno und einem GSM-Board (in diesem Fall mit dem Siemens TC35) SMS versenden kann. Heute nun soll das Programm dahingehend erweitert werden, dass SMS empfangen und ausgewertet werden können und anhand des SMS-Inhalts ein Schalter bzw. ein Pin des Arduino geschaltet werden kann.
Der Schaltungsaufbau ist der gleich, wie er im letzten Versuch verwendet wurde. Hinzugekommen ist ein größeres Stück Software für den Arduino, welches nun die erforderlichen Befehle zum Empfang von SMS an das GSM-Modem sendet.
Die zur Kommunikation verwendete Lib SoftwareSerial definiert nur einen 64 Byte großen Empfangspuffer. Für den Empfang von SMS ist das viel zu wenig. In der Datei hardware/arduino/avr/libraries/SoftwareSerial/SoftwareSerial.h wird die Puffergröße durch _SS_MAX_RX_BUFF festgelegt. Diese Puffergröße sollte dort auf mindestens 1024 festgelegt werden.
#define _SS_MAX_RX_BUFF 1024
Folgende Vorgehensweise im Arduino-Programm für die Initialisierung wurde gewählt:
- Aktivieren der seriellen Schnittstellen zum GSM-Modem wie auch zum Computer (für die Protokollierung und zu Testzwecken)
- Einschalten des GSM-Teils des TC35 über den IGT-Pin
- Löschen aller alten bereits auf der SIM-Karte gespeicherten SMS-Nachrichten
Im anschließenden loop des Arduino wird ermittelt, ob neue SMS-Nachrichten vorliegen. Diese sollen dem Schema "PIN{ ON | OFF | STATUS }" ensprechen. Bei korrekt übermittelter PIN wird bei falschem Kommando eine SMS mit entsprechendem Hilfetext zurückgesendet. ON bewirkt das Einschalten des Schalter, OFF das Ausschalten und STATUS sendet eine SMS mit dem aktuellen Zustand des Schalters an den Sender der SMS zurück.
Arduino-Programm
#include <SoftwareSerial.h> #define rxPin 2 #define txPin 3 #define statusPin 13 #define igtPin 8 String accessPin("1234"); String cmdOff("OFF"); String cmdOn("ON"); String cmdStatus("STATUS"); SoftwareSerial gsmSerial(rxPin, txPin); String smsNumber; String smsText; String cmdMessage; String cmdResponse; int nMessages; char c; int state; int switchStatus; // ------------------------------------------------------------- void setup() { Serial.begin(9600); while(!Serial) {}; gsmSerial.begin(9600); pinMode(statusPin, OUTPUT); digitalWrite(13, LOW); switchStatus = false; // TC35 einschalten, igtPin 100ms auf GND ziehen pinMode(igtPin, INPUT); digitalWrite(igtPin, LOW); pinMode(igtPin, OUTPUT); delay(100); pinMode(igtPin, INPUT); delay(5000); // Format Text fuer SMS einstellen SendCmd("AT+CMGF=1"); CountMessages(); DeleteAllMessages(); Serial.println("Ready"); } // ------------------------------------------------------------- void loop() { if (nMessages > 0) { ReadSms(nMessages); Serial.println("Incoming: [" + smsNumber + "] [" + smsText + "]"); DeleteMessage(nMessages); nMessages--; if (smsText.length() >= accessPin.length() && smsText.startsWith(accessPin)) { smsText.remove(0, accessPin.length()); if (smsText == cmdOn) { digitalWrite(13, HIGH); switchStatus = true; } else if (smsText == cmdOff) { digitalWrite(13, LOW); switchStatus = false; } else if (smsText == cmdStatus) { smsText = "Switch is "; if (switchStatus == true) { smsText += cmdOn; } else { smsText += cmdOff; } SendMessage(); } else { smsText = "Available commands: " + cmdOn + ", " + cmdOff + " und " + cmdStatus; SendMessage(); } } } else { delay(5000); } CountMessages(); } // ------------------------------------------------------------- void SendCmd(String cmd) { gsmSerial.println(cmd); delay(1000); while(gsmSerial.available() > 0) { c = gsmSerial.read(); } delay(100); } // ------------------------------------------------------------- void CountMessages() { nMessages = 0; cmdMessage = "AT+CPMS=\"SM\""; gsmSerial.println(cmdMessage); delay(1000); cmdResponse = ""; state = 0; String num = ""; while(gsmSerial.available() > 0) { c = gsmSerial.read(); if (c != 13 && c != 10) { cmdResponse += c; } if (c == ':' && state == 0) { // Leerzeichen vor der ersten Zahl c = gsmSerial.read(); state = 1; } if (c != ' ' && state == 1) { // Anfang der ersten Zahl state = 2; } if (c == ',' && state == 2) { // Ende der ersten Zahl state = 3; } if (state == 2) { num += c; } } nMessages = num.toInt(); } // ------------------------------------------------------------- void DeleteAllMessages() { while(nMessages > 0) { DeleteMessage(nMessages); nMessages--; } } // ------------------------------------------------------------- void DeleteMessage(int smsIndex) { cmdMessage = ""; cmdMessage = smsIndex + cmdMessage; cmdMessage = "AT+CMGD=" + cmdMessage; SendCmd(cmdMessage); } // ------------------------------------------------------------- void ReadSms(int smsIndex) { cmdMessage = ""; cmdMessage = smsIndex + cmdMessage; cmdMessage = "AT+CMGR=" + cmdMessage; gsmSerial.println(cmdMessage); delay(1000); smsNumber = ""; smsText = ""; cmdResponse = ""; state = 0; // Format: +CMGR: "REC READ","+336xxxxxxxx",,"13/06/10,22:18:35+08"<CR><LF>Message<CR> while(gsmSerial.available() > 0) { c = char(gsmSerial.read()); if (c != 13 && c != 10) { cmdResponse += c; } if (c == ',' && state == 0) { // Anfang der Telefonnummer c = char(gsmSerial.read()); // " ueberlesen c = char(gsmSerial.read()); state = 1; } if (c == '"' && state == 1) { // Ende der Telefonnummer state = 2; } if (c == 13 && state == 2) { // Anfang Text der SMS c = char(gsmSerial.read()); // <LF> ueberlesen state = 3; } if (c == 13 && state == 3) { // Ende Text der SMS state = 4; } switch(state) { case 1: smsNumber += c; break; case 3: smsText += c; break; } } smsText.toUpperCase(); smsText.trim(); } // ------------------------------------------------------------- void SendMessage() { if (smsText.length() > 0) { Serial.println("Outgoing: [" + smsText + "] an " + smsNumber); cmdMessage = "AT+CMGS=\"" + smsNumber + "\"\r"; gsmSerial.print(cmdMessage); delay(1000); gsmSerial.print(smsText); delay(1000); gsmSerial.println((char)26); delay(2000); while(gsmSerial.available() > 0) { c = gsmSerial.read(); } } }
Implementierte Subrouinen:
- SendCmd sendet eine Zeichenkette (einen Befehl) an das GSM-Modem und "verschluckt" die Antwort des Modems
- CountMessages ermittelt mit Hilfe des Befehls AT+CPMS="SM" die aktuelle Anzahl der auf der SIM-Karte gespeicherten SMS (genauer: im Speicherbereich SM)
- DeleteAllMessages löscht, wie der Name schon sagt, alle gespeicherten SMS
- DeleteMessage löscht eine einzelne SMS
- ReadSms ließt eine einzelne SMS aus dem SIM-Speicher aus und speichert die Absender-Telefonnummer in der Variablen smsNumber und den Text in smsText
- SendMessage verschickt eine Nachricht (smsText) an die in smsNumber eingetragene Telefonnummer
Im Kopfteil des Programms kann die PIN festgelegt werden, die zum Übermitteln von Kommandos in der SMS-Nachricht angegeben werden muss.
Im ersten Teil der Reihe wurde beschrieben, wie die Schaltung aufgebaut ist und wie mit dem TC35 SMS versendet werden können. Im dritten Teil der Reihe soll die vorhandene Schaltung um eine Relaiskarte erweitert werden, mit der auch größere Lasten geschaltet werden können.
Hallo,
ich bekomme, wenn ich eine SMS empfange irgendwie den Text nicht angezeigt, das sieht dann immer so aus:
Ready
Incoming: [+49176******] []
An was könnte das denn liegen?
Gruß, Tommes
Um erst mal zu sehen, was genau bei Dir ankommt, würde ich eine Ausgabe der einzelnen Zeichen im seriellen Monitor einbauen. Ab Zeile 191 in etwa so:
Hallo shogun,
vielen Dank für die schnelle Hilfe! :-)
Ich habe es, wie Du sagtest eingebaut, nun erhalte ich folgendes:
Ready
AT+CMGR=1
+CMGR: "REC UNREAD",49176********",,"15/10/22,17:Incoming: [+49176********] []
Hilft das weiter? Ich habe schonmal probiert die SMS aus dem Endgerät und nicht aus dem SIM-Speicher zu lesen, da kam dann allerdings gar nix mehr! :-/
Gruß, Tommes
Oh, da habe ich doch warhaftig etwas vergessen. Die Lib SoftwareSerial definiert nur einen 64 Byte großen Empfangspuffer. Das ist für den Empfang von SMS eindeutig zu wenig. Suche in hardware/arduino/avr/libraries/SoftwareSerial/SoftwareSerial.h nach _SS_MAX_RX_BUFF und setze den Wert dort auf 1024.
Danach das urspüngliche Programm von oben noch mal kompilieren und auf den Arduino übertragen und alles sollte sofort laufen. Den Artikel werde ich gleich noch anpassen. Danke für den Hinweis!
Hallo shogun,
PERFEKT!!!:-) Danke für die schnelle Hilfe, jetzt klappt's!:-)
Echt klasse!!!
Ich hatte bis jetzt zwei Mal das Phänomen, dass sich das TC35 nach vielleicht drei oder vier Tagen durchgängigem Betrieb mit obigem Programm einfach ausgeschaltet hat. Die LED auf dem Board blinkt dann nicht mehr alle 4 Sekunden, es sieht so aus als hätte sich der GSM-Teil deaktiviert. Hat noch jemand das Problem?
Im Programm werde ich erst mal einbauen, dass unerwartete Daten auf dem seriellen Monitor ausgegeben werden:
Mal sehen, was da kommt. Evtl. müsste man die Initialisierungsroutine für das TC35 mit in den Loop aufnehmen. Ich werde wieder berichten, wenn ich etwas herausgefunden habe.
Hallo shogun,
ich habe versucht die Signalstärke vom TC35 auszulesen, und ich bekomme es einfach nicht hin: Wenn ich den AT Befehl sende kommt überhaupt gar nix zurück! Hast Du vielleicht eine Idee?
Gruß, Tommes
#include
SoftwareSerial gsmSerial(5, 6);
char cGSMSerialRead;
void setup()
{
Serial.begin(9600);
while(!Serial) {};
gsmSerial.begin(9600);
pinMode(8, INPUT);
digitalWrite(8, LOW);
pinMode(8, OUTPUT);
delay(100);
pinMode(8, INPUT);
delay(5000);
delay(2000);
}
void loop()
{
gsmSerial.println("AT+CSQ");
delay(1000);
while(gsmSerial.available() > 0)
{cGSMSerialRead = gsmSerial.read();}
delay(1000);
Serial.println("Quality:" + cGSMSerialRead);
Hallo Tommes,
Nach dem Abschicken des Befehls liest Du zwar in einer Schleife alle Zeichen vom Modem ein, gibst dann aber erst nach der Schleife das zuletzt gelesene Zeichen aus, meistens wohl LF.
Folgendes sollte funktionieren (ungetestet):
Und hier auch gleich ein Link, auf dem die umgerechneten Werte in dBm aufgelistet werden: http://m2msupport.net/m2msupport/atcsq-signal-quality/
Ja prima! :-)
Das funktioniert!!! Vielen Dank für die schnelle Antwort!:-) DAUMEN HOCH!!!
Servus shogun,
bei meinem Arduino UNO läuft jetzt dank Dir alles prima. Jetzt wollte ich das auf einen SainSmart Mega2560 laufen lassen und scheinbar kommt erst gar keine Kommunikation zwischen dem TC35 und dem Mega zustande. Hättest Du da auch eine Idee?
Gruß, Tommes
Leider nein, da muss Dir jemand anderes helfen. Viel Erfolg trotzdem. Gruß
Hallo shogun,
habs gefunden!:-) Wer lesen kann ist wohl doch klar im Vorteil; beim Mega unterstüzen nur bestimmte PINs Wechselinterrupts..., mit PIN 10,11 klappts!:-)
Hallo,
Ich habe einen TC35i das Versenden mit deinem Code Funktioniert super nur Sms Empfangen bekomme ich nicht hin.
Habe gelesen das es unterschiede gibt beim Speicherort.
Hab folgendes versucht cmdMessage = "AT+CPMS=\"SM\"";
--> cmdMessage = "AT+CPMS=\"ME\""; oder cmdMessage = "AT+CPMS=\"MT\""; doch es hat nix gebracht.
Finde auch kein anderes Beispiel im Netzt was mir weiter Hilft.
Vieleicht hast du ja eine Lösung oder einen Ansatz für mich.
Danke schonmal mfg Max
Hallo Max,
wählt als Speicherort das Endgerät. Ich glaub, der Bausatz ist kein Endgerät, habe das aber nicht getestet. Um zu testen, warum das bei Dir nicht funktioniert würde ich nach AT+CPMS="ME" einbauen, dass die Antwort des TC35 ausgegeben wird. Sollte es da wirklich Unterschiede geben (du schreibst von einem TC35i), dann sollte man evtl. erst mal testen, welche Speicherorte unterstützt werden.
zeigt eine Liste der möglichen Optionen.
Dieses und viele weitere Befehle findest du auf einer Liste im Netz. Dort finden sich auch spezielle Befehle für Siemens-Modems.
HTH
Abend,
Danke für deine schnelle Antwort.
Die Listen mit AT Befehlen habe ich schon gefunden.
habe auch versucht den Speicherort in deinem Code zu ändern in dem ich das SM durch ME oder MT ersetzt habe wie ich schon beschrieben habe. Nur brachte das nix.
Mit Beispielen meinte ich Arduino Codes die das Sms Empfangen möglich machen.
könnte man die verschiedenen AT Befehle auch über den Seriellen Monitor übermitteln und die Antworten ausgeben lassen um zb. das mit den Speicherorten zu Testen?
Wie?
Werden bei deinem Programm nur SMS mit der Pin im Seriellen Monitor angezeigt ?
Sie muss wie folgt aussehen "Pin""Leerzeichen""Befehlt(ON...)" Richtig?
lg Max
Mein TC35 gibt als unterstützte Speicherorte nur "SM" zurück, "ME" geht also nicht.
Der Code im Artikel wertet die SMS ohne Leerzeichen aus. Sende also z.B. nur "1234STATUS" an den TC35.
Das Programm im Artikel gibt ebenfalls über den seriellen Monitor aus, wenn eine SMS empfangen wurde. Wird da bei Dir etwas angezeigt? Und hast Du die Puffergröße in der LibSoftwareserial geändert?
Mit folgendem Programm können über den seriellen Monitor am PC Befehle an den TC35 geschickt werden. Das eignet sich ganz gut zum Testen, bevor man die AT-Kommandos dann in ein anderes Programm implementiert.
Zu beachten ist bei dem Programm, dass die Befehle alle mit einem Punkt abgeschlossen werden müssen. Dieser wird nicht zum TC35 weitergeschickt.
Schreib mal, wie Du vorgegangen bist und ob Du den Fehler gefunden hast.
Gruß
Ein Lob für deine schnelle Hilfe!
Also bei meinen versuchen wurde bis auf "Ready" nix angezeigt. auch der Pin 13 machte nix.
Werden im normalfall alle SMS auch die ohne Pin angezeigt?
Wenn nein liegt es vlt daran das ich ein Leerzeichen in die SMS geschrieben habe?!
Den Puffer hab ich umgestellt.
Den "Test Code" probiere ich morgen und werde von meinen Erfolgen/Misserfolgen berichten.
mfg
Hallo shogun,
Habe Heute deinen "Test Code" verwendet und verschiedene AT Befehle ausprobiert.
at+cgmm ergab das es doch kein TC35i sondern ein normales TC35 nicht wie ausgeschrieben ist.
AT+CPMS=? ergab das selbe wie bei dir das nur der SM Speicher unterstützt wird.
at+cmgd=4 um alle Narrichten zu löschen klappte leider nicht. konnte die Narrichten nur einzeln löschen mit at+cmgd="index nr. der Narricht"
AT+CMGF? ergab dass, das Board auf Textmod eingestellt war. Das war auch der Fehler nach umstellen in den PDU-Mode klappt dein Code aus dem Artikel.
Obwohl ich beim abfragen der SMS mit at+cmgl=4 an der Ausgabe keinen unterschied zwischen den Modi festgestellt habe.
Danke für deine Hilfe! Mach weiter so!
lg Max
Hallo,
Ich hab in den letzten Tagen einiges Ausprobiert und Deinen Code meinem Projekt angepasst. Allerdings bei 2 Funktionen die es benötigt scheitere ich.
1.: ich möchte verschiedene Werte von Sensoren die in floats gespeichert Werten per SMS übermitteln sobald eine SMS mit pin und STATUS empfangen wurde.
Die Operationen mit Strings und floats geht ja nicht.
Hast du eine Lösung dazu?
2.: Wenn der Arduino die Befehle ON und OFF bekommt soll die Handynr. von der die SMS kam und eine fest vorgegebene Handynr. eine Rückmeldung bekommen. allerdings kann es vorkommen das die SMS von der vorgegebenen Nummer kommt und diese soll dan keine dopelte Antwort bekommen.
Hast du auch hier einen Ansatz?
Danke schonmal lg Max
Hallo Max,
zu 1.: das String-Objekt hat einen entsprechenden Konstruktor, um aus einem Float einen String zu machen. Alternativ kannst Du auch sprintf verwenden, musst dann allerdings in Deinem Float erst mal das Komma nach hinten verschieben und ein int draus machen, da das Arduino-sprintf keine Floats kennt.
zu 2.: wenn immer an zwei Nummern versendet werden soll, kann man doch einfach testen, ob die Nummer, an die gesendet werden soll gleich der fest eingestellten Nummer ist. Hm, kann es evtl. sein, dass Du noch am Lernen von grundsätzlichen Programmiertechniken bist? Eine kleine Erklärung für Kontrollstrukturen findest Du auf arduino.cc. Das kann jedoch kein gutes Buch über Programmieren im Allgemeinen ersetzen.
Gruß
Abend,
Erst einmal Danke für deine Antwort.
Um gleich einmal zu 2. zukommmen. Da muss ich dir recht geben. Die frage hätte ich mir sparen können manchmal komm ich einfach nicht auf die einfachsten Sachen. Bei dieser Sache sollte ich die Lösung jetzt kennen.
Nur bei 1. komme ich zu keiner Funktionierenden Lösung.
Natürlich habe ich schon gegoogelt und hab einiges gefunden und Ausprobiert. z.B. die Funktion dtostrf ... nur leider bin ich noch nicht soweit dahinter gestiegen das ich es verstehe und richtig Anwenden kann. Vieleicht könntest du mir es Anhand eines konkreten Beispieles (Code) erklären. Ich tuhe mich schwer aus Berichten nur das wichtigste was ich für meinen Zweck benötige heraus zu lesen, erst Recht wenn die Texte in Englisch sind. deshalb frage ich z.B. bei dir nach wenn ich überhaupt nicht weiter komme. lg Max
Hallo Max,
mit
könntest Du zuerst einmal aus Deinem Float-Wert einen Int-Wert (um drei Zehnerpotenzen verschoben) erstellen. Diesen Int-Wert kannst Du nachher an einen String anhängen, den Du anschließend verschicken kannst:
Du wirst nicht umhin kommen, auch die anderen Kapitel des Tutorials durchzuarbeiten. Nur die für Dich gerade nützlichen Teile zeigen ja nicht, was noch so alles möglich ist.
Ich würde vorschlagen, dass wir diese Diskussion per E-Mail weiterführen (hier über das Kontakt-Formular), da bei jedem neuen Eintrag alle bisherigen Kommentatoren eine Benachrichtigungen bekommen.
Gruß
Hallo shogun,
Du hattest ja geschrieben dass dein TC35 nach drei bis vier Tagen ab und zu aussteigt, gibt's da bei Dir was Neues?
Gruß, Thomas
Bisher kann ich nur vermelden, dass das Modem nach dem Anschalten und ohne weitere Statusabfrage offensichtlich nicht abschaltet. Zu mehr bin ich leider noch nicht gekommen. Im nächsten Schritt wollte ich das Programm so erweitern, dass es zwischen den Kommandos eintreffende Statusnachrichten immer ausgibt. Vielleicht erkennt man dann daraus ja etwas.
i send 1234cmdOn but it is not working for me give me the solution sir.
The script understands the following commands only: "1234ON", "1234OFF" and "1234STATUS". Without quotes. HTH
I send this following "1234ON" to GSM TC35 but LED 13 not working to my ARDUINO UNO.
i use this montage
.
.
ARDUINO GSM TC35
GND GND
5V 3.3V
2 PIN RX
3 PIN TX
8 PIN IGT
i use this montage
.
.
ARDUINO----------------GSM TC35
GND--------------------------GND
5V-----------------------------3.3V
2 PIN-------------------------RX
3 PIN-------------------------TX
8 PIN-------------------------IGT
Hey, wenn ich "1234ON" sende, passiert bei mir nichts, woran kann das liegen?
Hallo Manuel,
kannst Du denn überhaupt korrekt mit dem TC35 kommunizieren? Ein einfaches Modem-Skript habe ich im Forum veröffentlicht. Meldet sich der TC35 korrekt beim Provider an bzw. blinkt die LED auf dem TC35 in regelmäßigen Abständen?
Da die Kommentarfunktion im Blog leider nach einigen Kommentaren unübersichtlich wird, bitte ich Dich, im Forum einen neuen Thread im Arduino Board aufzumachen. Dort können wir dann "übersichtlich" weiterdiskutieren. Danke!