ESP32 CAM(USB版)通过HardwareSerial无法获取NEO6M数据求助
ESP32 CAM读取NEO6M GPS数据故障调试
问题描述
使用带USB的ESP32 CAM通过HardwareSerial读取NEO6M GPS模块数据时无法正常获取数据,需要借助TinyGPS++将接收的数据格式化为易读内容,调试以下代码使其正常运行:
// libraries #include "TinyGPS++.h" #include "TimeLib.h" HardwareSerial NEO6M(1); // tx, rx // constants #define CHAR_NUM 110 #define timeOffset 28800 // UTC-8 // variables char latitude[11]; char longitude[11]; char Date[] = "00/00"; char Time[] = "00:00"; byte last_second, Second, Minute, Hour, Day, Month; int Year; // texts char nameText[CHAR_NUM], alcoholLevelText[CHAR_NUM], locationText[CHAR_NUM], dateTimeText[CHAR_NUM]; // tinygps++ object TinyGPSPlus gps; void setup() { // serial monitor setup Serial.begin(9600); NEO6M.begin(9600, SERIAL_8N1, 14, 16); // TX/RX // check if serial monitor is available if (Serial.available()>0) { Serial.println("Serial monitor is available"); } else { Serial.println("Serial monitor is not available!"); } } void loop() { useNEO6M(); Serial.println(locationText); Serial.println(dateTimeText); snprintf(locationText, sizeof(locationText), "Location: %s,%s", latitude, longitude); snprintf(dateTimeText, sizeof(dateTimeText), "Date: %s\nTime: %s", Date, Time); delay(1000); } void useNEO6M() { char latitudeTemp[11]; char longitudeTemp[11]; while (NEO6M.available() > 0) { gps.encode(NEO6M.read()); Serial.println(latitudeTemp); dtostrf(gps.location.lat(), 9, 6, latitudeTemp); dtostrf(gps.location.lng(), 9, 6, longitudeTemp); if (gps.time.isValid()) { Second = gps.time.second(); Minute = gps.time.minute(); Hour = gps.time.hour(); } if (gps.date.isValid()) { Day = gps.date.day() + 1; Month = gps.date.month(); Year = gps.date.year(); } if (last_second != gps.time.second()) { last_second = gps.time.second(); setTime(Hour, Minute, Second, Day, Month, Year); adjustTime(timeOffset); changeLatitude(latitudeTemp); changeLongitude(longitudeTemp); changeTime(); changeDate(); } } }
输出结果显示程序无法从NEO6M GPS模块获取数据。
调试方案
1. 修正串口初始化与引脚选择
ESP32 CAM的UART1默认引脚(TX=10、RX=9)可能与板载SD卡功能冲突,且你当前使用的14/16引脚需要确认硬件兼容性。另外必须确保GPS模块的TX接ESP32的RX,RX接ESP32的TX,接线反了会导致无数据。
修改后的串口初始化代码:
// 改用UART2,选择ESP32 CAM空闲引脚(示例:TX=17,RX=16,根据实际接线调整) HardwareSerial NEO6M(2); void setup() { Serial.begin(9600); // 初始化GPS串口,波特率匹配NEO6M默认的9600 NEO6M.begin(9600, SERIAL_8N1, 16, 17); // 移除无效的串口监视器检测逻辑,Serial.available()仅检测是否有输入数据 Serial.println("GPS reading started..."); }
2. 修复TinyGPS++解析逻辑
原代码在每次读取一个字节后立刻尝试获取经纬度,此时GPS还未完成NMEA语句解析,必然得到无效值。需先将所有串口数据喂给TinyGPS++,再判断数据有效性后更新内容。
修改useNEO6M()函数:
void useNEO6M() { // 先将所有可用串口数据喂给TinyGPS++解析 while (NEO6M.available() > 0) { gps.encode(NEO6M.read()); } // 仅当位置有效时更新经纬度 if (gps.location.isValid()) { char latitudeTemp[11]; char longitudeTemp[11]; dtostrf(gps.location.lat(), 9, 6, latitudeTemp); dtostrf(gps.location.lng(), 9, 6, longitudeTemp); // 复制到全局变量(替换原changeLatitude/changeLongitude逻辑) strncpy(latitude, latitudeTemp, sizeof(latitude)-1); latitude[sizeof(latitude)-1] = '\0'; strncpy(longitude, longitudeTemp, sizeof(longitude)-1); longitude[sizeof(longitude)-1] = '\0'; } // 时间日期更新:仅当时间日期有效且秒数变化时更新 if (gps.time.isValid() && gps.date.isValid()) { if (last_second != gps.time.second()) { last_second = gps.time.second(); // 获取GPS原始时间 Hour = gps.time.hour(); Minute = gps.time.minute(); Second = gps.time.second(); Day = gps.date.day(); Month = gps.date.month(); Year = gps.date.year(); // 调整为UTC+8时区(替代TimeLib的adjustTime) Hour = (Hour + 8) % 24; // 更新时间日期字符串(替换原changeTime/changeDate逻辑) snprintf(Time, sizeof(Time), "%02d:%02d:%02d", Hour, Minute, Second); snprintf(Date, sizeof(Date), "%02d/%02d/%04d", Month, Day, Year); } } }
3. 调整输出顺序
原loop()中先打印再更新文本,导致输出滞后一次。需先更新内容再打印:
void loop() { useNEO6M(); // 先构建输出文本,加入有效性判断 snprintf(locationText, sizeof(locationText), "Location: %s,%s", gps.location.isValid() ? latitude : "Invalid", gps.location.isValid() ? longitude : "Invalid"); snprintf(dateTimeText, sizeof(dateTimeText), "Date: %s\nTime: %s", gps.date.isValid() ? Date : "Invalid", gps.time.isValid() ? Time : "Invalid"); Serial.println(locationText); Serial.println(dateTimeText); delay(1000); }
4. 补充缺失的辅助函数(可选)
若坚持使用原代码中的changeLatitude等函数,需补充实现:
void changeLatitude(char* src) { strncpy(latitude, src, sizeof(latitude)-1); latitude[sizeof(latitude)-1] = '\0'; } void changeLongitude(char* src) { strncpy(longitude, src, sizeof(longitude)-1); longitude[sizeof(longitude)-1] = '\0'; } void changeTime() { snprintf(Time, sizeof(Time), "%02d:%02d:%02d", Hour, Minute, Second); } void changeDate() { snprintf(Date, sizeof(Date), "%02d/%02d", Month, Day); }
5. 硬件排查要点
- 供电:NEO6M必须使用3.3V供电,禁止用5V供电,否则会损坏模块或导致数据异常。
- 接线:确认GPS模块的TX接ESP32的RX,RX接ESP32的TX,GND共地。
- 定位环境:GPS需要开阔天空,室内无法定位,建议拿到室外测试。
内容的提问来源于stack exchange,提问作者Christian
相关产品推荐
相关产品推荐

