SIM800L Modul

Über den Beitrag

Das SIM800L Modul ermöglicht es euch im Prinzip ein Mobiltelefon zu bauen, das ihr mit eurem Mikrocontroller steuern könnt. Der Funktionsumfang ist riesig. Die meisten von euch sind sicherlich vorrangig an SMS und Telefonie interessiert, um beispielsweise Daten in WLAN-freien Zonen zu übertragen. Es gibt aber noch vieles darüber hinaus, wie z.B. FTP, TCP/IP und HTTP Anwendungen, E-Mail, oder MMS. Man könnte ein ganzes Buch über das SIM800L Modul schreiben.

Da ich mich hier etwas beschränken muss, konzentriere ich mich auf die folgenden Themen:

Technische Eigenschaften

Das SIM800L ist ein Quadband GSM / GRPS Modul. Es deckt die Frequenzbänder GSM850, EGSM900, DCS1800 und PCS1900 ab. Um das SIM800L nutzen zu können, benötigt ihr eine 2G SIM-Karte im Mikroformat. Die Kommunikation eures Mikrocontrollers mit dem SIM800L erfolgt seriell über RX / TX und AT-Befehle.

Der Bereich für die Spannungsversorgung beträgt ungewöhnliche 3.4 bis 4.4 Volt. Deshalb, und aufgrund von Stromspitzen bis zu 2 Ampere, ist eine Spannungsversorgung über den Mikrocontroller nicht möglich. Geeignet sind Lithium-Ionen-Akkus, oder ihr setzt Schaltregler wie den LM2596 ein. Für Schaltregler braucht ihr dann aber auch ein Netzteil, das ausreichend Strom liefert.

Pinout des SIM800L Moduls
Pinout des SIM800L Moduls

Das SIM800L Modul hat die folgenden Anschlüsse:

  • Antennenanschluss (IPX U.FL, oben links / unbeschriftet).
  • NET: Antennenanschluss für Spiralantennen.
  • VCC: Spannungsversorgung (3.4 – 4.4 Volt).
  • RESET: LOW-aktiv, könnt ihr auch unverbunden lassen.
  • RX/TX: serielle Anschlüsse, Baudrate: 1200 – 115200 bps.
  • GND: zu verbinden mit GND der Spannungsversorgung und GND des Mikrocontrollers.
  • RING: standardmäßig HIGH, geht kurz auf LOW bei Anruf (auch für SMS einstellbar); nützlich für Interruptprogrammierung.
  • DTR: darüber steuert ihr Schlafmodi.
  • MIC+/MIC-: Mikrofonanschluss.
  • Speaker+/-: hier könnt ihr direkt 8 Ohm Lautsprecher anschließen und erhaltet „satte“ 1.08 Watt.

RX / TX Spannungslevel

Über das zulässige Spannungslevel der seriellen Anschlüsse des SIM800L liest man Widersprüchliches. Einige bescheinigen 5V Toleranz, einige andere sehen die Grenze bei 3.3 Volt. Laut Datenblatt liegt das Maximum hingegen bei 2.8 Volt. Dort ist auch beschrieben, wie man 3.3 Volt und 5 Volt Mikrocontroller idealerweise verbinden sollte (ab Seite 31). Ich habe lediglich einen Spannungsteiler vor RX des Moduls gesetzt und bin damit gut gefahren.

Antennen für das SIM800L Modul

Antennen und  Antennenadapter für das SIM800L Modul
Antennen und Antennenadapter für das SIM800L Modul
SIM800L Modul mit Spiralantenne

Das SIM800L Modul wird meistens mit einer oder mit mehreren Antennen angeboten. In vielen Fällen werdet ihr mit der einfachen Spiralantenne auskommen. In Gebieten mit schlechter Abdeckung, bei Störsignalen oder in abgeschirmten Gebäuden benötigt ihr unter Umständen eine größere Antenne.

Man könnte auch auf den Gedanken kommen, zwei Antennen anzuschließen. Das ist jedoch kontraproduktiv, da sie sich gegenseitig stören.

Wenn ihr euch eine Antenne mit SMA Anschluss besorgt (das ist der mit dem Schraubgewinde), dann benötigt ihr noch einen IPX UF.L auf SMA Adapter.

Stromverbrauch

Typische Verbrauchswerte sind:

  • Power Down Mode: 60 µA
  • Sleep Mode: 0.7 – 1.0 mA
  • Normal Mode: (Warten auf SMS oder Call): ca. 15 mA

Wie viel das SIM800L Modul während eines Telefonates oder bei der Datenübertragung per GRPS verbraucht, ist nicht so leicht zu beantworten, da sich kein konstanter Wert einstellt. Ich habe hier ziemlich konkrete Angaben gefunden (131 – 216 mA, je nach Frequenzband), konnte sie aber in eigenen Messungen nicht nachvollziehen. Bei mir lagen die Werte eher bei 70 mA, allerdings mit Spitzen.

Zu Beginn einer Verbindung können, wie oben schon erwähnt, Spitzen von bis zu 2 Ampere auftreten.

Anmerkungen zur SIM-Karte

How to put the SIM card into the SIM800L

Die SIM-Karte wird, wie rechts abgebildet, in den Kartenhalter gesteckt.

Ich kann euch nicht sagen, welches die ideale SIM-Karte für euch ist. Das hängt zu sehr von eurer Anwendung ab, also hauptsächlich von der zu erwartenden Frequenz an SMS oder Anrufen.

Aber ich möchte eine Erfahrung mit euch teilen. Und zwar hatte ich mir eine „IoT und M2M Prepaid“ Karte besorgt, weil das so schön passend klang. Nur leider hatte die Karte eine „+882“ Vorwahl, was für „Internationale Netzwerke“ steht. Diese Nummer ist von vielen Mobilfunkanbietern gesperrt, weil darüber auch Betrugsanrufe laufen. Außerdem kann eine Verbindung mit dieser Vorwahl hohe Kosten erzeugen. Telefonieren ging also nicht ohne Weiteres und SMS konnte ich nur vom, aber nicht zum Modul versenden. Ich habe mir dann eine andere SIM-Karte von der guten, alten Telekom besorgt. Schaut also genau hin.

Und seid vorsichtig, wenn ihr Programme zum Versenden von SMS erstellt, dass ihr nicht aus Versehen Massen davon verschickt. Bestenfalls habt ihr eine Prepaid Karte, die dann auf null gezogen ist.

Schaltung für das SIM800L Modul

So sah die von mir verwendete Basisschaltung aus:

SIM800L am Arduino Nano
SIM800L am Arduino Nano

Beachtet, dass RX des Moduls mit TX des Mikrocontrollers und TX des Moduls mit RX des Microcontrollers verbunden wird.

Für die obige Schaltung ist die Spannung an RX des Moduls:

V_{RX}=\frac{5.6}{5.6+4.7}\cdot 5.0\;=\;\sim 2.72\;[\text{V}]

Kommunikation über AT-Befehle

Der eine oder andere von euch kennt AT-Befehle vielleicht schon von den HC05 / HC06 Bluetooth Modulen oder anderen seriell gesteuerten Bauteilen. Die meisten AT-Befehle haben die Struktur (Ausnahmen bestätigen die Regel!):

  • AT+xxxx: Funktionsaufruf oder Abfrage ohne Parameter
  • AT+xxxx=yyyy: Zuweisung des Wertes yyyy zur Eigenschaft / Funktion xxxx
  • AT+xxxx?: Abfrage des Wertes xxxx
  • AT+xxxx=? Abfrage der Optionen

Eine Liste mit den vielen AT-Befehlen des SIM800L Moduls bekommt ihr hier. Es gibt alleine in diesem Dokument über 300 davon.

Zum ersten „Herumspielen“ sendet ihr die AT-Befehle am einfachsten über den seriellen Monitor der Arduino IDE. Ihr könnt aber auch genauso gut Terminalprogramme wie PuTTY oder HTerm verwenden, braucht dann aber einen USB-zu-TTL Adapter.

SoftwareSerial Sketch

Ladet den folgenden SoftwareSerial Sketch auf euer Arduino Board, um über den seriellen Monitor kommunizieren zu können:

