Error in texting using ESP32 and SIM800L V2

Trying to connect and send text using ESP32 with the SIM800L V2 module but I am receiving error after pressing the button. Can anyone check if there are issues with my code/connections?

#include <HardwareSerial.h>

HardwareSerial sim800(2); // Use UART2 for SIM800L

const int buttonPin = 15; // Pin where the button is connected
int buttonState = LOW;    // Variable for reading the button status
int lastButtonState = LOW; // Variable to store the previous button state
unsigned long lastDebounceTime = 0; // The last time the button state was toggled
unsigned long debounceDelay = 50; // Debounce time in milliseconds

unsigned long commandTimeout = 3000; // Time to wait for command responses
unsigned long lastCommandTime = 0;
bool awaitingResponse = false;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP); // Enable internal pull-up resistor
  sim800.begin(115200, SERIAL_8N1, 16, 17); // SIM800L baud rate, using GPIO16 (RX2) and GPIO17 (TX2)
  Serial.begin(115200); // Serial monitor for debugging

  Serial.println("Initializing SIM800L...");

  // Initialize SIM800L
  sendCommand("AT");
  delay(1000); // Wait for the module to respond
  sendCommand("AT+CSCS=\"GSM\"");
  delay(1000);
  sendCommand("AT+CMGF=1"); // Set SMS to text mode
  delay(1000);
}

void loop() {
  handleButton();
  handleResponse();
}

void handleButton() {
  int reading = digitalRead(buttonPin);

  // Check if the button state has changed
  if (reading != lastButtonState) {
    lastDebounceTime = millis(); // Reset the debouncing timer
  }

  // If the button state has been stable for the debounce delay, take it as an actual press
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // If the button state has changed
    if (reading != buttonState) {
      buttonState = reading;
      // Only send SMS when the button is pressed (not released)
      if (buttonState == LOW) { // LOW because INPUT_PULLUP means button press is LOW
        sendSMS("+6***********", "Hello");
      }
    }
  }

  lastButtonState = reading; // Save the reading for the next loop iteration
}

void handleResponse() {
  if (awaitingResponse) {
    if (millis() - lastCommandTime > commandTimeout) {
      // Time out handling
      awaitingResponse = false;
      Serial.println("Command timeout.");
    }

    while (sim800.available()) {
      Serial.write(sim800.read());
    }

    awaitingResponse = false;
  }
}

void sendCommand(String command) {
  sim800.println(command);
  Serial.print("Sending command: ");
  Serial.println(command);
  lastCommandTime = millis();
  awaitingResponse = true;
}

void sendSMS(String number, String text) {
  sendCommand("AT+CMGS=\"" + number + "\"");
  waitForResponse();
  sim800.print(text);
  waitForResponse();
  sim800.write(26); // ASCII code for Ctrl+Z to send the SMS
  waitForResponse();
}

void waitForResponse() {
  lastCommandTime = millis();
  awaitingResponse = true;
  while (awaitingResponse) {
    handleResponse();
  }
}

Error below:

as you don't wait for a response to AT commands you are probably sending too fast

have you attempted to type AT commands and wait for the OK response?
try this

// // SIM800L EVB ESP32 test using Serial2 (pins 16 Rx  and 17 Tx)

// connect so
// SIM800 5V to ESP32 5V
// SIM800 GND to ESP32 GND
// SIM800 VDD to ESP32 3.3v
// SIM800 TXD to ESP32 pin 16 Rx
// SIM800 TXD to ESP32 pin 17 tx

// AT+CGMI  returns the manufacturer's name
// AT+CGMM returns the MODEM model number
// AT+CGMR returns details of the software and model revision level
// AT+CGSN returns the MODEM's serial number

#include <Arduino.h>

// ESP32 example using HardwareSerial library to access Serial port 2 (pins 16 and 17)
// from https://programming.vip/docs/esp32-use-of-hardwareserial-library.html

#define SERIAL_BAUD 9600//115200

int distance = 0;

void setup() {
  //Initialize serial port 0
  Serial.begin(115200);
  //Initialize serial port 2
  Serial2.begin(SERIAL_BAUD, SERIAL_8N1);
  Serial.println("\nSIM800 EVB to ESP32 Serial port 2 test");
}

void loop() {
  while (Serial2.available() > 0) {
    uint8_t byteFromSerial = Serial2.read();
    Serial.write(byteFromSerial);
  }
  while (Serial.available() > 0) {
    uint8_t byteFromSerial1 = Serial.read();
    Serial2.write(byteFromSerial1);
  }
}

text typed on keyboard is sent to SIM800 and response displayed on screen
a run gave

at
OK
at+cgmi
SIMCOM_Ltd
OK
at+cgmm
SIMCOM_SIM800L
OK
at+cgmr
Revision:1418B05SIM800L24
OK

