NEO—6M/7M GPS模塊,具有高靈敏度、低功耗、小型化、高追蹤靈敏度,大大擴(kuò)大了其定位的覆蓋面,在普通GPS接收模塊不能定位的地方,如狹窄都市天空下、密集的叢林環(huán)境,NEO-6M都能高精度定位。模塊的高靈敏度、小靜態(tài)漂移、低功耗及輕巧的體積,適用于車載、手持設(shè)備如PDA,車輛監(jiān)控、手機(jī)、攝像機(jī)及其他移動(dòng)定位系統(tǒng)的應(yīng)用,是GPS產(chǎn)品應(yīng)用的好選擇。
一模塊來源
模塊實(shí)物展示:
資料鏈接:https://pan.baidu.com/s/1QvwMg9JbkzFauYmwExWcnQ
資料提取碼:8888
二規(guī)格參數(shù)
工作電壓:3.3V-5V
工作電流:10-26mA
模塊尺寸:
控制方式:SPI
三移植過程
我們的目標(biāo)是在立創(chuàng)·CW32F030C8T6開發(fā)板上能夠獲取到定位信息的功能。首先要獲取資料,查看數(shù)據(jù)手冊應(yīng)如何實(shí)現(xiàn),再移植至我們的工程。
3.1查看資料
注:在主電源斷開后,后備電池可以維持半小時(shí)左右的GPS星歷數(shù)據(jù)的保存,以支持溫啟動(dòng)或熱啟動(dòng),從而實(shí)現(xiàn)快速定位。
首次定位時(shí)間較長,請(qǐng)確保是在室外進(jìn)行定位。
3.2引腳選擇
想要使用uart串口,需要確定使用的引腳是否有串口外設(shè)功能,可以通過用戶手冊進(jìn)行查看。在用戶手冊的第146頁。
這里選擇使用PA2和PA3的附加串口2功能。
有串口功能的引腳
模塊接線圖
3.3移植至工程
移植步驟中的導(dǎo)入.c和.h文件與【CW32模塊使用】DHT11溫濕度傳感器相同,只是將.c和.h文件更改為bsp_gps.c與bsp_gps.h。這里不再過多講述,移植完成后面修改相關(guān)代碼。
在文件bsp_gps.c中,編寫如下代碼。
/*
* Change Logs:
* Date Author Notes
* 2024-06-21 LCKFB-LP first version
*/
#include "bsp_gps.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define GPSRX_LEN_MAX 255
unsigned char GPSRX_BUFF[GPSRX_LEN_MAX];
unsigned char GPSRX_LEN = 0;
_SaveData Save_Data;
/******************************************************************
* 函 數(shù) 名 稱:GPS_GPIO_Init
* 函 數(shù) 說 明:GPS引腳初始化
* 函 數(shù) 形 參:band_rate GPS通信波特率
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:默認(rèn)波特率為9600
******************************************************************/
void GPS_GPIO_Init(uint32_t band_rate)
{
GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化結(jié)構(gòu)體
BSP_GPS_GPIO_RCC_ENABLE(); // 使能GPIO時(shí)鐘
BSP_GPS_UART_RCC_ENABLE(); // 使能UART時(shí)鐘
GPIO_InitStruct.Pins = BSP_GPS_TX_PIN; // GPIO引腳
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽輸出
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // 輸出速度高
GPIO_Init(BSP_GPS_GPIO_PORT, &GPIO_InitStruct); // 初始化
GPIO_InitStruct.Pins = BSP_GPS_RX_PIN; // GPIO引腳
GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP; // 上拉輸入
GPIO_Init(BSP_GPS_GPIO_PORT, &GPIO_InitStruct); // 初始化
BSP_GPS_AF_UART_TX(); // UART_TX復(fù)用
BSP_GPS_AF_UART_RX(); // UART_RX復(fù)用
// 配置UART
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = band_rate; // 波特率
USART_InitStructure.USART_Over = USART_Over_16; // 配置USART的過采樣率。
USART_InitStructure.USART_Source = USART_Source_PCLK; // 設(shè)置時(shí)鐘源
USART_InitStructure.USART_UclkFreq = 64000000; //設(shè)置USART時(shí)鐘頻率(和主頻一致即可)
USART_InitStructure.USART_StartBit = USART_StartBit_FE; //RXD下降沿開始
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 停止位1
USART_InitStructure.USART_Parity = USART_Parity_No ; // 不使用校驗(yàn)
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 不使用流控
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 收發(fā)模式
USART_Init(BSP_GPS_USART, &USART_InitStructure); // 初始化串口2
// 優(yōu)先級(jí),無優(yōu)先級(jí)分組
NVIC_SetPriority(BSP_GPS_IRQn, 0);
// UARTx中斷使能
NVIC_EnableIRQ(BSP_GPS_IRQn);
// 使能UARTx RC中斷
USART_ITConfig(BSP_GPS_USART, USART_IT_RC, ENABLE);
}
/******************************************************************
* 函 數(shù) 名 稱:GPS_Send_Bit
* 函 數(shù) 說 明:向GPS發(fā)送單個(gè)字符
* 函 數(shù) 形 參:ch發(fā)送的字符
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:無
******************************************************************/
void GPS_Send_Bit(unsigned char ch)
{
// 發(fā)送一個(gè)字節(jié)
USART_SendData_8bit(BSP_GPS_USART, (uint8_t)ch);
// 等待發(fā)送完成
while( RESET == USART_GetFlagStatus(BSP_GPS_USART, USART_FLAG_TXE) ){}
}
/******************************************************************
* 函 數(shù) 名 稱:GPS_send_String
* 函 數(shù) 說 明:GPS發(fā)送字符串
* 函 數(shù) 形 參:str要發(fā)送的字符串
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:無
******************************************************************/
void GPS_send_String(unsigned char *str)
{
while( str && *str ) // 地址為空或者值為空跳出
{
GPS_Send_Bit(*str++);
}
}
/******************************************************************
* 函 數(shù) 名 稱:Hand
* 函 數(shù) 說 明:在GPS數(shù)據(jù)中,識(shí)別是否有想要的串口命令
* 函 數(shù) 形 參:需要識(shí)別的命令
* 函 數(shù) 返 回:1識(shí)別成功 0識(shí)別失敗
* 作 者:LC
* 備 注:無
******************************************************************/
uint8_t Hand(char *a)
{
if(strstr((const char*)GPSRX_BUFF,a)!=NULL)
return 1;
else
return 0;
}
/******************************************************************
* 函 數(shù) 名 稱:CLR_Buf
* 函 數(shù) 說 明:清除串口接收的數(shù)據(jù)
* 函 數(shù) 形 參:無
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:無
******************************************************************/
void CLR_Buf(void)
{
memset(GPSRX_BUFF, 0, GPSRX_LEN_MAX); //清空
GPSRX_LEN = 0;
}
/******************************************************************
* 函 數(shù) 名 稱:clrStruct
* 函 數(shù) 說 明:清除GPS結(jié)構(gòu)體數(shù)據(jù)
* 函 數(shù) 形 參:無
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:無
******************************************************************/
void clrStruct(void)
{
Save_Data.isGetData = 0;
Save_Data.isParseData = 0;
Save_Data.isUsefull = 0;
memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length); //清空
memset(Save_Data.UTCTime, 0, UTCTime_Length);
memset(Save_Data.latitude, 0, latitude_Length);
memset(Save_Data.N_S, 0, N_S_Length);
memset(Save_Data.longitude, 0, longitude_Length);
memset(Save_Data.E_W, 0, E_W_Length);
}
/******************************************************************
* 函 數(shù) 名 稱:BSP_GPS_IRQHandler
* 函 數(shù) 說 明:串口中斷服務(wù)函數(shù)
* 函 數(shù) 形 參:無
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:無
******************************************************************/
void BSP_GPS_IRQHandler(void)
{
uint8_t Res;
if(USART_GetITStatus(BSP_GPS_USART,USART_IT_RC) != RESET) // 接收緩沖區(qū)不為空
{
Res = USART_ReceiveData(BSP_GPS_USART);
if(Res == '$')
{
GPSRX_LEN = 0;
}
GPSRX_BUFF[GPSRX_LEN++] = Res;
if(GPSRX_BUFF[0] == '$' && GPSRX_BUFF[4] == 'M' && GPSRX_BUFF[5] == 'C')//確定是否收到"GPRMC/GNRMC"這一幀數(shù)據(jù)
{
if(Res == 'n')
{
memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length); //清空
memcpy(Save_Data.GPS_Buffer, GPSRX_BUFF, GPSRX_LEN); //保存數(shù)據(jù)
Save_Data.isGetData = 1;
GPSRX_LEN = 0;
memset(GPSRX_BUFF, 0, GPSRX_LEN_MAX); //清空
}
}
if(GPSRX_LEN >= GPSRX_LEN_MAX)
{
GPSRX_LEN = GPSRX_LEN_MAX;
}
}
USART_ClearITPendingBit(BSP_GPS_USART, USART_IT_RC); //已經(jīng)處理就清楚標(biāo)志位
}
在文件bsp_gps.h中,編寫如下代碼。
/*
* Change Logs:
* Date Author Notes
* 2024-06-21 LCKFB-LP first version
*/
#ifndef _BSP_GPS_H
#define _BSP_GPS_H
#include "board.h"
#define BSP_GPS_GPIO_RCC_ENABLE() __RCC_GPIOA_CLK_ENABLE() // 串口TX的端口時(shí)鐘
#define BSP_GPS_UART_RCC_ENABLE() __RCC_UART2_CLK_ENABLE() // 串口2的時(shí)鐘
#define BSP_GPS_AF_UART_TX() PA02_AFx_UART2TXD() // GPIO的引腳復(fù)用
#define BSP_GPS_AF_UART_RX() PA03_AFx_UART2RXD() // GPIO的引腳復(fù)用
#define BSP_GPS_GPIO_PORT CW_GPIOA // 串口TX的端口
#define BSP_GPS_TX_PIN GPIO_PIN_2 // 串口TX的引腳
#define BSP_GPS_RX_PIN GPIO_PIN_3 // 串口RX的引腳
#define BSP_GPS_USART CW_UART2 // 串口2
#define BSP_GPS_IRQn UART2_IRQn
#define BSP_GPS_IRQHandler UART2_IRQHandler
//定義數(shù)組長度
#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
typedef struct SaveData
{
char GPS_Buffer[GPS_Buffer_Length];
char isGetData; //是否獲取到GPS數(shù)據(jù)
char isParseData; //是否解析完成
char UTCTime[UTCTime_Length]; //UTC時(shí)間
char latitude[latitude_Length]; //緯度
char N_S[N_S_Length]; //N/S
char longitude[longitude_Length]; //經(jīng)度
char E_W[E_W_Length]; //E/W
char isUsefull; //定位信息是否有效
} _SaveData;
extern _SaveData Save_Data;
void GPS_GPIO_Init(uint32_t band_rate);
void CLR_Buf(void);
uint8_t Hand(char *a);
void clrStruct(void);
#endif
四移植驗(yàn)證
>>>
在自己工程中的main主函數(shù)中,編寫如下。
/*
* Change Logs:
* Date Author Notes
* 2024-06-21 LCKFB-LP first version
*/
#include "board.h"
#include "stdio.h"
#include "bsp_uart.h"
#include "bsp_gps.h"
void parseGpsBuffer(void);
void printGpsBuffer(void);
int32_t main(void)
{
board_init();
uart1_init(115200U);
GPS_GPIO_Init(9600U);
clrStruct();
printf("startrn");
while(1)
{
parseGpsBuffer();
printGpsBuffer();
}
}
/******************************************************************
* 函 數(shù) 名 稱:errorLog
* 函 數(shù) 說 明:錯(cuò)誤日志打印
* 函 數(shù) 形 參:num 要輸出的錯(cuò)誤碼
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:無
******************************************************************/
void errorLog(int num)
{
while (1)
{
printf("ERROR%drn",num);
}
}
/******************************************************************
* 函 數(shù) 名 稱:parseGpsBuffer
* 函 數(shù) 說 明:解析GPS發(fā)送過來的數(shù)據(jù)
* 函 數(shù) 形 參:無
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:無
******************************************************************/
void parseGpsBuffer(void)
{
char *subString;
char *subStringNext;
char i = 0;
if (Save_Data.isGetData)
{
Save_Data.isGetData = 0;
printf("**************rn");
printf("%srn",Save_Data.GPS_Buffer);
for (i = 0 ; i <= 6 ; i++)
{
if (i == 0)
{
if ((subString = strstr(Save_Data.GPS_Buffer, ",")) == NULL)
errorLog(1); //解析錯(cuò)誤
}
else
{
subString++;
if ((subStringNext = strstr(subString, ",")) != NULL)
{
char usefullBuffer[2];
switch(i)
{
case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break; //獲取UTC時(shí)間
case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break; //獲取UTC時(shí)間
case 3:memcpy(Save_Data.latitude, subString, subStringNext - subString);break; //獲取緯度信息
case 4:memcpy(Save_Data.N_S, subString, subStringNext - subString);break; //獲取N/S
case 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break; //獲取經(jīng)度信息
case 6:memcpy(Save_Data.E_W, subString, subStringNext - subString);break; //獲取E/W
default:break;
}
subString = subStringNext;
Save_Data.isParseData = 1;
if(usefullBuffer[0] == 'A')
Save_Data.isUsefull = 1;
else if(usefullBuffer[0] == 'V')
Save_Data.isUsefull = 0;
}
else
{
errorLog(2); //解析錯(cuò)誤
}
}
}
}
}
/******************************************************************
* 函 數(shù) 名 稱:printGpsBuffer
* 函 數(shù) 說 明:輸出解析后的數(shù)據(jù)
* 函 數(shù) 形 參:無
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:無
******************************************************************/
void printGpsBuffer(void)
{
// uint8_t buff[100]={0};
if (Save_Data.isParseData)
{
Save_Data.isParseData = 0;
//在廣東深圳進(jìn)行測量,發(fā)現(xiàn)UTC時(shí)間存在8小時(shí)誤差
printf("Save_Data.UTCTime = ");
printf("%s",Save_Data.UTCTime);
printf("rn");
if(Save_Data.isUsefull)
{
Save_Data.isUsefull = 0;
//串口顯示緯度
printf("Save_Data.latitude = ");
printf("%s",Save_Data.latitude);
//串口顯示
printf("Save_Data.N_S = ");
printf("%srn",Save_Data.N_S);
//串口顯示經(jīng)度
printf("Save_Data.longitude = ");
printf("%s",Save_Data.longitude);
printf("rn");
//串口顯示
printf("Save_Data.E_W = ");
printf("%s",Save_Data.E_W);
printf("rn");
}
else
{
printf("GPS DATA is not usefull!rn");
}
}
}
移植現(xiàn)象:
注意室內(nèi)大概率無法定位,所以最好外接屏幕去空曠地帶測試!
模塊移植成功案例代碼:
鏈接:https://pan.baidu.com/s/1Zqe1B8ncdZA2cpboYM-kgA?pwd=LCKF
提取碼:LCKF