#include <SoftwareSerial.h>
SoftwareSerial mySerial(7,8);

void setup() {
  Serial.begin(9600);
  Serial.println("Software Serial Sketch");
  mySerial.begin(9600);
}

void loop() { // run over and over
  while(mySerial.available()) {
    Serial.write(mySerial.read());
  }
  while(Serial.available()) {
    mySerial.write(Serial.read());
  }
}

Nach meiner Erfahrung kann man mit einer Baudrate von 9600 bps zuverlässig arbeiten. Bei 115200 bps gingen mir Teile von SMS verloren. Im seriellen Monitor stellt ihr dieselbe Baudrate ein und wählt „Zeilenumbruch (CR)“.

Erste Schritte

Habt ihr alles verkabelt, die SIM-Karte eingelegt und das SIM800L Modul mit Strom versorgt, kann es jetzt losgehen. Die LED auf dem SIM800L Modul sollte nach Anlegen der Stromversorgung zunächst mit einer Frequenz von ca. 0.8 Sekunden aufleuchten.

Als ersten Test gebt ihr einfach nur AT ein und bestätigt mit Enter oder klickt auf „Senden“. Das Modul sollte mit OK antworten. Tut es das nicht, dann überprüft noch einmal die Verkabelung und die Einstellungen des seriellen Monitors.

Wenn alles OK ist, könnt ihr jetzt Informationen über das Modul abfragen:

ATI → Antwort: SIM800 R14.18

Eventuell ist eure SIM-Karte durch eine PIN geschützt. Gebt Folgendes ein:

AT+CPIN? →  bei Antwort:  +CPIN: READY ist keine PIN notwendig; bei Antwort: +CPIN: SIM PIN müsst ihr die PIN einschließlich der Anführungszeichen eingeben:

AT+CPIN="xxxx" → Antwort: OK; bei falschem PIN oder wenn die PIN schon eingegeben wurde: ERROR.

Spätestens nach der Eingabe des korrekten Pins sollte sich das Modul mit dem Netz verbinden und die LED im 3-Sekunden-Takt blinken.

Eine sehr nützliche Funktion ist die Abfrage des Akkustatus:

AT+CBC → Antwort: +CBC: 0,75,4005

Das bedeutet: „0“ – Akku lädt nicht („1“ hieße der Akku lädt). „75“ heißt, der Akku hat noch 75 % Kapazität. „4005“ steht für 4005 mV Spannung.

Die Signalstärke eures Netzes erfahrt ihr so:

AT+CSQ → Antwort: +CSQ: 20,0

Dabei bedeutet die erste Zahl: 

  • 0„:  -115 dBm oder weniger
  • 1„:  -111 dBm
  • 2 … 30″: -110 … -54 dBm
  • 31„:  -52 dBm oder größer
  • 99„:  unbekannt oder nicht messbar

In welchem Netz ihr seid, fragt ihr folgendermaßen ab:

AT+COPS? → Antwort: +COPS: 0,0,"D1"

Die wesentliche Information steht hinter dem zweiten Komma. Hier ist es also das D1-Netz. Die anderen Zahlen codieren Modus und Format. Schaut in die AT-Befehlsliste, wenn ihr näheres dazu wissen möchtet. 

Nützlich ist auch diese Abfrage:

AT+CREG? → Antwort: +CREG: 0,1

Die zweite Zahl bedeutet: „1“ Registered, home network; „5“ Registered: Roaming. Erhaltet ihr eine 2, 3 oder 4, seid ihr nicht im Netz registriert.

Euren Service Provider (gem. SIM-Karte) erfahrt ihr durch:

AT+CSPN? → Antwort: +CSPN: "Telekom.de",0

Sleep und Power Down Modi

Den Power-Down Modus aktiviert ihr mit:

AT+CPOWD=1 → Antwort: NORMAL POWER DOWN

Mit dem Parameter 0 geht das SIM800L Modul sofort und ohne Rückmeldung aus. Leider scheint der Power-Down Modus aber nicht stabil zu sein. Nach einiger Zeit schaltet sich mein Modul immer wieder von allein an. Ich konnte bisher nicht klären, warum das so ist.

Besser funktioniert der Schlafmodus (Slow Clock). Und so wird der Schlafmodus gestartet:

AT+CSCLK=x → Antwort: +CSCLK: x mit x = 0, 1, 2:

  • 0: normaler (Wach-)Modus.
  • 1: Slow Clock Modus 1; um zwischenzeitlich aus diesem Slow Clock Modus zu gehen, zieht ihr DTR auf GND. Das ist sehr praktisch. Wenn DTR wieder HIGH ist, geht das Modul zurück in den Schlafmodus. Im Normalzustand ist DTR durch einen internen Pull-Up Widerstand auf HIGH gezogen.
  • 2: Slow Clock Modus 2; zum Aufwecken sendet ihr zweimal kurz hintereinander AT+CSCLK=0.

Im Sleep Modus ist das SIM800L Modul für SMS und Anrufe erreichbar.

SMS senden

Um eine SMS zu versenden, müsst ihr ggf. eure PIN eingeben und das Modul mit AT+CMGF=1 in den SMS Textmodus bringen. Evtl. müsst ihr noch ein delay einbauen, um dem Modul Zeit zu geben, sich zu verbinden.

Das eigentliche Versenden der SMS leitet ihr mit der Eingabe der Telefonnummer des Empfängers ein:

AT+CMGS="+491738xxxxxx"

Daraufhin erhaltet ihr ein Promptzeichen (>). Ihr gebt den SMS Text ein und schließt die Eingabe mit Strg+Z (ASCII-Code Nr. 26) und dann Enter ab. So die Theorie. Praktisch habe ich es nicht hinbekommen, ein Strg+Z über den seriellen Monitor zu senden, da dieser nur sichtbare Zeichen verarbeitet. Mittels eines Sketches (s.u.) ist das aber kein Problem. Ein Strg+Z erzeugt ihr über Serial.write(26)

Alle anderen Befehle übermittelt ihr mit Serial.println(). Anführungszeichen müsst ihr ein Backslash voranstellen, damit sie nicht als Ende der println-Anweisung interpretiert werden.

Die SoftwareSerial Abfrage habe ich als separate Funktion (updateSerial) ausgelagert. Da die Reaktion auf einen AT Befehl ein wenig dauern kann,  habe ich eine Wartezeit (wt_ms = 100 ms) eingefügt. Eventuell müsst ihr den Wert bei euch anpassen.

In der Hauptschleife (loop) könnt ihr weitere Befehle über den seriellen Monitor eingeben. Hier braucht ihr keine Wartezeit, da ihr permanent abfragt.

So sieht der vollständige Sketch aus:

#include <SoftwareSerial.h>
SoftwareSerial mySerial(7,8);
const unsigned int wt_ms = 100; // wait ms

void setup() {
  Serial.begin(9600);
  Serial.println("Send SMS Sketch");
  mySerial.begin(9600);
  delay(1000);
  updateSerial(wt_ms);
  mySerial.println("AT"); // to check if the module is connected
  updateSerial(wt_ms);
  mySerial.println("AT+CPIN=\"xxxx\""); // if Pin is needed
  updateSerial(wt_ms);
//  delay(8000); // maybe needed to setup connection to the network
//  mySerial.println("AT+CCID"); // optional check
//  updateSerial(wt_ms);
//  mySerial.println("AT+CBC"); // optional check
//  updateSerial(wt_ms);
//  mySerial.println("AT+COPS?"); // optional check
//  updateSerial(wt_ms);
//  mySerial.println("AT+CSQ"); // optional check
//  updateSerial(wt_ms);
//  mySerial.println("AT+CREG?"); // optional check
//  updateSerial(wt_ms);
  mySerial.println("AT+CMGF=1"); // SMS text mode
  updateSerial(wt_ms);
  mySerial.println("AT+CMGS=\"+491738xxxxxx\"");
  updateSerial(wt_ms);
  mySerial.print("Hi Wolle, this is a message from your SIM800L Module."); 
  updateSerial(wt_ms);
  mySerial.write(26);
  mySerial.println("");
  updateSerial(wt_ms);
}

