合宙AIR001 Nano开发板
合宙的这块板价格便宜,可以使用arduino进行编程,价格便宜,体积小,非常好看。
然而它与arduino nano相比没有EEPROM,flash空间也小很多,没有板载ch340芯片
所以,下载时记住按住BOOT键再上电,点击下载,下载完成后再松手。
另外,windows的用户名不能有中文,否则arduino编译时路径有中文,无法编译通过。
资料下载中心网址 https://product.abrobot.club
const char *deviceName = "CAR2";
// GPS 数据缓冲区
char gpsBuffer[100]; // 存储 GPS 数据的缓冲区
bool gpsDataReady = false;
// 函数声明
void sendCommand(const char *cmd);
void parseGPSData(const char *data);
void sendMQTTMessage(float latitude, float longitude);
// 初始化
void setup() {
// 设置串口通信
Serial.begin(9600); // 串口通信
// 等待模块启动
delay(8000);
// 初始化 GPS 定位
sendCommand("AT+MGPSC=1\r\n"); // 开启 GPS 功能
delay(500);
sendCommand("AT+MGPSGET=0\r\n"); // 暂时关闭 NMEA 数据输出
delay(500);
// 设置 4G MQTT 连接
sendCommand("AT+MDISCONNECT\r\n"); // 断开已有 MQTT 连接
delay(200);
sendCommand("AT+MIPCLOSE\r\n"); // 关闭当前会话
delay(200);
sendCommand("AT+QICSGP=1,1,\"\",\"\",\"\"\r\n"); // 设置 APN
delay(200);
sendCommand("AT+NETOPEN\r\n"); // 打开网络
delay(3000);
// 配置 MQTT 连接
sendCommand("AT+MCONFIG=\"设备名称\",\"\",\"\",0,0,0,\"1883\",\"2024\"\r\n");
delay(200);
sendCommand("AT+MIPSTART=\"nbzch.cn\",1883,3\r\n"); // 连接 MQTT Broker
delay(2000);
sendCommand("AT+MCONNECT=0,60\r\n"); // 连接到 MQTT 服务器
delay(200);
sendCommand("AT+MGPSGET=ALL,1\r\n");
delay(200);
// 向 gps/lastLocation 发送 online 消息
char onlineMessage[100];
snprintf(onlineMessage, sizeof(onlineMessage), "{\"name\":\"%s\",\"msg\":\"online\"}", deviceName);
char mqttCommand[100];
snprintf(mqttCommand, sizeof(mqttCommand), "AT+MPUBEX=\"gps/lastLocation\",0,0,%d\r\n", strlen(onlineMessage));
sendCommand(mqttCommand); // 发送 MQTT 发布指令
Serial.print(onlineMessage); // 发送消息内容
}
void loop() {
static int index = 0;
while (Serial.available()) {
char c = Serial.read();
if (c == '\n') {
gpsBuffer[index] = '\0';
index = 0;
gpsDataReady = true;
} else if (c != '\r') {
gpsBuffer[index++] = c;
}
if (gpsDataReady) {
gpsDataReady = false;
if (strncmp(gpsBuffer, "$GNGLL", 6) == 0) {
parseGPSData(gpsBuffer);
}
}
}
}
// 发送 AT 指令
void sendCommand(const char *cmd) {
Serial.print(cmd);
delay(500); // 等待模块响应
}
// 转换 GPS 数据中的纬度和经度格式
float convertToDecimalDegrees(float rawValue) {
int degrees = (int)(rawValue / 100); // 提取度部分
float minutes = rawValue - (degrees * 100); // 提取分部分
return degrees + (minutes / 60.0); // 转换为十进制度
}
// 解析 GPS 数据
void parseGPSData(const char *data) {
// 创建一个可以修改的字符数组
char dataCopy[100];
strncpy(dataCopy, data, sizeof(dataCopy) - 1); // 复制 data 到 dataCopy
dataCopy[sizeof(dataCopy) - 1] = '\0'; // 确保字符串结尾
char *token;
char gpsLat[15], gpsLon[15], latDirection, lonDirection;
float latitude, longitude;
token = strtok(dataCopy, ","); // 跳过 GNGLL
token = strtok(NULL, ","); // Latitude
strcpy(gpsLat, token);
token = strtok(NULL, ","); // Latitude Direction (N/S)
latDirection = *token;
token = strtok(NULL, ","); // Longitude
strcpy(gpsLon, token);
token = strtok(NULL, ","); // Longitude Direction (E/W)
lonDirection = *token;
token = strtok(NULL, ","); // UTC time (忽略)
token = strtok(NULL, ","); // Status (A = Active, V = Void)
char status = *token;
if (status == 'A') { // 如果定位有效
latitude = atof(gpsLat); // 原始纬度
longitude = atof(gpsLon); // 原始经度
// 将纬度和经度转换为十进制度
latitude = convertToDecimalDegrees(latitude);
longitude = convertToDecimalDegrees(longitude);
// 根据 N/S 和 E/W 修改经纬度符号
if (latDirection == 'S') latitude = -latitude;
if (lonDirection == 'W') longitude = -longitude;
// 通过 MQTT 发送 GPS 数据
sendMQTTMessage(latitude, longitude);
}
}
// 发送 MQTT 消息
void sendMQTTMessage(float latitude, float longitude) {
char latBuffer[15]; // 用于存储纬度的字符串
char lonBuffer[15]; // 用于存储经度的字符串
// 转换浮点数为字符串
dtostrf(latitude, 0, 6, latBuffer); // 6 表示保留 6 位小数
dtostrf(longitude, 0, 6, lonBuffer);
char mqttMessage[100]; // 增大缓冲区
snprintf(mqttMessage, sizeof(mqttMessage), "{\"name\":\"%s\",\"lat\":%s,\"lon\":%s}", deviceName, latBuffer, lonBuffer);
char mqttCommand[100];
snprintf(mqttCommand, sizeof(mqttCommand), "AT+MPUBEX=\"gps/location\",0,0,%d\r\n", strlen(mqttMessage));
sendCommand(mqttCommand); // 发送 MQTT 发布指令
Serial.print(mqttMessage); // 发送消息内容
}