also when you send a command to send a text you should wait for > response, e.g.

AT+CMGS=”+TTTTT” 
>

also avoid uploading screen images - they waste space and are impossible to copy from - copy the text and post it using code tags </>

Correct me from what I understood so far @horace

I ran the code you provided and the response is similar to the one you provided.

As much as possible, I would like to send a message when the button is clicked.

Right now I modified my code to reflect what you did in your code but it looks like it's still isnt working.

#include <HardwareSerial.h>

// HardwareSerial sim800(2); // Use UART2 for SIM800L

const int buttonPin = 15; // Pin where the button is connected
int buttonState = LOW;    // Variable for reading the button status
int lastButtonState = LOW; // Variable to store the previous button state
unsigned long lastDebounceTime = 0; // The last time the button state was toggled
unsigned long debounceDelay = 50; // Debounce time in milliseconds

unsigned long commandTimeout = 3000; // Time to wait for command responses
unsigned long lastCommandTime = 0;
bool awaitingResponse = false;

String phoneNumber = "+6***********"
String yourMessage = "Hello"

void setup() {
  pinMode(buttonPin, INPUT_PULLUP); // Enable internal pull-up resistor
  Serial2.begin(9600, SERIAL_8N1); // SIM800L baud rate, using GPIO16 (RX2) and GPIO17 (TX2)
  Serial.begin(115200); // Serial monitor for debugging

  Serial.println("Initializing SIM800L...");

  // Initialize SIM800L
  sendCommand("AT");
  delay(1000); // Wait for the module to respond
  sendCommand("AT+CSCS=\"GSM\"");
  delay(1000);
  sendCommand("AT+CMGF=1"); // Set SMS to text mode
  delay(1000);
}

void loop() {
  handleButton();
  handleResponse();
}

void handleButton() {
  int reading = digitalRead(buttonPin);

  // Check if the button state has changed
  if (reading != lastButtonState) {
    lastDebounceTime = millis(); // Reset the debouncing timer
  }

  // If the button state has been stable for the debounce delay, take it as an actual press
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // If the button state has changed
    if (reading != buttonState) {
      buttonState = reading;
      // Only send SMS when the button is pressed (not released)
      if (buttonState == LOW) { // LOW because INPUT_PULLUP means button press is LOW
        Serial.println("Button pressed, sending SMS...");
        sendSMS(phoneNumber, yourMessage);
      }
    }
  }

  lastButtonState = reading; // Save the reading for the next loop iteration
}

void handleResponse() {
  if (awaitingResponse) {
    if (millis() - lastCommandTime > commandTimeout) {
      // Time out handling
      awaitingResponse = false;
      Serial.println("Command timeout.");
    }

    while (Serial2.available()) {
      char c = Serial2.read();
      Serial.write(c); // Print response to Serial Monitor
    }

    awaitingResponse = false;
  }
}

void sendCommand(String command) {
  Serial2.println(command);
  Serial.print("Sending command: ");
  Serial.println(command);
  lastCommandTime = millis();
  awaitingResponse = true;
}

void sendSMS(String number, String text) {
  sendCommand("AT+CMGS=\"" + number + "\"");
  waitForResponse();
  Serial2.print(text);
  waitForResponse();
  Serial2.write(26); // ASCII code for Ctrl+Z to send the SMS
  waitForResponse();
}

void waitForResponse() {
  lastCommandTime = millis();
  awaitingResponse = true;
  while (awaitingResponse) {
    handleResponse();
  }
}

void testCommunication() {
  Serial.println("Testing communication with SIM800L...");
  sendCommand("AT");
  waitForResponse();
}

Result from bootup based on Serial output:


01:36:27.010 -> AT+CSCS="GSM"

01:36:27.010 -> OK
01:36:27.010 -> AT+CMGF=1

01:36:27.010 -> OK
01:36:36.813 -> Button pressed, sending SMS...
01:36:36.850 -> Sending command: AT+CMGS="+6***********"
01:44:47.034 -> Sending command: AT+CSCS="GSM"
01:44:48.005 -> Sending command: AT+CMGF=1
01:44:49.008 -> AT

01:44:49.008 -> OK
01:44:49.008 -> AT+CSCS="GSM"

01:44:49.008 -> OK
01:44:49.008 -> AT+CMGF=1

01:44:49.008 -> OK
01:44:59.906 -> Button pressed, sending SMS...
01:44:59.906 -> Sending command: AT+CMGS="+6***********"

Were my changes correct or am I still missing something?

Looking at the code. I think I can try doing the following.

  1. Connect SIM800L V2 VDD to 3.3V of ESP32.
  2. Use your code and send a text so something like:
  sim.println("AT+CMGF=1");
  sim.println("AT+CMGS=\"" + number + "\"\r");
  sim.println("Hey");
  sim.println((char)26);// ASCII code of CTRL+Z
  1. Add ""\r" to my sendCommand("AT+CSCS="GSM"");