void loop() { 
  updateSerial(0);
}
  
void updateSerial(unsigned int wait_ms){
  String dataString = "";
  delay(wait_ms);
  if(mySerial.available()) {
    dataString = mySerial.readString();
    Serial.println(dataString);
  }
  while(Serial.available()) {
    mySerial.write(Serial.read());
  }
}

Vielleicht ist euch aufgefallen, dass die Antworten des SIM800L Moduls in diesem Sketch mit mySerial.readString() ausgelesen und in einer Variable gespeichert werden. Das hat den Vorteil, dass man die Antwort des Moduls bearbeiten oder auswerten kann.

Ausgabe auf seriellem Monitor und Smartphone

So sahen die Ausgaben aus:

Ausgabe von send_sms_from_sim800l.ino
Ausgabe von send_sms_from_sim800l.ino
SMS auf dem Smartphone
SMS auf dem Smartphone

Auswerten von Strings

Zum Auswerten und Bearbeiten von Strings gibt es drei sehr nützliche Funktionen:

  • indexOf() / lastIndexOf(): liefert die nächste oder letzte Position der übergebenen Zeichenkette im String. Wird die Zeichenkette nicht gefunden, dann geben die Funktionen -1 zurück.
  • parseInt(): sucht nach der nächsten Zahlenfolge in einem String und liefert sie als Integerwert.
  • substring(x,y): schneidet eine Zeichenfolge aus einem String (Position x bis y-1).

Als ein kleines Beispiel für die substring() Funktion zeige ich, wie ihr aus der Modulantwort auf eine „COPS“-Abfrage gezielt den Namen des Netzes herausschneidet. In meinem Fall also das „D1″ aus +COPS: 0,0,“D1“.

#include <SoftwareSerial.h>
SoftwareSerial mySerial(7,8);
const int wt_ms = 100; // wait ms
String moduleAnswer = "";

void setup() {
  String irg = "AT+COPS";
  Serial.begin(9600);
  Serial.println("Evaluate Answer");
  mySerial.begin(9600);
  delay(1000);
  
  mySerial.println("AT+COPS?");
  updateSerial(wt_ms);
  
  moduleAnswer = moduleAnswer.substring(1);   // does not work without, don't know why!
  int pos1 = moduleAnswer.indexOf("\"");      // first position of " 
  int pos2 = moduleAnswer.lastIndexOf("\"");  // last position of "
  moduleAnswer = moduleAnswer.substring(pos1+1,pos2);
  Serial.print("The module is connected to ");
  Serial.println(moduleAnswer);
}

void loop(){
}
  
void updateSerial(unsigned int wait_ms){
  delay(wait_ms);
  if(mySerial.available()) {
    moduleAnswer = mySerial.readString();
  }
  while(Serial.available()) {
    mySerial.write(Serial.read());
  }
}

Warum ich die Zeile:

moduleAnswer = moduleAnswer.substring(1);

einfügen musste, weiß ich nicht. Ohne das ging es nicht.

Ausgabe von evaluate_module_answer.ino
Ausgabe von evaluate_module_answer.ino

SMS empfangen

Um SMS zu empfangen, müsst ihr zunächst wieder mit dem Netz verbunden sein und den SMS Textmodus aktivieren. Zusätzlich definiert ihr, wie eingehende SMS zu behandeln sind:

AT+CNMI=1,2.

Die hier verwendeten Parameter sorgen dafür, dass der SMS-Text direkt auf dem seriellen Monitor erscheint.

#include <SoftwareSerial.h>
SoftwareSerial mySerial(7,8);
const int wt_ms = 100; // wait ms

void setup() {
  Serial.begin(9600);
  Serial.println("Receive SMS Sketch");
  mySerial.begin(9600);
  delay(1000);
  updateSerial(wt_ms);
  mySerial.println("AT+CPIN=\"xxxx\""); // in your SIM card has a PIN
  updateSerial(wt_ms);
  mySerial.println("AT+CREG?"); // optional check
  updateSerial(wt_ms);
  mySerial.println("AT+CMGF=1"); 
  updateSerial(wt_ms);
  mySerial.println("AT+CNMI=1,2"); // defines how incoming SMS are handled
  updateSerial(wt_ms);
}

void loop() { 
  updateSerial(0);
}
  
void updateSerial(unsigned int wait_ms){
  String bufString = "";
  delay(wait_ms);
  if(mySerial.available()) {
    bufString = mySerial.readString();
  }
  if(bufString != ""){
    Serial.println(bufString);
  }
  while(Serial.available()) {
    mySerial.write(Serial.read());
  }
}

Und so sieht es auf dem seriellen Monitor aus, wenn eine SMS eintrifft:

Empfangene SMS
Empfangene SMS

Ein alternativer Modus zum Verarbeiten von SMS ist: AT+CNMI=2,1 (anstelle „1,2“). Damit wird die SMS gespeichert. Ihr bekommt auf dem seriellen Monitor lediglich eine Meldung wie z.B.:

+CMTI: "ME",21

Das bedeutet, dass die SMS Nr. 21 im Telefonspeicher („ME“ = Mobile Equipment) gespeichert wurde. Ihr könnt die gespeicherten SMS mit AT+CMGL="ALL" auflisten:

Anstelle von „ALL“ könnt ihr auch „REC UNREAD“ (received unread) oder „REC READ“ (received read) als Parameter verwenden.

Mit AT+CMGD=21 löscht ihr die SMS Nr 21. Ihr könnt auch alle SMS auf einmal löschen. Dazu verwendet ihr die Anweisung AT+CMGDA="DEL ALL".

Den Mikrocontroller per SMS steuern

Ihr könnt euren Mikrocontroller per SMS steuern. Das möchte ich hier am Beispiel von zwei LEDs, die ich an die Pins 9 und 10 angeschlossen habe, demonstrieren.

Variante 1: mit indexOf()

Die beiden LEDs habe ich led1 und led2 genannt. Wenn eine SMS eingeht, sucht der Sketch mithilfe der Funktion indexOf, ob led1 oder led2 im Text enthalten ist. Dann sucht er, ob das Schlüsselwort „on“ enthalten ist. Ist das der Fall, wird led1 bzw. led2 eingeschaltet. Wenn kein „on“ enthalten ist, wird die led1 bzw. led2 ausgeschaltet. Beispiele:

  • led1on: led1 wird angeschaltet
  • blablaled2blablaonblabla: led2 wird angeschaltet
  • led1: led1 wird ausgeschaltet.
#include <SoftwareSerial.h>
SoftwareSerial mySerial(7,8);
const int led1_pin = 9;
const int led2_pin = 10;
const int wt_ms = 100; // wait ms

void setup() {
  String moduleAnswer = "";
  Serial.begin(9600);
  Serial.println("Control LED Sketch");
  mySerial.begin(9600);
  pinMode(led1_pin, OUTPUT);
  pinMode(led2_pin, OUTPUT);
  
  delay(1000);
  updateSerial(wt_ms, moduleAnswer);
  mySerial.println("AT+CPIN=\"xxxx\"");
  updateSerial(wt_ms, moduleAnswer);
  mySerial.println("AT+CREG?"); 
  updateSerial(wt_ms, moduleAnswer);
  mySerial.println("AT+CMGF=1"); 
  updateSerial(wt_ms, moduleAnswer);
  mySerial.println("AT+CNMI=1,2");
  updateSerial(wt_ms, moduleAnswer);
}

void loop() { 
  String smsText = "";
  updateSerial(0, smsText);
    
  if(smsText != ""){
    smsText = smsText.substring(1);
    Serial.print("Text: ");
    Serial.println(smsText);
    if(smsText.indexOf("led1")>0){
      
      if(smsText.indexOf("on")>0){
        digitalWrite(led1_pin, HIGH);
      }
      else{
        digitalWrite(led1_pin, LOW);
      }
    }
    
    if(smsText.indexOf("led2")>0){
      if(smsText.indexOf("on")>0){
        digitalWrite(led2_pin, HIGH);
      }
      else{
        digitalWrite(led2_pin, LOW);
      }  
    }  
  }
}
  
