The SIM800L lets a project send SMS alerts and take calls — the classic “farm motor via missed call” or “tank full SMS” build. On the Mega it goes on its own hardware port, Serial2 (pins 17/16), keeping Serial1 free for a GPS.
The sketch checks the basics in order — module alive, SIM ready, signal, network registration — then turns the Serial Monitor into an AT terminal. Set the monitor to Both NL & CR and try AT+CMGF=1 and SMS commands from there.
Wiring
| Arduino Mega 2560 | SIM800L GSM/GPRS module (2G) | Wire | Notes |
|---|---|---|---|
| LM2596 buck set to 4.0 V (2 A) · + | VCC | red | 1000 µF capacitor across VCC/GND at the module. Never from the Mega’s 5V or 3.3V pin. |
| LM2596 buck set to 4.0 V (2 A) · - | GND | black | |
| GND | GND | black | Common ground: Mega GND, buck − and SIM800L GND. |
| D17 | TXD | green | SIM800L TX → RX2. |
| D16 | RXD | yellow | Via 10 kΩ / 20 kΩ divider — TX2 → SIM800L RX; the divider brings 5 V down to about 3.3 V. |
3.4–4.4 V, peaks up to 2 A part, 5 V board. The SIM800L’s serial pins work at about 2.8 V. Its TXD is read fine by 3.3 V and 5 V boards; its RXD must be protected from a 5 V Arduino TX with a divider (10 kΩ / 20 kΩ). ESP32 and Pico can connect directly.
Board quirks
- The SIM800L draws 2 A peaks when it registers or sends. Any weaker supply makes it reset in a loop (the LED blinks fast, then restarts). Set the buck to 4.0 V with a meter before connecting the module.
- It is a 2G-only module. Use a SIM from an operator that still runs 2G in your area; Jio SIMs (4G-only) never register.
- The Mega’s Serial2 (RX2 = 17, TX2 = 16) does the UART work in hardware, so AT replies and incoming SMS text arrive intact while the sketch is busy.
- Network LED: blinking every 1 s = searching; every 3 s = registered; fast = GPRS data.
- Fit the spring antenna (or the u.FL antenna) — without it signal (AT+CSQ) stays below 10.
Code
// SIM800L GSM module on an Arduino Mega 2560 using hardware Serial2.
// SIM800L TXD → D17 (RX2), RXD ← D16 (TX2) through a 10 kΩ / 20 kΩ divider, VCC from a 4.0 V
// 2 A buck converter (NOT the Mega), GND common. Checks the module, SIM and network, then
// becomes a bridge: type AT commands in the Serial Monitor (set to "Both NL & CR").
void sendAT(const __FlashStringHelper *cmd, unsigned long waitMs) {
Serial.print(F(">> "));
Serial.println(cmd);
Serial2.println(cmd);
unsigned long start = millis();
while (millis() - start < waitMs) {
while (Serial2.available()) Serial.write(Serial2.read());
}
}
void setup() {
Serial.begin(115200);
Serial2.begin(9600); // SIM800L auto-bauds; 9600 is the safe choice
delay(3000); // module boot time
sendAT(F("AT"), 500); // expect OK
sendAT(F("ATE0"), 500); // echo off
sendAT(F("AT+CPIN?"), 500); // READY = SIM found and unlocked
sendAT(F("AT+CSQ"), 500); // signal: 10-31 is usable, 99 = none
sendAT(F("AT+CREG?"), 500); // 0,1 = home network, 0,5 = roaming
sendAT(F("AT+COPS?"), 1000); // operator name
Serial.println(F("Bridge mode - type AT commands"));
}
void loop() {
while (Serial.available()) Serial2.write(Serial.read());
while (Serial2.available()) Serial.write(Serial2.read());
}// SIM800L GSM module on an Arduino Mega 2560 using hardware Serial2.
// SIM800L TXD → D17 (RX2), RXD ← D16 (TX2) through a 10 kΩ / 20 kΩ divider, VCC from a 4.0 V
// 2 A buck converter (NOT the Mega), GND common. Checks the module, SIM and network, then
// becomes a bridge: type AT commands in the Serial Monitor (set to "Both NL & CR").
void sendAT(const __FlashStringHelper *cmd, unsigned long waitMs) {
Serial.print(F(">> "));
Serial.println(cmd);
Serial2.println(cmd);
unsigned long start = millis();
while (millis() - start < waitMs) {
while (Serial2.available()) Serial.write(Serial2.read());
}
}
void setup() {
Serial.begin(115200);
Serial2.begin(9600); // SIM800L auto-bauds; 9600 is the safe choice
delay(3000); // module boot time
sendAT(F("AT"), 500); // expect OK
sendAT(F("ATE0"), 500); // echo off
sendAT(F("AT+CPIN?"), 500); // READY = SIM found and unlocked
sendAT(F("AT+CSQ"), 500); // signal: 10-31 is usable, 99 = none
sendAT(F("AT+CREG?"), 500); // 0,1 = home network, 0,5 = roaming
sendAT(F("AT+COPS?"), 1000); // operator name
Serial.println(F("Bridge mode - type AT commands"));
}
void loop() {
while (Serial.available()) Serial2.write(Serial.read());
while (Serial2.available()) Serial.write(Serial2.read());
}Library: TinyGSM (Volodymyr Shymanskyy).
Expected serial output
>> AT
OK
>> AT+CPIN?
+CPIN: READY
>> AT+CSQ
+CSQ: 18,0
>> AT+CREG?
+CREG: 0,1
Bridge mode - type AT commands>> AT OK >> AT+CPIN? +CPIN: READY >> AT+CSQ +CSQ: 18,0 >> AT+CREG? +CREG: 0,1 Bridge mode - type AT commands
Common errors
Module keeps restarting
Supply too weak or the voltage drops during transmit bursts. Full fix.
+CREG: 0,2 forever
Searching but never registering: no 2G network for that SIM, a weak antenna, or the SIM is not activated.
Garbage or nothing in reply to AT
TXD/RXD swapped, or the divider is on the wrong wire. The divider belongs on the Mega TX → module RXD side.