Microcontroller Integration & Code Examples
Production-grade, copy-pasteable, tested code for the Arduino Uno/Nano (SoftwareSerial + AT+GPSRD), Arduino Mega 2560 (Dual Hardware UART), and ESP32 (Non-blocking location-on-demand tracker).
Example 1: Arduino Uno / Nano (Single-Port with AT+GPSRD)
Demonstrates how to boot the A7, enable GPS via AT+GPS=1, mirror NMEA sentences onto the AT port with AT+GPSRD=1, acquire a lock, stop redirection with AT+GPSRD=0, and transmit the coordinates via SMS.
Arduino Uno (5V) AI-Thinker A7 Board
+-------------------+ +--------------------+
| Pin 10 (Soft RX) <-----------------------+ U_TXD (P1 Pin 5)|
| | | |
| Pin 11 (Soft TX) +----[ 1.0k ]---+-------> U_RXD (P1 Pin 4)|
| | | | |
| | [2.0k] | |
| | | | |
| Pin 7 (PWR_KEY) +---------------+-------> PWR_KEY (P2 Pin 11|
| | | | |
| GND +---------------+-------> GND (P1 Pin 3)|
+-------------------+ +--------------------+
#include <SoftwareSerial.h>
const byte A7_RX_PIN = 10; // Connect to A7 U_TXD
const byte A7_TX_PIN = 11; // Connect to A7 U_RXD (via 1k/2k divider)
const byte A7_PWR_PIN = 7; // Connect to A7 PWR_KEY
SoftwareSerial A7Serial(A7_RX_PIN, A7_TX_PIN);
const char TARGET_PHONE[] = "+1234567890"; // Target recipient
void setup() {
Serial.begin(9600);
A7Serial.begin(9600); // Ensure A7 is set to 9600 baud (see Chapter 3)
Serial.println(F("=== AI-Thinker A7 Uno Tracker Starting ==="));
powerOnModule();
sendAT("AT", 1000);
sendAT("AT+CPIN?", 2000);
sendAT("AT+CMGF=1", 1000); // Set SMS to Text Mode
Serial.println(F("[GPS] Turning ON GPS Receiver..."));
sendAT("AT+GPS=1", 2000);
acquireFixAndSendSMS();
}
void loop() {
// Idle after execution
}
void powerOnModule() {
Serial.println(F("[PWR] Sending Active-HIGH pulse to PWR_KEY..."));
pinMode(A7_PWR_PIN, OUTPUT);
digitalWrite(A7_PWR_PIN, HIGH);
delay(2500); // 2.5 second pulse
digitalWrite(A7_PWR_PIN, LOW);
delay(5000); // Allow RTOS and network registration to complete
}
void acquireFixAndSendSMS() {
Serial.println(F("[GPS] Starting AT+GPSRD stream..."));
sendAT("AT+GPSRD=1", 2000);
char nmeaLine[100];
byte index = 0;
bool fixAcquired = false;
char lat[12] = "";
char lon[12] = "";
unsigned long startTime = millis();
while (!fixAcquired && (millis() - startTime < 180000)) { // 3-min timeout
while (A7Serial.available()) {
char c = A7Serial.read();
if (c == '\n') {
nmeaLine[index] = '\0';
index = 0;
if (strstr(nmeaLine, "$GPRMC") != NULL || strstr(nmeaLine, "$GNRMC") != NULL) {
Serial.print(F("[NMEA] "));
Serial.println(nmeaLine);
// Parse: $GPRMC,time,status,lat,NS,lon,EW,...
char* p = strchr(nmeaLine, ',');
if (p) p = strchr(p + 1, ',');
if (p && *(p + 1) == 'A') { // 'A' indicates Valid Fix
Serial.println(F("[GPS] >>> VALID FIX ACQUIRED! <<<"));
char* latStart = p + 3;
char* latEnd = strchr(latStart, ',');
if (latEnd) {
strncpy(lat, latStart, latEnd - latStart);
lat[latEnd - latStart] = '\0';
}
char* ns = latEnd + 1;
char* lonStart = ns + 2;
char* lonEnd = strchr(lonStart, ',');
if (lonEnd) {
strncpy(lon, lonStart, lonEnd - lonStart);
lon[lonEnd - lonStart] = '\0';
}
fixAcquired = true;
break;
}
}
} else if (c != '\r' && index < sizeof(nmeaLine) - 1) {
nmeaLine[index++] = c;
}
}
}
// CRITICAL: Stop GPSRD to restore clean AT command interface!
Serial.println(F("[GPS] Stopping AT+GPSRD stream..."));
sendAT("AT+GPSRD=0", 2000);
delay(1000);
if (fixAcquired) {
Serial.println(F("[SMS] Transmitting Location SMS..."));
A7Serial.print(F("AT+CMGS=\""));
A7Serial.print(TARGET_PHONE);
A7Serial.println(F("\""));
delay(1000);
A7Serial.print(F("A7 Alert: Vehicle Location: Lat: "));
A7Serial.print(lat);
A7Serial.print(F(", Lon: "));
A7Serial.print(lon);
A7Serial.write(0x1A); // Send Ctrl+Z to finish SMS
delay(3000);
Serial.println(F("[SMS] SMS Sent Successfully!"));
} else {
Serial.println(F("[GPS] Timed out waiting for fix."));
}
}
String sendAT(const char* cmd, const int timeout) {
A7Serial.println(cmd);
String response = "";
unsigned long t = millis();
while (millis() - t < timeout) {
while (A7Serial.available()) {
response += (char)A7Serial.read();
}
}
Serial.print(F("CMD: ")); Serial.print(cmd);
Serial.print(F(" -> RESP: ")); Serial.println(response);
return response;
}
Example 2: Arduino Mega 2560 (Dual Hardware UART)
Using hardware UARTs allows continuous GPS streaming from GPS_TXD without ever having to send AT+GPSRD.
#define A7_AT_Serial Serial3 // Mega TX3 (Pin 14), RX3 (Pin 15)
#define A7_GPS_Serial Serial2 // Mega RX2 (Pin 19) <- A7 GPS_TXD
void setup() {
Serial.begin(115200);
A7_AT_Serial.begin(115200);
A7_GPS_Serial.begin(9600); // GPS_TXD fixed at 9600 baud
Serial.println(F("=== Mega 2560 Dual-UART A7 Demo Starting ==="));
delay(1000);
// Turn ON GPS subsystem
Serial.println(F("Enabling GPS Subsystem via Serial3..."));
A7_AT_Serial.println("AT+GPS=1");
delay(1000);
// NOTE: DO NOT send AT+GPSRD!
// GPS data will stream automatically out of GPS_TXD into Serial2.
}
void loop() {
// Read and print GPS stream from Serial2
if (A7_GPS_Serial.available()) {
char c = A7_GPS_Serial.read();
Serial.write(c); // Direct forward to PC monitor
}
// Read unsolicited cellular events (incoming SMS, RING) from Serial3
if (A7_AT_Serial.available()) {
char c = A7_AT_Serial.read();
Serial.write(c);
}
// Forward PC terminal commands to A7
if (Serial.available()) {
char c = Serial.read();
A7_AT_Serial.write(c);
}
}
Example 3: ESP32 Non-Blocking Location-On-Demand Tracker
The ESP32 runs at 3.3V, connecting directly to the A7 without level shifters. This non-blocking sketch listens for incoming text messages containing "LOC" and responds with a clickable Google Maps URL.
#include <HardwareSerial.h>
HardwareSerial A7_AT(2); // UART2: GPIO 16 (RX), GPIO 17 (TX)
HardwareSerial A7_GPS(1); // UART1: GPIO 4 (RX), GPIO 5 (TX unused)
const int PIN_PWR_KEY = 23;
String currentLat = "0.0";
String currentLon = "0.0";
bool hasGPSLock = false;
void setup() {
Serial.begin(115200);
A7_AT.begin(115200, SERIAL_8N1, 16, 17);
A7_GPS.begin(9600, SERIAL_8N1, 4, -1);
Serial.println(F("[ESP32] Booting AI-Thinker A7..."));
// Pulse PWR_KEY
pinMode(PIN_PWR_KEY, OUTPUT);
digitalWrite(PIN_PWR_KEY, HIGH);
delay(2500);
digitalWrite(PIN_PWR_KEY, LOW);
delay(4000);
// Initialize Cellular & GPS
A7_AT.println("AT");
delay(500);
A7_AT.println("AT+CMGF=1"); // SMS Text mode
delay(500);
A7_AT.println("AT+CNMI=2,2,0,0,0"); // Direct SMS display
delay(500);
A7_AT.println("AT+GPS=1"); // Turn on GPS
delay(500);
Serial.println(F("[ESP32] Tracker Ready. Listening for SMS 'LOC'..."));
}
void loop() {
processGPSStream();
processCellularEvents();
}
void processGPSStream() {
static char buffer[120];
static byte idx = 0;
while (A7_GPS.available()) {
char c = A7_GPS.read();
if (c == '\n') {
buffer[idx] = '\0';
idx = 0;
if (strstr(buffer, "$GPRMC") || strstr(buffer, "$GNRMC")) {
char* p = strchr(buffer, ',');
if (p) p = strchr(p + 1, ',');
if (p && *(p + 1) == 'A') { // Valid Fix
hasGPSLock = true;
char* latStart = p + 3;
char* latEnd = strchr(latStart, ',');
if (latEnd) {
currentLat = String(latStart).substring(0, latEnd - latStart);
char* lonStart = latEnd + 3;
char* lonEnd = strchr(lonStart, ',');
if (lonEnd) {
currentLon = String(lonStart).substring(0, lonEnd - lonStart);
}
}
} else {
hasGPSLock = false;
}
}
} else if (c != '\r' && idx < sizeof(buffer) - 1) {
buffer[idx++] = c;
}
}
}
void processCellularEvents() {
static String atBuffer = "";
while (A7_AT.available()) {
char c = A7_AT.read();
atBuffer += c;
if (c == '\n') {
atBuffer.trim();
if (atBuffer.startsWith("+CMT:")) {
int senderStart = atBuffer.indexOf("\"") + 1;
int senderEnd = atBuffer.indexOf("\"", senderStart);
String senderNumber = atBuffer.substring(senderStart, senderEnd);
String body = A7_AT.readStringUntil('\n');
body.trim();
Serial.printf("[SMS] From: %s | Text: %s\n", senderNumber.c_str(), body.c_str());
if (body.equalsIgnoreCase("LOC")) {
sendReplySMS(senderNumber);
}
}
atBuffer = "";
}
}
}
void sendReplySMS(String recipient) {
Serial.printf("[SMS] Sending reply to %s...\n", recipient.c_str());
A7_AT.printf("AT+CMGS=\"%s\"\r\n", recipient.c_str());
delay(1000);
if (hasGPSLock) {
A7_AT.printf("Vehicle Location Lock:\nhttp://maps.google.com/maps?q=%s,%s",
currentLat.c_str(), currentLon.c_str());
} else {
A7_AT.print("GPS searching for satellites. Please retry in 1 minute.");
}
A7_AT.write(0x1A); // Send Ctrl+Z
}