日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STM32——定位模块ATGM336H,数据解析,提取经纬度

發布時間:2023/12/20 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32——定位模块ATGM336H,数据解析,提取经纬度 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

模塊介紹

ATGM336H定位模塊支持GPS系統,BDS(北斗)系統,GLONASS(俄羅斯)系統,伽利略衛星導航系統(歐盟)。這個模塊要拿到室外才能接收到信號,且初次初始化或者隔太久時間沒有啟用會導致獲取定位信息的時間很長。

可以使用中科微電子提供的集成軟件設置模塊,可以設置串口輸出的參數,波特率等等參數。
本文介紹用STM32串口接收定位模塊的數據,并將數據進行解析,解析后得到經緯度的原始數據,把經緯度原始數據轉換成精確的經緯度信息后存放到數組里,可打印或繼續串口傳輸到其他設備,后面會介紹傳輸到ESP32,并保存到SPIFFS中。
上圖是模塊通過串口向上位機輸出的數據幀樣例。

通過GNSS工具可以看到模塊能夠獲取的數據幀有如下格式。

其中RMC數據是最簡定位信息,得到這串數據后,可以將GNRMC開始的前六項數據提取,分別是UTC時間,數據有效標志位,緯度,緯度方向,經度,經度方向。此時的經度和緯度只是原始數據,需要再轉換為精確數據。

RMC的數據樣例為

$GNRMC,123211.000,A,2295.33602,N,11326.27041,E,3.21,217.19,100722,,,A*7A

程序思路

數據轉換:
2322.74250 格式:ddmm.mmmmm
11326.27041 格式:ddmm.mmmmm
轉換成北緯:23 + 22.74250 / 60 = 23.37904
轉換成東經:113 + 26.27041 / 60 = 113.43784
比較不準。。串口輸出的數據就是這樣的,估計芯片哪里出了問題。。
讀取數據可以先用一個緩存數組接收所有的數據,先判斷是不是$GNRMC開頭的數據幀,如果是的話則逐個字符接收,因為數據幀是以換行符為結尾的,當讀取到’\n’則是數據幀的結尾。
定義幾個字符數組,用于分別存放UTC時間,經度和緯度的原始數組,經度和緯度的方向。
以逗號為分隔符切割字符串,這里我們需要用到strstr這個函數。

返回指向str1中第一次出現str2的位置的指針,當str1中沒有str2則返回空指針。我們可以定義一個子串指針,用這個函數在數據幀中找逗號,再用memcpy函數把數據分割后存在相應的數組。

#include "ATGM336H.h" #include "string.h"#define GPS_Buffer_Length 80 #define UTCTime_Length 11 #define latitude_Length 11 #define N_S_Length 2 #define longitude_Length 12 #define E_W_Length 2 char USART_RX_BUF[USART_REC_LEN]; //接收緩沖,最大USART_REC_LEN個字節. typedef struct SaveData {char GPS_Buffer[GPS_Buffer_Length];char isGetData; //數據獲取完成標志位char isParseData; //解析完成標志位char UTCTime[UTCTime_Length]; //UTC時間char latitude[latitude_Length]; //緯度char N_S[N_S_Length]; //N/Schar longitude[longitude_Length]; //經度char E_W[E_W_Length]; //E/Wchar isUsefull; //信息有效標志位 }GNRMC;

首先定義一個結構體存放幾個數組,并宏定義數組的長度。

void ATGM_StructInit() {GNRMC_Info.isGetData = false;GNRMC_Info.isParseData = false;GNRMC_Info.isUsefull = false;memset(GNRMC_Info.GPS_Buffer, 0, GPS_Buffer_Length); memset(GNRMC_Info.UTCTime, 0, UTCTime_Length);memset(GNRMC_Info.latitude, 0, latitude_Length);memset(GNRMC_Info.N_S, 0, N_S_Length);memset(GNRMC_Info.longitude, 0, longitude_Length);memset(GNRMC_Info.E_W, 0, E_W_Length); }

首先初始化結構體,先把結構體成員內容全部置零。