void updateSerial(unsigned int wait_ms, String &bufString){
  bufString = "";
  delay(wait_ms);
  if(mySerial.available()) {
    bufString = mySerial.readString();
  }
  if(bufString != ""){
    Serial.println(bufString);
  }
  while(Serial.available()) {
    mySerial.write(Serial.read());
  }
}

Das Strings recht viel Speicher kosten, übergebe ich „moduleAnswer“ und „smsText“ als Referenz (&bufString). Das bedeutet, dass in der Funktion mit dem Original gearbeitet wird. Entsprechend gibt es keinen Rückgabewert.

Variante 2: mit parseInt()

Bei dieser Variante steht die Pinnummer und der gewünschte Pinzustand (0 oder 1) direkt im SMS Text. Beispiele:

  • *10*1*: Pin 10 geht HIGH
  • *9*0*: Pin 9 geht LOW
#include <SoftwareSerial.h>
SoftwareSerial mySerial(7,8);
const int led1_pin = 9;
const int led2_pin = 10;
const int wt_ms = 100; // wait ms

void setup() {
  Serial.begin(9600);
  Serial.println("Control LED Sketch");
  mySerial.begin(9600);
  pinMode(led1_pin, OUTPUT);
  pinMode(led2_pin, OUTPUT);
  
  delay(1000);
  updateSerial(wt_ms);
  mySerial.println("AT+CPIN=\"xxxx\"");
  updateSerial(wt_ms);
  mySerial.println("AT+CREG?"); 
  updateSerial(wt_ms);
  mySerial.println("AT+CMGF=1"); 
  updateSerial(wt_ms);
  mySerial.println("AT+CNMI=1,2");
  updateSerial(wt_ms);
}

void loop() { 
  waitForSMS();
}
  
void waitForSMS(){
  int led = 0;
  bool state = false;
  if(mySerial.available()){
    while(((char)mySerial.read())!= '\n'){}
    led = mySerial.parseInt();
    state = mySerial.parseInt();
    digitalWrite(led, state);
  }
}


void updateSerial(unsigned int wait_ms){
  String bufString = "";
  delay(wait_ms);
  if(mySerial.available()) {
    bufString = mySerial.readString();
  }
  if(bufString != ""){
    Serial.println(bufString);
  }
  while(Serial.available()) {
    mySerial.write(Serial.read());
  }
}

Telefonieren

Telefonieren mit dem SIM800L ist noch einfacher als SMS zu versenden. Eigentlich müsst ihr nur dafür sorgen, dass euer SIM800L Modul mit dem Netz verbunden ist und Serial/SoftwareSerial wie bei den anderen Sketchen einrichten:

#include <SoftwareSerial.h>
SoftwareSerial mySerial(7,8);
const int wt_ms = 100; // wait ms 

void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
  Serial.println("Call or wait for a call");
  delay(1000);
  mySerial.println("AT");  // optional check
  updateSerial(wt_ms);
  mySerial.println("AT+CPIN=\"++++\"");
  updateSerial(wt_ms);
  mySerial.println("AT+CREG?"); // optional check
  updateSerial(wt_ms);
}
void loop() { 
  updateSerial(0);
}
  
void updateSerial(unsigned int wait_ms){
  String dataString = "";
  delay(wait_ms);
  if(mySerial.available()) {
    dataString = mySerial.readString();
    if(dataString != ""){
      Serial.println(dataString);
    }
  }
  while(Serial.available()) {
    mySerial.write(Serial.read());
  }
}

Ausgehender Anruf

Einen Anruf startet ihr mit dem folgenden AT-Befehl:

ATD+ +xxxxxxxxxxxx;

Ersetzt xxxxxxxxxxxx durch die zu wählende Nummer, beginnend mit dem Ländercode. Mit ATH beendet ihr das Gespräch. Vergesst nicht das Semikolon am Ende (kein Schreibfehler!).

Eingehender Anruf

Verwendet denselben Sketch, wenn ihr euer SIM800L Modul anrufen wollt. Der Anruf macht sich akustisch bemerkbar, durch „RING“ im seriellen Monitor und durch ein kurzes LOW Signal am RING-Pin. Letzteres Signal könntet ihr nutzen, um euren Mikrocontroller aus einem Sleep Modus zu wecken. So lassen sich stromsparende Projekte umsetzen.

Mit ATA nehmt ihr den Anruf an, mit ATH lehnt ihr den Anruf ab.

Eingehender Anruf auf dem seriellen Monitor
Eingehender Anruf auf dem seriellen Monitor

Telefonie-Einstellungen

Hier noch ein paar nützliche Einstellungen. Die Gesprächslautstärke fragt ihr folgendermaßen ab:

AT+CLVL? → Antwort: +CLVL: 33

Und so stellt ihr sie ein:

AT+CLVL=x mit x = 0 – 100

Die Klingeltonlautstärke ist davon unabhängig (auch 0-100):

AT+CRSL? (Abfrage) / AT+CRSL=x (Einstellung)

Es gibt 20 Klingelsounds, die ihr so einstellt:

AT+CALS=x mit x = 0 – 19

Den Mikrocontroller per Anruf steuern

Ich habe mir dann noch überlegt, wie man den Mikrocontroller per Anruf steuern kann. Eine LED anzuschalten, ist über das „RING“ sehr einfach. Genauso einfach ist es, die LED mit einem weiteren Anruf wieder auszuschalten. Allerdings kommt man dabei auch leicht durcheinander. Schön wäre es, eine Rückmeldung zu erhalten, ob die LED an oder aus ist.

Das habe ich mit dem folgenden Sketch realisiert. Wenn ein Anruf eingeht, dann prüft der Sketch den Status der LED. Sollte sie angeschaltet sein, wird der Anruf sofort abgelehnt. Ist sie hingegen aus, passiert erst einmal nichts. In beiden Fällen wird 10 Sekunden gewartet und die weiteren eingehenden „Rings“ gezählt. War die LED ausgeschaltet, wird der Anruf jetzt abgelehnt. Dadurch zählt der Sketch je nach LED Zustand eine unterschiedliche Anzahl von „Rings“. Entsprechend wird die LED an- oder ausgeschaltet. Und der Anrufer weiß, dass bei sofortiger Ablehnung des Anrufes die LED aus war und jetzt angeschaltet ist.

#include <SoftwareSerial.h>
SoftwareSerial mySerial(7,8);
const int ledPin = 9;
const int wt_ms = 100; // wait ms

void setup() {
  String moduleAnswer = "";
  Serial.begin(9600);
  Serial.println("Control LED by Call");
  mySerial.begin(9600);
  pinMode(ledPin, OUTPUT);
  delay(1000);
  updateSerial(wt_ms, moduleAnswer); 
  mySerial.println("AT+CPIN=\"xxxx\""); // in case a PIN is required
  updateSerial(wt_ms, moduleAnswer); 
  mySerial.println("AT+CREG?"); // optional check
  updateSerial(wt_ms, moduleAnswer);
}

void loop() { 
  String ring = "";
  int noOfRings = 0;
  unsigned long callTime = 0;
  const unsigned long threshold = 10000; 
  
  updateSerial(0, ring); 
  
  if(ring != ""){
    if(ring.indexOf("RING")>0){
      noOfRings++;
      callTime = millis();
      ring = "";
      if(digitalRead(ledPin)){
        mySerial.println("ATH");
      }
      
      while((millis()-callTime)<threshold){
        updateSerial(0, ring); 
        if(ring != ""){
          if(ring.indexOf("RING")>0){
            noOfRings++;
            ring = "";
          }
        }
      }
      if(noOfRings == 1){
        digitalWrite(ledPin, LOW);
      }
      else{
        digitalWrite(ledPin, HIGH);
        mySerial.println("ATH");
      }
    }
  }
}
  
void updateSerial(unsigned int wait_ms, String &bufString){
  bufString = "";
  delay(wait_ms);
  if(mySerial.available()) {
    bufString = mySerial.readString();
  }
  if(bufString != ""){
    Serial.println(bufString);
  }
  while(Serial.available()) {
    mySerial.write(Serial.read());
  }
}

