#include "gps.h" //#define TEST 1 //测试使用,去除的时候可以接触代码的调用 #define parse 1 // 测试使用 /** 提示: 虽然 BLE 以及 GPS都是DMA+ UART接收,但是它们都有所不同 BLE --- DMA + IDLE 中断 循环 DMA + 空闲中断触发处理 UART IDLE GPS --- DMA +固定长度 + TC中断 设置固定长度 DMA DMA传输完成中断 **/ //外部引入 extern UART_HandleTypeDef huart2; extern DMA_HandleTypeDef handle_GPDMA1_Channel3; //全局数据变量定义 uint8_t GPS_DMA_RX_BUF[GPS_DMA_RX_BUF_LEN]; //用于DMA接收缓冲 _GPSData GPS; void GPS_Init(void) { HAL_UARTEx_ReceiveToIdle_IT(&huart2, GPS_DMA_RX_BUF, GPS_DMA_RX_BUF_LEN); // HAL_UARTEx_ReceiveToIdle_DMA(&huart2,GPS_DMA_RX_BUF,GPS_DMA_RX_BUF_LEN); } #ifdef parse // GPS数据解析 //void parseGpsBuffer() //{ // char *subString; // char *subStringNext; // char i = 0; // // if(GPS.isGetData) // { // GPS.isGetData = 0; // 把标志位置为1 // // char usefullBuffer[2] = {0}; // for(i = 0; i <= 6; i++) // { // if(i == 0) // { // // subString = strstr(GPS.GPS_Buffer,","); // if(!subString)return; // } // else // { // subString++; // subStringNext = strstr(subString,","); // if(!subStringNext)return; // // switch(i) // { // case 1: // memcpy(GPS.UTCTime,subString,subStringNext - subString); // break; // case 2: // memcpy(usefullBuffer,subString,subStringNext - subString); // break; // case 3: // memcpy(GPS.latitude,subString,subStringNext - subString); // break; // case 4: // memcpy(GPS.N_S,subString,subStringNext - subString); // break; // case 5: // memcpy(GPS.longitude,subString,subStringNext - subString); // break; // case 6: // memcpy(GPS.E_W,subString,subStringNext - subString); // break; // default:break; // } // // subString = subStringNext; // } // // } // GPS.isParseData = 1; // GPS.isUsefull = (usefullBuffer[0] == 'A') ? 1 : 0; // } // //} //void parseGpsBuffer(void) //{ // if (!GPS.isGetData) return; // GPS.isGetData = 0; // /* ----------- 句型判别 ------------ */ // const char *p = GPS.GPS_Buffer; // /* ★ RMC ----------------------------------------------------- */ // if (!strncmp(p, "$GNRMC", 6) || !strncmp(p, "$GPRMC", 6)) // { // char status, lat[16], ns[3], lon[16], ew[3]; // if (sscanf(p, // "$%*[^,],%*[^,],%c,%15[^,],%2[^,],%15[^,],%2[^,],", // &status, lat, ns, lon, ew) == 5) // { // if (status == 'A') /* 定位有效 */ // { // strcpy(GPS.latitude, lat); // strcpy(GPS.N_S, ns); // strcpy(GPS.longitude, lon); // strcpy(GPS.E_W, ew); // GPS.isParseData = 1; // GPS.isUsefull = 1; // } // } // return; // } // /* ★ GGA ----------------------------------------------------- */ // if (!strncmp(p, "$GNGGA", 6) || !strncmp(p, "$GPGGA", 6)) // { // int q; char lat[16], ns[3], lon[16], ew[3]; // if (sscanf(p, // "$%*[^,],%*[^,],%15[^,],%2[^,],%15[^,],%2[^,],%d,", // lat, ns, lon, ew, &q) == 5) // { // if (q > 0) /* q=0 无定位 */ // { // strcpy(GPS.latitude, lat); // strcpy(GPS.N_S, ns); // strcpy(GPS.longitude, lon); // strcpy(GPS.E_W, ew); // GPS.isParseData = 1; // GPS.isUsefull = 1; // } // } // return; // } // /* ★ GLL ----------------------------------------------------- */ // if (!strncmp(p, "$GNGLL", 6) || !strncmp(p, "$GPGLL", 6)) // { // char status, lat[16], ns[3], lon[16], ew[3]; // if (sscanf(p, // "$%*[^,],%15[^,],%2[^,],%15[^,],%2[^,],%*[^,],%c", // lat, ns, lon, ew, &status) == 5) // { // if (status == 'A') // { // strcpy(GPS.latitude, lat); // strcpy(GPS.N_S, ns); // strcpy(GPS.longitude, lon); // strcpy(GPS.E_W, ew); // GPS.isParseData = 1; // GPS.isUsefull = 1; // } // } // } //} /* === ① 行缓存区 & 推送函数 === */ static char line_buf[GPS_Buffer_Length]; static uint16_t line_w = 0; void GPS_LinePush(uint8_t ch) { if (ch == '\n') { /* 正常行结束 */ line_buf[line_w] = '\0'; /* A. 如果不是 '$' 开头,说明它只是上一句的后半截 → 直接拼接 */ if (line_buf[0] != '$' && GPS.isGetData == 0 && GPS.GPS_Buffer[0] == '$') { strncat(GPS.GPS_Buffer, line_buf, GPS_Buffer_Length - strlen(GPS.GPS_Buffer) - 1); } else /* B. 正常完整新句 */ { strncpy(GPS.GPS_Buffer, line_buf, GPS_Buffer_Length); } line_w = 0; GPS.isGetData = 1; tx_event_flags_set(&system_events, EVENT_GPS_DATA_READY, TX_OR); return; } } /* === ② 新解析器:只要经纬度 === */ void parseGpsBuffer(void) { if (!GPS.isGetData) return; GPS.isGetData = 0; GPS.isParseData = 0; GPS.isUsefull = 0; const char *p = GPS.GPS_Buffer; /* ---- $GxRMC ---- */ if (!strncmp(p, "$GNRMC", 6) || !strncmp(p, "$GPRMC", 6)) { char s, lat[16], ns[3], lon[16], ew[3]; if (sscanf(p, "$%*[^,],%*[^,],%c,%15[^,],%2[^,],%15[^,],%2[^,],", &s, lat, ns, lon, ew) == 5 && s == 'A') { strcpy(GPS.latitude, lat); strcpy(GPS.N_S, ns); strcpy(GPS.longitude, lon); strcpy(GPS.E_W, ew); GPS.isParseData = GPS.isUsefull = 1; } return; } /* ---- $GxGGA ---- */ if (!strncmp(p, "$GNGGA", 6) || !strncmp(p, "$GPGGA", 6)) { int q; char lat[16], ns[3], lon[16], ew[3]; if (sscanf(p, "$%*[^,],%*[^,],%15[^,],%2[^,],%15[^,],%2[^,],%d,", lat, ns, lon, ew, &q) == 5 && q > 0) { strcpy(GPS.latitude, lat); strcpy(GPS.N_S, ns); strcpy(GPS.longitude, lon); strcpy(GPS.E_W, ew); GPS.isParseData = GPS.isUsefull = 1; } return; } /* ---- $GxGLL ---- */ if (!strncmp(p, "$GNGLL", 6) || !strncmp(p, "$GPGLL", 6)) { char s, lat[16], ns[3], lon[16], ew[3]; if (sscanf(p, "$%*[^,],%15[^,],%2[^,],%15[^,],%2[^,],%*[^,],%c", lat, ns, lon, ew, &s) == 5 && s == 'A') { strcpy(GPS.latitude, lat); strcpy(GPS.N_S, ns); strcpy(GPS.longitude, lon); strcpy(GPS.E_W, ew); GPS.isParseData = GPS.isUsefull = 1; } } } #else // 这里是对于改进后的parse 解析 两个都需要进行测试 void parseGpsBuffer() { char *fields[7]; char *token; int fieldIndex = 0; if (GPS.isGetData) { GPS.isGetData = 0; // 把标志位置为0 token = strtok(GPS.GPS_Buffer, ","); while (token != NULL && fieldIndex < 7) { fields[fieldIndex++] = token; token = strtok(NULL, ","); } if (fieldIndex == 7) { memcpy(GPS.UTCTime, fields[1], sizeof(GPS.UTCTime) - 1); GPS.UTCTime[sizeof(GPS.UTCTime) - 1] = '\0'; memcpy(GPS.latitude, fields[3], sizeof(GPS.latitude) - 1); GPS.latitude[sizeof(GPS.latitude) - 1] = '\0'; memcpy(GPS.N_S, fields[4], sizeof(GPS.N_S) - 1); GPS.N_S[sizeof(GPS.N_S) - 1] = '\0'; memcpy(GPS.longitude, fields[5], sizeof(GPS.longitude) - 1); GPS.longitude[sizeof(GPS.longitude) - 1] = '\0'; memcpy(GPS.E_W, fields[6], sizeof(GPS.E_W) - 1); GPS.E_W[sizeof(GPS.E_W) - 1] = '\0'; GPS.isParseData = 1; GPS.isUsefull = (fields[2][0] == 'A') ? 1 : 0; } } } /* 改进点总结 使用 strtok 进行分隔: 更加简洁地分割字符串。 数组存储字段: 使用数组存储每个字段的指针,减少重复代码。 边界检查: 确保字段数量足够,避免数组越界。 字符串截断: 确保复制的字符串以 null 结尾,避免潜在的字符串处理问题。 */ #endif // 转换角度 double Convert_to_degrees(char *data) { double temp = atof(data); int deg = (int)(temp / 100); double min = temp - deg * 100; return deg + (min / 60.0); } // 串口数据清除 void GPS_Data_CLR(void) { memset(GPS_DMA_RX_BUF,0,GPS_DMA_RX_BUF_LEN); } //void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) //{ // if(huart->Instance == USART2) // { // // 根据 Size 拷贝接收到的数据 // memcpy(GPS.GPS_Buffer,GPS_DMA_RX_BUF,Size); // GPS.GPS_Buffer[Size] = '\0'; // GPS.isGetData = 1; //数据接收标志位置为1 // // tx_event_flags_set(&system_events, EVENT_GPS_DATA_READY, TX_OR); // //重新开启接收 // HAL_UARTEx_ReceiveToIdle_IT(&huart2,GPS_DMA_RX_BUF,GPS_DMA_RX_BUF_LEN); // } // //} // 如果需要使用到ThreadX 就把gps.h中的 TEST 宏定义加入 #ifdef TEST void gps_thread_entry(ULONG thread_input) { GPS_Init(); static int gps_first_fix_sent = 0; BleMessage msg; while (1) { ULONG events; tx_event_flags_get(&system_events, EVENT_GPS_DATA_READY, TX_OR_CLEAR, &events, TX_WAIT_FOREVER); parseGpsBuffer(); // HCBle_SendData("[GPS] isGetData=%d, isParseData=%d, isUsefull=%d, Buffer=%s\r\n", // GPS.isGetData, GPS.isParseData, GPS.isUsefull, GPS.GPS_Buffer); if (GPS.isParseData && GPS.isUsefull) { current_location.lat = Convert_to_degrees(GPS.latitude); current_location.lon = Convert_to_degrees(GPS.longitude); tx_event_flags_set(&system_events, EVENT_LOCATION_UPDATED, TX_OR); // msg.lat = current_location.lat; // msg.lon = current_location.lon; // snprintf(msg, sizeof(msg), "#{\"lat\":%.6f,\"lon\":%.6f,\"angle\":%.2f}\n", // current_location.lat, // current_location.lon, // current_location.angle); BleMessage msg = current_location; tx_queue_send(&ble_tx_queue, &msg, TX_WAIT_FOREVER); } } } #endif