void ATGM336H_Init() {GPIO_InitTypeDef GPIO_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;USART_InitTypeDef USART_InitStructure;ATGM_StructInit();RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //USART1_TX PA.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure);//USART1_RX PA.10GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure); //配置中斷通道NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ;//優先級最低NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_InitStructure.USART_BaudRate = 9600;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發模式USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);USART_Cmd(USART1, ENABLE); ClrBuf(); //初始化 }

之后配置引腳,配置串口1中斷,配置串口。引腳TX我選擇PA9,RX選擇PA10。TX要選擇復用推挽輸出,RX選擇浮空輸入。之后開通NVIC中斷通道,配置串口波特率為9600,8位數據位,1位停止位,吳嬌艷,無硬件流控制,模式為收發模式,因為我既要接收定位數據,也要打印或發送數據。最后別忘記使能中斷和串口。

unsigned int DataIndex = 0; void USART1_IRQHandler() {unsigned char receive;if(USART_GetITStatus(USART1, USART_IT_RXNE) == 1) {receive = USART_ReceiveData(USART1); //讀取接收到的數據if(receive == '$')DataIndex = 0; USART_RX_BUF[DataIndex++] = receive;//GNRMC\GPRMCif(USART_RX_BUF[0] == '$' && USART_RX_BUF[4] == 'M' && USART_RX_BUF[5] == 'C') {if(receive == '\n') {memset(GNRMC_Info.GPS_Buffer, 0, GPS_Buffer_Length); //清空memcpy(GNRMC_Info.GPS_Buffer, USART_RX_BUF, DataIndex); //保存數據GNRMC_Info.isGetData = true;DataIndex = 0;memset(USART_RX_BUF, 0, USART_REC_LEN); //清空 } } } }

先是定義一個DataIndex作為數組的下標,當讀到了$標志表示數據幀開始,將下標置零,之后判斷是不是我們要讀取的這種格式,如果是則讀到’\n’,即把數據轉而存儲到GPS_Buffer中,并把數據讀取標志位置為true。

void ParseGps() {char *subString;char *subStringNext;char i = 0;if (GNRMC_Info.isGetData){GNRMC_Info.isGetData = false; // printf("\r\n"); // printf(GNRMC_Info.GPS_Buffer);//截取數據幀前六部分 |對地航速 對地航向 日期//$GNRMC,112536.000,A,2322.75023,N,11326.28605,E,| 0.00, 0.00, 100722,,,A*78for (i = 0 ; i <= 6 ; i++){if (i == 0){if ((subString = strstr(GNRMC_Info.GPS_Buffer, ",")) == NULL)//如果沒有找到逗號{return;//ERROR}}else{subString++;if ((subStringNext = strstr(subString, ",")) != NULL){char usefulBuffer[2]; switch(i){case 1:memcpy(GNRMC_Info.UTCTime, subString, subStringNext - subString);break; case 2:{memcpy(usefulBuffer, subString, subStringNext - subString);//有效標志位if(usefulBuffer[0] == 'A')GNRMC_Info.isUsefull = true;else if(usefulBuffer[0] == 'V')GNRMC_Info.isUsefull = false; break;} case 3:memcpy(GNRMC_Info.latitude, subString, subStringNext - subString);break; case 4:memcpy(GNRMC_Info.N_S, subString, subStringNext - subString);break; case 5:memcpy(GNRMC_Info.longitude, subString, subStringNext - subString);break; case 6:memcpy(GNRMC_Info.E_W, subString, subStringNext - subString);break; default:break;}subString = subStringNext; }}}GNRMC_Info.isParseData = true; } }

這里進行六次循環,把數據幀分成六部分,用strstr函數找到從子串next指針開始的下一個逗號的位置,并把這個這個位置到子串指針之間的數據分別存到各自的數組中去。六次循環之后便結束,因為后面的數據是對地航速,對地航向和日期,我沒有這個需求,有需要的同學可以自己修改。

extern float Lat; extern float Lon; extern char dest[23]; void printGpsBuffer() {//$GNRMC,123211.000,A,2322.74250,N,11326.27041,E,3.21,217.19,100722,,,A*7Aif (GNRMC_Info.isParseData){int i = 0;GNRMC_Info.isParseData = false; if(GNRMC_Info.isUsefull){float tmp = 0; int j = 0; GNRMC_Info.isUsefull = false;for (i = 0; GNRMC_Info.latitude[i] != '\0'; i++){if (GNRMC_Info.latitude[i] == '.'){continue;}if (i <= 1){Lat = (GNRMC_Info.latitude[0] - 48) * 10 + (GNRMC_Info.latitude[1] - 48);//取出個位和十位}else{tmp += (GNRMC_Info.latitude[i] - 48);tmp *= 10;}}for (j = 0; j <= 5; j++){tmp /= 10;}Lat += tmp / 60;//23 22.74250//23.xxxxxint iLat = 0; iLat = (int)Lat;GNRMC_Info.latitude[0] = iLat / 10 + '0';GNRMC_Info.latitude[1] = iLat % 10 + '0';GNRMC_Info.latitude[2] = '.';Lat -= iLat;for (j = 3; j < 10; j++){Lat *= 10;iLat = (int)Lat;GNRMC_Info.latitude[j] = iLat + '0';Lat -= iLat;} tmp = 0;//113.27041for (i = 0; GNRMC_Info.longitude[i] != '\0'; i++){if (GNRMC_Info.longitude[i] == '.'){continue;}if (i <= 2){Lon = (((GNRMC_Info.longitude[0] - 48) * 10 + (GNRMC_Info.longitude[1] - 48)) * 10) + (GNRMC_Info.longitude[2] - 48);//取出個位和十位和百位}else{tmp += (GNRMC_Info.longitude[i] - 48);tmp *= 10;}}for (j = 0; j <= 5; j++){tmp /= 10;}int iLon = 0;//113.43784Lon += tmp / 60;iLon = (int)Lon;GNRMC_Info.longitude[0] = iLon / 100 + '0';GNRMC_Info.longitude[1] = (iLon % 100) / 10 + '0';GNRMC_Info.longitude[2] = iLon % 10 + '0';GNRMC_Info.longitude[3] = '.';Lon -= iLon;for (j = 4; j < 11; j++){Lon *= 10;iLon = (int)Lon;GNRMC_Info.longitude[j] = iLon + '0';Lon -= iLon;}dest[8] = dest[10] = dest[20] = ',';dest[9] = 'N'; dest[21] = 'E'; dest[22] = '\0';for(i = 0; i < 22; i++){if(i <= 7)dest[i] = GNRMC_Info.latitude[i];if(i >= 11 && i <= 19)dest[i] = GNRMC_Info.longitude[i - 11];}//printf("\r\ndest = ");printf(dest);//printf("\r\n");}else{printf("GPS DATA Is Not Useful!");} } }

最后就是數據的轉換,要把經緯度數組中的字符提取出來組合成數字。對于緯度,先提取數組前兩位的數據作為個位和十位,從第三位開始后面的數據提取出來組成一個浮點數,之后把這個浮點數除以60,最后加上個位和十位的整數,便得到了轉換后的緯度。經度同理,區別在于經度有百位。
這里只是簡單的沒有啥依據的不合理的提取。
提取得到兩個浮點數后,把經緯度方向一起存儲在dest數組中,組合成完整的包括經緯度方向的數據。

結語

數據解析的步驟很繁瑣,且模塊輸出的原始數據不是很準確。后面再試試。

總結

以上是生活随笔為你收集整理的STM32——定位模块ATGM336H,数据解析,提取经纬度的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 91黄色在线观看 | 色诱久久av | 国产网红无码精品视频 | 免费在线视频一区 | 免费精品无码AV片在线观看黄 | 亚洲精品偷拍 | 免费一级毛片麻豆精品 | 日本三级视频在线观看 | av资源网在线 | 中文字幕精品三级久久久 | av资源在线播放 | 国产午夜伦鲁鲁 | aaaaa级少妇高潮大片免费看 | 日韩av中文字幕在线播放 | 黄色av网站在线 | 国产精品入口日韩视频大尺度 | 成人h动漫精品一区二区下载 | 亚洲精品久久久久久久久久 | 色网站免费 | 欧美成人午夜精品久久久 | 欧美顶级metart裸体全部自慰 | 日本一区免费看 | 国产精品久久久久久久久免费看 | 一区二区三区在线观看免费视频 | 蜜桃臀aⅴ精品一区二区三区 | 亚洲天天综合网 | 亚洲乱亚洲乱妇 | 超碰69 | 亚洲av片不卡无码久久 | 影音先锋久久久 | 黄色av网页| 人人艹人人爱 | 啪啪国产精品 | 久久最新网址 | 亚洲第一视频网 | 中文字幕精品在线视频 | 日韩欧美99 | 欧美一级大片在线观看 | 91草视频 | 国产福利资源 | 97理伦| 日韩有码在线视频 | 成人午夜免费在线观看 | 久草小说| 精品一区电影 | 精东传媒在线 | 亚洲av成人无码一区二区三区在线观看 | 中文不卡视频 | 久久涩涩| 亚洲熟女综合一区二区三区 | 人人爽人人爽人人片av | 1区2区视频 | 久久久久久久久免费 | 合欢视频在线观看 | 91波多野结衣| 99久久久无码国产精品 | 奶妈的诱惑 | 国产sm在线 | 成人日韩视频 | 色图综合 | 欧美在线一级片 | 黑人巨大av | 美国黄色一级毛片 | 黄色免费看视频 | 欧美一区精品 | 日韩三级一区 | 亚洲成a人v欧美综合天堂麻豆 | 激情五月婷婷综合 | 欧美日韩偷拍视频 | 日韩精品一区二区在线视频 | 成人免费视频国产在线观看 | 夜夜夜网| 亚洲一级淫片 | 久久精品在线免费观看 | 国产无套丰满白嫩对白 | www.69pao.com| 狠狠操91| 欧美精品一区二区视频 | 女同一区 | 寻找身体恐怖电影免费播放 | aa片在线观看视频在线播放 | 少妇人妻真实偷人精品视频 | 成人毛片视频在线观看 | 婷婷人体 | 国产在线视频第一页 | 古装三级吃奶做爰 | 天天爽天天插 | 亚洲第一国产视频 | 国产成人欧美一区二区三区91 | 日韩电影中文字幕在线观看 | √天堂中文官网8在线 | www.午夜视频 | 玖玖玖在线观看 | 凹凸日日摸日日碰夜夜 | 欧美精品自拍 | 中文字幕亚洲精品在线观看 | 国产在线视频导航 | 中文字幕日韩国产 | 日本一区二区欧美 |