Achtung: Ein abgelehnter Anruf ist nicht unbedingt kostenfrei! Ggf. müsst ihr unter anderem die Einstellung, dass bei „Besetzt“ der SMS Benachrichtigungsservice angeboten wird, abstellen. Prüft das lieber bevor eure Telefonrechnung explodiert!

Den Zugriff beschränken – Whitelist

Die SMS- und die Anrufmethode bergen grundsätzlich die Gefahr, dass irgendjemand, aus Versehen oder mit böser Absicht, unbefugt euer Gerät steuert. Um das zu verhindern, könnt ihr eine Whitelist einrichten. Damit stellt ihr ein, für welche Telefonnummern euer SIM800L erreichbar sein soll. Anrufe von Geräten mit anderen Telefonnummern lehnt das SIM800L ab. Der Anrufer erhält ein Besetztzeichen.

Und so geht’s:

AT+CWHITELIST=mode,index,phone_number

Der Modus (mode) legt fest, ob die Whitelist für Anrufe, SMS oder beides wirksam ist:

  • 0: Whitelist deaktiviert
  • 1: Anruf Whitelist
  • 2: SMS Whitelist
  • 3: Anruf und SMS Whitelist

Der Modus gilt immer für die gesamte Whitelist. Das bedeutet, dass unterschiedliche Einstellungen für unterschiedliche Nummern nicht möglich sind.

Index ist die Nummer des Eintrages (1-30). Die phone_number ist die Telefonnummer mit Ländervorwahl, aber ohne „+“ – wie ich nach mehrstündigem Herumprobieren und Recherchieren herausbekam.

AT+CWHITELIST? fragt die Whitelist ab und AT+CWHITELIST=0 deaktiviert die gesamte Liste.

Hier ein Beispiel:

Einsatz der Whitelist für das SIM800L Modul
Einsatz der Whitelist

Zeit abfragen

Ihr könnt das SIM800L Modul auch als RTC (Real Time Clock) nutzen. Mit AT+CCLK? fragt ihr die Uhrzeit ab.

+CCLK: "04/01/01,00:01:31+00"

Das Format ist:  „YY/MM/DD,hh:mm:ss±tz“, also „Jahr/Monat/Tag,Stunden:Minuten:Sekunden+tz“, wobei tz die Abweichung von GMT in Viertelstunden ist. Das Modul startet nach Trennung von der Spannungsversorgung immer wieder um 0 Uhr am 01.01.2004. Ihr müsst die Uhrzeit also stellen. Dafür gibt es drei Möglichkeiten:

  1. Manuell stellen
  2. Über die Systemzeit des Computers
  3. Abfrage über einen NTP Server

Manuelles Einstellen der Zeit

Ich denke, die folgenden Ein-/Ausgaben auf dem seriellen Monitor sind selbsterklärend:

Zeiteinstellung mit CCLK
Zeiteinstellung mit CCLK

Einstellen nach der Systemzeit

Bei dieser Methode wird die Zeit mithilfe der Systemzeit des Computers gestellt. Dazu müsst ihr erst einmal dem Mikrocontroller die Zeit „beibringen“. Dazu ist die Soft-RTC Variante der RTCLib gut geeignet. Dann überträgt der Mikrocontroller die Zeit auf das SIM800L Modul. Ich möchte nicht zu weit ins Detail gehen. Wie ihr mit DateTime und RTC_Millis Objekten arbeitet, habe ich in meinem Beitrag zum RTC Modul DS3231 erklärt.

Ich bringe die Methode nur der Vollständigkeit halber. Besser ist die dritte Methode, mit der ihr die Zeit immer wieder nachstellen könnt.

#include "RTClib.h"
#include <SoftwareSerial.h>
RTC_Millis rtc;
SoftwareSerial mySerial(7,8);
const int wt_ms = 100; // wait ms 

void setup () {
  Serial.begin(9600); 
  mySerial.begin(9600);
  Serial.println("Set time and date by system time");
  delay(1000);
  Serial.println("Time before setting: ");
  mySerial.println("AT+CCLK?");
  updateSerial(wt_ms);
  Serial.println("Time after setting: ");
  rtc.begin(DateTime(F(__DATE__), F(__TIME__))); // sets soft-RTC time by system time
  setTimeBySystemTime();
}

void loop () {
  mySerial.println("AT+CCLK?");
  updateSerial(wt_ms);
  delay(3000);
}

void setTimeBySystemTime(){
  DateTime now = rtc.now();
  String dateTimeString = String(now.year()-2000);
  dateTimeString += "/";
  dateTimeString += byteToStringAndFormat(now.month());
  dateTimeString += "/";
  dateTimeString += byteToStringAndFormat(now.day());
  dateTimeString += ",";
  dateTimeString += byteToStringAndFormat(now.hour());
  dateTimeString += ":";
  dateTimeString += byteToStringAndFormat(now.minute());
  dateTimeString += ":";
  dateTimeString += byteToStringAndFormat(now.second());
  dateTimeString += "+08"; // change according to your time zone 
  mySerial.print("AT+CCLK=\"");
  mySerial.print(dateTimeString);
  mySerial.println("\"");
  updateSerial(wt_ms);
}

String byteToStringAndFormat(byte b){
  String str = "";
  str = String(b);
  if(b<10){
    str = "0" + str;
  }
  return str;    
}

void updateSerial(unsigned int wait_ms){
  String dataString = "";
  delay(wait_ms);
  if(mySerial.available()) {
    dataString = mySerial.readString();
    if(dataString != ""){
      Serial.println(dataString);
    }
  }
  while(Serial.available()) {
    mySerial.write(Serial.read());
  }
}

So sieht dann die Ausgabe aus:

Zeiteinstellung über die Systemzeit
Zeiteinstellung über die Systemzeit

Einstellen der Zeit über NTP Server

Ihr könnt die Uhrzeit des SIM800L auch mit einem NTP (Network Time Protocoll) Server synchronisieren. Das ist eine GPRS Anwendung, für die ihr eine Reihe von „SAPBR“ Befehlen ausführen müsst. Im Sketch habe ich einige Kommentare eingefügt. Ansonsten schaut bitte in die AT-Befehlsliste. Die „CNTP“ Befehle für den NTP Server findet ihr in einem separaten Dokument, der NTP Application Note.

#include <SoftwareSerial.h>
SoftwareSerial mySerial(7,8);
const int wt_ms = 100; // wait ms

void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
  Serial.println("Get Time");
  delay(1000);
  mySerial.println("AT");  // optional check
  updateSerial(wt_ms);
  mySerial.println("AT+CPIN=\"xxxx\""); // if PIN is required
  updateSerial(wt_ms);
  mySerial.println("AT+CREG?"); // optional check
  updateSerial(wt_ms);
  mySerial.println("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\""); // set GPRS connection
  updateSerial(wt_ms);
  mySerial.println("AT+SAPBR=3,1,\"APN\",\"internet\""); // set APN name
  updateSerial(wt_ms);
  mySerial.println("AT+SAPBR=3,1,\"USER\",\"\""); // username empty
  updateSerial(wt_ms);
  mySerial.println("AT+SAPBR=3,1,\"PWD\",\"\"");  // password empty
  updateSerial(wt_ms);
  mySerial.println("AT+SAPBR=1,1"); // set rate
  updateSerial(wt_ms);
  mySerial.println("AT+SAPBR=2,1");  // connect
  updateSerial(wt_ms);
  mySerial.println("AT+CNTPCID=1"); // set GPRS Bearer Profile’s ID
  updateSerial(wt_ms);
  int timeZone = 2; // local time = UTC + timeZone
  int timeVal = timeZone*4;
  mySerial.print("AT+CNTP=\"0.de.pool.ntp.org\","); // replace by your country ntp server
  mySerial.println(timeVal);
  updateSerial(wt_ms);
  mySerial.println("AT+CNTP"); // synchronize time
  updateSerial(wt_ms);

  mySerial.println("AT+CCLK?"); // query local (module) time
  updateSerial(wt_ms);
  
  // close connection:
  mySerial.println("AT+SAPBR=0,1");
} 
  