Let me know if there's anything else I can do

after sending the AT+CMGS command you need to wait for > or error message before attempting to send text terminated by CTRL/Z
e.g. using a SIM900 (none of my working SIMs fit the SIM800)

at+cgmm
SIMCOM_SIM900
OK
AT+CMGS="+44xxxxxxxxxxx"
> testing test
> test2 1234567890
> 
+CMGS: 137
OK

I got it to work with this code:

#include <HardwareSerial.h>

HardwareSerial sim800(2); // Use UART2 for SIM800L

const int buttonPin = 15; // Pin where the button is connected
int buttonState = LOW;    // Variable for reading the button status
int lastButtonState = LOW; // Variable to store the previous button state
unsigned long lastDebounceTime = 0; // The last time the button state was toggled
unsigned long debounceDelay = 50; // Debounce time in milliseconds

unsigned long commandTimeout = 3000; // Time to wait for command responses
unsigned long lastCommandTime = 0;
bool awaitingResponse = false;

String myNumber = "+6**********"; //change to your number
String myMessage = "My message"; //change to my message

void setup() {
  pinMode(buttonPin, INPUT_PULLUP); // Enable internal pull-up resistor
  sim800.begin(9600, SERIAL_8N1); // SIM800L baud rate, using GPIO16 (RX2) and GPIO17 (TX2)
  Serial.begin(115200); // Serial monitor for debugging

  Serial.println("Initializing SIM800L...");

  // Initialize SIM800L
  sendCommand("AT");
  delay(1000); // Wait for the module to respond
  sendCommand("AT+CSCS=\"GSM\"");
  delay(1000);
  sendCommand("AT+CMGF=1"); // Set SMS to text mode
  delay(1000);
}

void loop() {
  handleButton();
  handleResponse();
}

void handleButton() {
  int reading = digitalRead(buttonPin);

  // Check if the button state has changed
  if (reading != lastButtonState) {
    lastDebounceTime = millis(); // Reset the debouncing timer
  }

  // If the button state has been stable for the debounce delay, take it as an actual press
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // If the button state has changed
    if (reading != buttonState) {
      buttonState = reading;
      // Only send SMS when the button is pressed (not released)
      if (buttonState == LOW) { // LOW because INPUT_PULLUP means button press is LOW
        Serial.println("Button pressed, sending SMS...");
        sendSMS(myNumber, myMessage);
      }
    }
  }

  lastButtonState = reading; // Save the reading for the next loop iteration
}

void handleResponse() {
  if (awaitingResponse) {
    if (millis() - lastCommandTime > commandTimeout) {
      // Time out handling
      awaitingResponse = false;
      Serial.println("Command timeout.");
    }

    while (sim800.available()) {
      char c = sim800.read();
      Serial.write(c); // Print response to Serial Monitor
    }

    awaitingResponse = false;
  }
}

void sendCommand(String command) {
  sim800.println(command);
  Serial.print("Sending command: ");
  Serial.println(command);
  lastCommandTime = millis();
  awaitingResponse = true;
}

void sendSMS(String number, String text) {
  sendCommand("AT+CMGS=\"" + number + "\"\r");
  waitForResponse();
  sim800.print(text);
  // waitForResponse();
  delay(500);
  sim800.println((char)26); // ASCII code for Ctrl+Z to send the SMS
  delay(1000);
  // waitForResponse();
}

void waitForResponse() {
  lastCommandTime = millis();
  awaitingResponse = true;
  while (awaitingResponse) {
    handleResponse();
  }
}

void testCommunication() {
  Serial.println("Testing communication with SIM800L...");
  sendCommand("AT");
  waitForResponse();
}

What I did different were:

  1. VDD of SIM800L v2 is connected to 3V of ESP32
  2. Added "\r" to
sendCommand("AT+CMGS=\"" + number + "\"");
  1. sendSMS function uses less waitForResponse function and more delays
  2. sendSMS function used
sim800.println((char)26);

instead of

sim800.write(26); // ASCII code for Ctrl+Z to send the SMS
void sendSMS(String number, String text) {
  sendCommand("AT+CMGS=\"" + number + "\"\r");
  waitForResponse();
  sim800.print(text);
  // waitForResponse();
  delay(500);
  sim800.println((char)26); // ASCII code for Ctrl+Z to send the SMS
  delay(1000);
  // waitForResponse();
}

My thoughts:
I think I could make it work without using delays because my entire code would freeze up using it. Also, I don't think "\r" is necessary as well as the HardwareSerial library since ESP32 has a 2nd serial port so I can do "serial2".

Let me know what you think about these.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.