void loop() { 
  updateSerial(0);
}
  
void updateSerial(unsigned int wait_ms){
  String dataString = "";
  delay(wait_ms);
  if(mySerial.available()) {
    dataString = mySerial.readString();
    if(dataString != ""){
      Serial.println(dataString);
    }
  }
  while(Serial.available()) {
    mySerial.write(Serial.read());
  }
}

Noch eine Bemerkung zur timeZone: Einige Zeitzonen haben keine ganzstündigen Verschiebungen. Deswegen wird Server die Verschiebung in Viertelstunden übergeben.

SIM800L Modul mit Bibliothek steuern

Ich habe mir verschiedene Bibliotheken angeschaut und halte GSMSim von Erdem Arslan am besten. Ihr könnt sie über den Library Manager installieren oder hier direkt von GitHub herunterladen. Allerdings funktionieren die Beispielsketche nicht ohne Weiteres auf einem Arduino UNO. Unten findet ihr den angepassten Beispielsketch zum Versenden von SMS.

#include <GSMSimSMS.h>
#include <SoftwareSerial.h>
#define RESET_PIN 10 // you can use any pin.

SoftwareSerial Serial1(6,7);
GSMSimSMS sms(Serial1, RESET_PIN); // GSMSimSMS inherit from GSMSim. You can use GSMSim methods with it.

void setup() {
  Serial1.begin(9600); // If you don't change module baudrate, it comes with auto baudrate.
  Serial.begin(9600); // Serial for debug...

  // Init module...
  sms.init(); // use for init module. Use it if you don't have any valid reason.

  Serial.print("Set Phone Function... ");
  Serial.println(sms.setPhoneFunc(1));
  delay(1000);

  //Serial.println("Enter Pin Code:...");
  //Serial.println(sms.enterPinCode("xxxx"));
  //delay(3000);

  Serial.print("is Module Registered to Network?... ");
  Serial.println(sms.isRegistered());
  delay(1000);

  Serial.print("Signal Quality... ");
  Serial.println(sms.signalQuality());
  delay(1000);

  Serial.print("Operator Name... ");
  Serial.println(sms.operatorNameFromSim());
  delay(1000);

  Serial.print("Init SMS... ");
  Serial.println(sms.initSMS()); // Its optional but highly recommended. Some function work with this function.
  delay(1000);

  Serial.print("List Unread SMS... ");
  Serial.println(sms.list(true)); // Its optional but highly recommended. Some function work with this function.
  delay(1000);

  Serial.print("SMS to any number... ");
  Serial.println(sms.send("+49173xxxxxxx", "SMS test message")); // only use ascii chars please
  delay(1000);
}

void loop() { 
}

Alles in allem würde ich aber raten, ohne Bibliothek zu arbeiten. Ihr seid einfach flexibler.

Anhang – Versuche zur Ortsbestimmung

Theoretisch lässt sich der Standort des SIM800L bestimmen. Um es vorwegzunehmen, ich erhalte dabei „Location Error“. Es könnte sein, dass das mit meinem Standort zusammenhängt und es anderswo funktioniert. Normalerweise veröffentliche ich nichts, was vielleicht funktionieren könnte. Da ich jedoch viele Stunden in das Problem investiert habe und einige Teilprobleme, mit denen andere Probleme hatten, lösen könnte, möchte ich meine Erfahrungen teilen.

CIPGSMLOC funktioniert nicht mehr

Mithilfe des AT-Befehls AT+CIPGSMLOC=1,1 und einigen vorbereitenden Einstellungen konnte man bis vor einiger Zeit den Standort in Längen- und Breitengrad bestimmen. Die Methode basiert aber auf einem Dienst, der leider abgeschaltet worden ist. Dieser Weg ist also verbaut.

Alternativ gibt es die „CLBS“ AT-Befehle, die in der Location_Application_Note beschrieben werden. Allerdings ist dazu ein Update der Firmware des SIM800L erforderlich.

Update der Firmware auf Version 1418B05SIM800L24

Vorbereitungen

Hardwareseitig braucht Ihr einen USB-zu-TTL Adapter, den ihr für wenige Euro bei Amazon und Co bekommt. Dann benötigt ihr die Firmware Version 1418B05SIM800L24. Die gibt es zum Beispiel hier auf Github. Ladet die ZIP-Datei herunter und entpackt sie irgendwo. Des Weiteren braucht ihr das Programm SIM800_Series_download_Tools_Customer_v1.19 zum Upload der Firmware. Das bekommt ihr z.B. hier. Ladet die rar-Datei herunter und entpackt sie. Der Ort ist nicht wichtig. Im entpackten Ordner findet ihr das Programm Flash_tool.exe.

Verkabelt alles folgendermaßen:

Schaltung zum Upload neuer Firmware für das SIM800L Modul
Schaltung zum Upload neuer Firmware

Der Spannungsteiler (5.6 kΩ / 4.7 kΩ) bezieht sich auf einen 5V Adapter. Wie weiter oben erwähnt, gibt es Stimmen, die sagen, die SIM800L Pins seien 5V tolerant. Ihr müsst selbst entscheiden, wie vorsichtig ihr sein wollt.

Aufspielen der Firmware

Nun startet Flash_tool.exe. Klickt auf „Image Folder“ und wählt die zuvor heruntergeladene und entpackte Firmware Datei. Stellt SIM800L, UART und Baudrate 115200 ein.  Als „Com“ wählt ihr den Port eures Adapters. „Erase Type“ ist „Erase Source Code And User Data“:

Firmware Upload auf das SIM800L Modul mit Flash_tool.exe
Firmware Upload auf das SIM800L Modul mit Flash_tool.exe

Klickt auf „Start Download“. Dann nehmt ihr das SIM800L kurz vom Strom und verbindet es wieder. Der Upload (hier Download genannt) sollte nun in ca. 10 Sekunden beginnen.

Nach ein paar Minuten ist die Firmware auf dem Modul. Trennt es wieder kurzfristig vom Strom, um es neu zu starten.

Versuch der Ortsbestimmung

Mit dem folgenden Sketch scheint alles zu funktionieren, bis zur eigentlichen Ortsbestimmung mit AT+CLBS=1,1. Die Antwort lautet +CLBS: 1. Das ist laut Fehlerliste „Location Failed“. Vielleicht muss noch irgendetwas anders eingestellt werden, vielleicht hängt es aber auch mit der Funkabdeckung meines Wohnortes zusammen. Oder wurde der Dienst wieder eingestellt? Ich habe das Ganze erst einmal in meinem Akte X Ordner geparkt.

#include <SoftwareSerial.h>
SoftwareSerial mySerial(7,8);
const int wt_ms = 100; // wait ms

void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
  Serial.println("Get Location");
  delay(1000);
  mySerial.println("AT");  // optional check
  updateSerial(wt_ms);
  mySerial.println("AT+CPIN=\"xxxx\""); // if PIN is required
  updateSerial(wt_ms);
  mySerial.println("AT+CREG?"); // optional check
  updateSerial(wt_ms);
  mySerial.println("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\""); // set GPRS connection
  updateSerial(wt_ms);
  mySerial.println("AT+SAPBR=3,1,\"APN\",\"internet\""); // set APN name
//  updateSerial(wt_ms);
//  mySerial.println("AT+SAPBR=3,1,\"USER\",\"\""); // username empty
//  updateSerial(wt_ms);
//  mySerial.println("AT+SAPBR=3,1,\"PWD\",\"\"");  // password empty
  updateSerial(wt_ms);
  mySerial.println("AT+SAPBR=1,1"); // set rate
  updateSerial(wt_ms);
  mySerial.println("AT+SAPBR=2,1");  // connect
  updateSerial(500);
  mySerial.println("AT+CLBSCFG=0,1"); 
  updateSerial(500);
  mySerial.println("AT+CLBSCFG=0,2"); 
  updateSerial(wt_ms);
  mySerial.println("AT+CLBSCFG=0,3"); 
  updateSerial(wt_ms);
  mySerial.println("AT+CLBSCFG=1,3,\"lbs-simcom.com:3002\"");
  updateSerial(500);
  mySerial.println("AT+CLBS=1,1");
  updateSerial(500);
  delay(10000);
  
  //close connection:
  mySerial.println("AT+SAPBR=0,1");
} 
  
void loop() { 
  updateSerial(0);
}
  
void updateSerial(unsigned int wait_ms){
  String dataString = "";
  delay(wait_ms);
  if(mySerial.available()) {
    dataString = mySerial.readString();
    if(dataString != ""){
      Serial.println(dataString);
    }
  }
  while(Serial.available()) {
    mySerial.write(Serial.read());
  }
}

 

Danksagung

Wieder habe ich einige Bilder von Pixabay für mein Beitragsbild verwendet. Besten Dank an die Erschaffer:

Das SIM800L habe ich von Andrey Fedorov auf GitHub.

 

22 thoughts on “SIM800L Modul

  1. Hallo, erst einmal vielen Dank für den Beitrag. Mich würde interessieren, was das genau für eine Telekom-SIM Karte ist, bzw. wie der Tarif heißt. Denn wenn ich das richtig verstehe funktioniert das SIM800L-Modul nur mit einer 2G-SIM-Karte, aber nicht mit einer 3G/4G/LTE-Karte, wie sie in den üblichen Handys verwendet wird.

    1. Hallo, mein Vertrag nennt sich
      „Smart Connect S eco 1M“. Die Sim Karte heißt TD Triple Sim Standard. Ich könnte sie wohl auch in einem Smartphone nutzen. 2G ist damit abgedeckt. VG, Wolfgang

  2. Hallo Wolle,
    ich bin immer wiede begeistert, wie gut Arduino-Projekte hier erklärt werden!! Deswegen versuche ich mal, mein Anliegen zu plzieren, in der Hofnung, dass Sie es ebenso interessant finden 😉

    Mich würde folgendes interessieren: Haben Sie eine Lösung, wie der Arduino die Nummer des Absenders einer SMS im EEPROM ablegen könnte und diese dann für zukünftige SMS/Anrufe abrufen?

    Ich würde gerne per SMS Rufnummern für verschiedene Szenarien programmieren (Wenn der Taster an D2 gedrückt wird, ruf Bertie an, wenn Taster an D3 gedrückt wird, schreibe Oma, dass wir auf dem Weg sind).
    Und da Bertie und Oma nicht programmieren können, sollen sie ihre Nummer per SMS „programmieren“ können (z.B. mit einer SMS „KontaktOma +4917xxxxxx“).

    Leider finde ich immer nur Beipiele für einzelne Teile meines Plans (bei Ihnen zum Beispiel „Fernsteuern per SMS“, auf anderen Seiten „Auf SMS antowrten“) aber dann sind die Codes mit verschiedenen Bibliotheken und mein Wissen reicht nicht, die Codes dann sinnvoll zu kombinieren, zumal die Kommentierung meist dürftig ist 🙁

    Herzliche Grüße!
    Marie

    1. Hallo, meine erste Antwort an dieser Stelle war viel zu kompliziert. Ich habe deinen Kommentar zum Anlass genommen, einen Beitrag über EEPROMs zu machen. In ein paar Wochen kommt er raus. Ich kann die Vorgehensweise hier nur skizzieren. Du nimmst jeweils eine Telefonnummer und die Nachricht und speicherst sie durch Komma getrennt in einem String. Den String speicherst du Zeichen für Zeichen auf dem EEPROM und schließt ihn mit einem ‚\0‘ (Nullstring) ab. Das wiederholst du mit den anderen Einträgen. Du musst die lediglich die Reihenfolge merken. Wenn du dann z.B. den dritten Eintrag aufrufen willst, dann liest du den EEPROM zeichenweise von der Adresse 0 bis zu der Stelle, an der du das zweite Mal auf ‚\0‘ stößt. Ab da liest du zeichenweise weiter, bis du auf das nächste ‚\0‘ stößt. Die Zeichen fügst du zum String zusammen. Über die substring(), indexOf() und length() kannst du den Eintrag dann in Telefonnummer und Nachricht trennen und die Nachricht verschicken.
      Ich kann dir die Sketche schon mal zusenden.
      VG, Wolfgang

      1. Hallo Wolfgang, Ich danke dir für beide Einträge sehr!! Mittlerweile habe ich es geschafft, den Inhalt von SMS abhängig von bestimmten Triggerzeichen im Text in verschiedene char zu speichern – so weit zur Vorbereitung. An EEPROM hab ich mich bisher nicht getraut, wird aber der nächste Schritt sein. Einer der Links in deiner ersten Antwort hat mir da schon ein bisschen geholfen und in Kombination mit deiner zweiten Antwort, werde ich es hoffentlich bald schaffen. Ich sage Bescheid, wenn ich es hinbekommen hab.

  3. Hallo,
    ich habe gerade den Abschnitt „Versuch der Ortsbestimmung“ gelesen.
    Bei mir hat das auch plötzlich nicht mehr funktioniert. Ich habe dann etwas rumgesucht und dabei gefunden, dass nach einem Firmwareupdate der Befehl AT+CLBS=4,1 funktioniert.
    Firmware ist (AT+CGMR) Revision:1418B04SIM800L24.
    Der von SIM800 gelieferte Standort ist recht ungenau aber besser als nichts ;-).
    Bei Interesse kann ich mal den Sketch raussuchen….

  4. Hallo, ich habe versucht ein Projekt mit dem Sim 800l umzusetzen. Leider funktioniert es nicht. Können sie mir helfen. Es soll ein Weihnachtsgeschenk für meine Freundin werden.
    Zu meinem Projekt:
    Ich möchte eine LED mit einem Arduino UNO und dem SIM800l Modus verbinden. Durch SMS soll es möglich sein die LED anzumachen und eine Bestätigung, dass Licht angemacht wurde soll vom SIm800l zurück gesendet werden.

    Ich habe den Code soweit implementiert und alles verkabelt.

    Verkabelung: Stromversorgung für den Sim: 3,7V 1800 mAh Lipo Batterie ( in etwa wie auf dieser Internetseite https://elektro.turanis.de/html/prj237/index.html) nur das LED noch von Arduino weggeht.
    Code : ich würde ihnen den Code unten eingefügt. Bei Creq kommt immer 0,2.
    Sim Karte: Congstar Prepaid Karte: https://www.amazon.de/gp/product/B001ASIKDU/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1

    Das ganze funktioniert nicht wirklich. Es hat mal funktioniert aber nachdem ich es einen Tag später nochmal versucht habe hat es nicht mehr geklappt. es gibt mir immer komische Ausgaben für die AT Befehle. Die Led am Sim blinkt im Sekundentakt
    was darauf schließt das er sich nicht mit dem Netz verbindet aber er gibt mir eine gute Signalqualität und CPIn Ready wieder ( manchmal auch nicht aber es funktioniert so oder so nicht).

    Können sie mir helfen was ich falsch mache oder was das Problem ist ?

    Mit freundlichen Grüßen
    Michael März

    #include

    //Create software serial object to communicate with SIM800L
    SoftwareSerial mySerial(3, 2);

    boolean timersetted = false;
    String message;
    #define lampe 4
    const long interval = 7200; // in sekunden = 2stunden
    unsigned long previousMillis = 0;
    void setup()
    {

    pinMode(lampe, OUTPUT);
    //Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
    Serial.begin(9600);

    //Begin serial communication with Arduino and SIM800L
    mySerial.begin(9600);

    Serial.println(„Initializing…“);
    delay(1000);
    mySerial.println(„AT“);
    updateSerial();
    mySerial.println(„AT+CSQ“);
    updateSerial();
    mySerial.println(„AT+CFUN=1“);
    updateSerial();
    //mySerial.println(„AT+CPIN=\“PIN\““);
    //updateSerial();
    mySerial.println(„AT+CPIN?“);
    updateSerial();
    mySerial.println(„AT+CREG?“);
    updateSerial();
    mySerial.println(„AT+CMGF=1“);
    updateSerial();
    mySerial.println(„AT+CNMI=1,2,0,0,0“);
    updateSerial();
    mySerial.println(„AT+CMGS=\“+Hier steht nummer\““);
    updateSerial();
    // zum testen ob funktioniert
    mySerial.print(„Lampe initialisiert „); //text content
    updateSerial();
    mySerial.write(26);

    }

    void loop()
    {

    unsigned long currentMillis = millis();
    if(timersetted == true){
    if ((currentMillis – previousMillis)/1000 >= interval) {
    previousMillis = currentMillis;
    digitalWrite(lampe,LOW);
    mySerial.println(„AT+CMGS=\“hier Nummer\““);//change ZZ with country code and xxxxxxxxxxx with phone number to sms
    updateSerial();
    mySerial.print(„Licht wurde ausgemacht, Schoenen Tag noch 🙂 „); //text content
    updateSerial();
    mySerial.write(26);
    timersetted =false;
    }
    }

    message=mySerial.readString();
    if(message != „“){
    Serial.println(message);
    }
    if (message.indexOf(„#on“)>=0){
    previousMillis = currentMillis;
    timersetted = true;
    digitalWrite(lampe,HIGH);
    mySerial.println(„AT+CMGS=\“+hier nummer\““);//change ZZ with country code and xxxxxxxxxxx with phone number to sms
    updateSerial();
    mySerial.print(„Licht wurde angemacht. In 2 Stunden schalte ich es automatisch aus und benachrichtige Sie. Oder sie schreiben #off. Schoenen Tag noch 🙂 „); //text content
    updateSerial();
    mySerial.write(26);
    }

    if (message.indexOf(„#off“)>=0){
    digitalWrite(lampe,LOW);
    mySerial.println(„AT+CMGS=\“+hier nummer\““);//change ZZ with country code and xxxxxxxxxxx with phone number to sms
    updateSerial();
    mySerial.print(„Licht wurde ausgemacht, Schoenen Tag noch 🙂 „); //text content
    updateSerial();
    mySerial.write(26);
    previousMillis = currentMillis;
    timersetted=false;
    }

    }

    void updateSerial()
    {
    delay(5000);
    while (Serial.available())
    {
    mySerial.write(Serial.read());//Forward what Serial received to Software Serial Port
    }
    while(mySerial.available())
    {
    Serial.write(mySerial.read());//Forward what Software Serial received to Serial Port
    }
    }

    1. Hallo Michael,

      Weihnachtsgeschenk für die Freundin – das ist natürlich eine kritische Situation!

      Wenn die LED im Sekundentakt blinkt, dann hast du keine Netzverbindung. Bei mir hat es manchmal auch etwas gedauert, bis ich Netzverbindung hatte und ich weiß nicht genau wieso. Ich habe zunächst die Rückmeldung bekommen „+CPIN: READY“ und die LED stockte kurz, aber dann ging sie wieder im Sekundentakt. Für einen weiteren Versuch musst du die Pin erneut senden. Wenn ich aber drin war, bin ich auch immer drin geblieben. Vielleicht probierst du mal in einer Schleife im setup die Pin 10 oder 20 mal zu übermitteln. Zwischen den einzelnen Versuchen müssen ein paar Sekunden liegen.

      Was mir auffällt, ist das lange delay in der Update seriell Funktion. 5 Sekunden ist sehr lang. Der Rest des Sketches ist erstmal ziemlich unerheblich. Wenn du keine Verbindung hast, dann liegt das Problem ganz am Anfang.

      Evtl. hilft auch eine bessere Antenne, dagegen spricht natürlich, dass dir das Modul sagt, die Netzqualität sei OK. Bei mir ist die Netzqualität angeblich auch gut, trotzdem hatte ich tendentiell weniger Fehlversuche mit einer guten Antenne. Oder wenn du mal rausgeht, ist es dann vielleicht besser?

      Was meinst du mit „komischen Zeichen“ auf die AT Befehle? Das klingt so als hättest du eine falsch Baudrate eingestellt. Wenn es im Sketch 9600 sind, dann müssen auch 9600 im seriellen Monitor eingestellt werden. Du kannst mir auch mal einen Screenshot schicken (Wolfgang.Ewald@wolles-elektronikkiste.de).

      Dann ist noch wichtig, dass die Batterie und der Arduino ihre GNDs verbunden haben.

      Deine Batterie sollte funktionieren. So etwas benutze ich auch. Ebenso glaube ich nicht, dass es ein Problem mit der Simkarte gibt.

      Mehr fällt mir erst einmal nicht ein.

      VG, Wolfgang

  5. Hallo Wolfgang, als Arduino- und Elektronik-Neuling freue ich mich außerordentlich über deine sorgfältigen, gut verständlichen und gründlichen Anleitungen. Das ist für mich eine tolle Hilfe, und ich kann ganz gut ermessen, wieviel Arbeit da von deiner Seite aus drinsteckt. Vielen Dank!

    Zum SoftwareSerial Sketch habe ich jetzt nur eine harmlose Frage: In der Breadboard-Schaltung sind RX und TX mit den Pins D7 und D8 verbunden. Müsste es in SoftwareSerial.ino dann nicht heißen:

    SoftwareSerial mySerial(7, 8);
    ?

    1. Hallo Thomas,

      trotz x-maligen Durchlesens gehen immer noch Fehler durch – vielen Dank! Da bin ich in der Schaltung um einen Pin verrutscht.

      Ich muss mal schauen, ob ich die Schaltung oder die Sketche anpasse.

      VG, Wolfgang

  6. Meine Erfahrung mit dem Modul ist auch gut. Ich kann noch empfehlen einen 1000uF direkt an VCC+GND am Modul anzulöten, wenn man nicht mit LiPo Akkus arbeitet, die schnell viel Strom abgeben können.
    Das Modul hatte sich bei mir sonst manchmal resettet wenn spontan ein hoher Strom gezogen wurde (Stichwort „burst“)

  7. Hallo Wolfgang,

    wieder einmal ein sehr ausführlicher und schöner Beitrag von dir!
    Herzlichen Dank!

    Ich hätte da mal eine andere Frage, hast du Erfahrungen mit der TR-064 SOAP Library? Hier kämpfe ich gerade. Immer wenn ich diese Bibliothek in meinen Arduino Sketch einbaue, gibt es einen Compiler Fehler, egal, welches Board ich auswähle.

    exit status 1
    Fehler beim Kompilieren für das Board NodeMCU 0.9 (ESP-12 Module)

    Schöne Grüße von der Nordseeküste aus Wilhelmshaven
    Enno Jürgens

    1. Hallo Enno, diese Bibliothek ist mir noch nicht über den Weg gelaufen, sieht aber sehr interessant aus. Ich schaue sie mir sicherlich mal an, aber ich glaube „für mal eben auf die Schnelle“ ist das wahrscheinlich nichts. Bleibt wohl nur der Weg über Foren oder du meldest die Fehler direkt als Issue auf GitHub. VG, Wolfgang

  8. Danke wieder einmal für den, wie immer, äußerst lehrreichen Beitrag. Irgendwann wirst du ein Buch daraus binden müssen.
    Das SIM800L hatte ich schon vor einiger Zeit entdeckt. Was ich daraus gemacht habe:
    Die FeTap612 der Bundespost von 1973 sowie die W48 von 1955 zu einem Retro-Handy umgebaut. Muss noch etwas an der Software drehen, dann hat es Serienreife, dann gibt es auch Pläne auf Github.
    https://makeprojects.com/project/retro-handy-fetap-gsm

    1. Falls es jemanden interessiert oder jemand sehen möchte, wie man das SIM800L im Real Life benutzen kann:
      Die Pläne für die zum Mobiltelefon umfunktionierten Telefone „FeTap-612“ (Bundespost-Telefon der 70er) und das „W48-GSM“ (Bundespost-Telefon aus Bakelit der 50er und 50er) sind veröffentlicht. Schaltplan, Platine, Software , Bedienungsanleitung. Software wird irgendwann noch auf Stromsparen optimiert, sobald das „Power Profiler Kit II“ mal lieferbar ist. Ansonsten ist alles stabil.
      Here we go:
      https://github.com/Pontifex42/W48-GSM
      https://github.com/Pontifex42/FeTap-GSM

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.