NEO—6M/7M GPS模块,具有高灵敏度、低功耗、小型化、高追踪灵敏度,大大扩大了其定位的覆盖面,在普通GPS接收模块不能定位的地方,如狭窄都市天空下、密集的丛林环境,NEO-6M都能高精度定位。模块的高灵敏度、小静态漂移、低功耗及轻巧的体积,适用于车载、手持设备如PDA,车辆监控、手机、摄像机及其他移动定位系统的应用,是GPS产品应用的好选择。
一模块来源
模块实物展示:
资料链接:https://pan.baidu.com/s/1QvwMg9JbkzFauYmwExWcnQ
资料提取码:8888
二规格参数
工作电压:3.3V-5V
工作电流:10-26mA
模块尺寸:
控制方式:SPI
三移植过程
我们的目标是在立创·CW32F030C8T6开发板上能够获取到定位信息的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
3.1查看资料
注:在主电源断开后,后备电池可以维持半小时左右的GPS星历数据的保存,以支持温启动或热启动,从而实现快速定位。
首次定位时间较长,请确保是在室外进行定位。
3.2引脚选择
想要使用uart串口,需要确定使用的引脚是否有串口外设功能,可以通过用户手册进行查看。在用户手册的第146页。
这里选择使用PA2和PA3的附加串口2功能。
有串口功能的引脚
模块接线图
3.3移植至工程
移植步骤中的导入.c和.h文件与【CW32模块使用】DHT11温湿度传感器相同,只是将.c和.h文件更改为bsp_gps.c与bsp_gps.h。这里不再过多讲述,移植完成后面修改相关代码。
在文件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 255unsigned char GPSRX_BUFF[GPSRX_LEN_MAX];unsigned char GPSRX_LEN = 0;_SaveData Save_Data;/******************************************************************* 函 数 名 称:GPS_GPIO_Init* 函 数 说 明:GPS引脚初始化* 函 数 形 参:band_rate GPS通信波特率* 函 数 返 回:无* 作 者:LC* 备 注:默认波特率为9600******************************************************************/void GPS_GPIO_Init(uint32_t band_rate){GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化结构体BSP_GPS_GPIO_RCC_ENABLE(); // 使能GPIO时钟BSP_GPS_UART_RCC_ENABLE(); // 使能UART时钟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复用BSP_GPS_AF_UART_RX(); // UART_RX复用// 配置UARTUSART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = band_rate; // 波特率USART_InitStructure.USART_Over = USART_Over_16; // 配置USART的过采样率。USART_InitStructure.USART_Source = USART_Source_PCLK; // 设置时钟源USART_InitStructure.USART_UclkFreq = 64000000; //设置USART时钟频率(和主频一致即可)USART_InitStructure.USART_StartBit = USART_StartBit_FE; //RXD下降沿开始USART_InitStructure.USART_StopBits = USART_StopBits_1; // 停止位1USART_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(BSP_GPS_USART, &USART_InitStructure); // 初始化串口2// 优先级,无优先级分组NVIC_SetPriority(BSP_GPS_IRQn, 0);// UARTx中断使能NVIC_EnableIRQ(BSP_GPS_IRQn);// 使能UARTx RC中断USART_ITConfig(BSP_GPS_USART, USART_IT_RC, ENABLE);}/******************************************************************* 函 数 名 称:GPS_Send_Bit* 函 数 说 明:向GPS发送单个字符* 函 数 形 参:ch发送的字符* 函 数 返 回:无* 作 者:LC* 备 注:无******************************************************************/void GPS_Send_Bit(unsigned char ch){// 发送一个字节USART_SendData_8bit(BSP_GPS_USART, (uint8_t)ch);// 等待发送完成while( RESET == USART_GetFlagStatus(BSP_GPS_USART, USART_FLAG_TXE) ){}}/******************************************************************* 函 数 名 称:GPS_send_String* 函 数 说 明:GPS发送字符串* 函 数 形 参:str要发送的字符串* 函 数 返 回:无* 作 者:LC* 备 注:无******************************************************************/void GPS_send_String(unsigned char *str){while( str && *str ) // 地址为空或者值为空跳出{GPS_Send_Bit(*str++);}}/******************************************************************* 函 数 名 称:Hand* 函 数 说 明:在GPS数据中,识别是否有想要的串口命令* 函 数 形 参:需要识别的命令* 函 数 返 回:1识别成功 0识别失败* 作 者:LC* 备 注:无******************************************************************/uint8_t Hand(char *a){if(strstr((const char*)GPSRX_BUFF,a)!=NULL)return 1;elsereturn 0;}/******************************************************************* 函 数 名 称:CLR_Buf* 函 数 说 明:清除串口接收的数据* 函 数 形 参:无* 函 数 返 回:无* 作 者:LC* 备 注:无******************************************************************/void CLR_Buf(void){memset(GPSRX_BUFF, 0, GPSRX_LEN_MAX); //清空GPSRX_LEN = 0;}/******************************************************************* 函 数 名 称:clrStruct* 函 数 说 明:清除GPS结构体数据* 函 数 形 参:无* 函 数 返 回:无* 作 者: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);}/******************************************************************* 函 数 名 称:BSP_GPS_IRQHandler* 函 数 说 明:串口中断服务函数* 函 数 形 参:无* 函 数 返 回:无* 作 者:LC* 备 注:无******************************************************************/void BSP_GPS_IRQHandler(void){uint8_t Res;if(USART_GetITStatus(BSP_GPS_USART,USART_IT_RC) != RESET) // 接收缓冲区不为空{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"这一帧数据{if(Res == 'n'){memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length); //清空memcpy(Save_Data.GPS_Buffer, GPSRX_BUFF, GPSRX_LEN); //保存数据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); //已经处理就清楚标志位}
在文件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的端口时钟#define BSP_GPS_UART_RCC_ENABLE() __RCC_UART2_CLK_ENABLE() // 串口2的时钟#define BSP_GPS_AF_UART_TX() PA02_AFx_UART2TXD() // GPIO的引脚复用#define BSP_GPS_AF_UART_RX() PA03_AFx_UART2RXD() // GPIO的引脚复用#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//定义数组长度#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 2typedef struct SaveData{char GPS_Buffer[GPS_Buffer_Length];char isGetData; //是否获取到GPS数据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; //定位信息是否有效} _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
四移植验证
>>>
在自己工程中的main主函数中,编写如下。
/** 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();}}/******************************************************************* 函 数 名 称:errorLog* 函 数 说 明:错误日志打印* 函 数 形 参:num 要输出的错误码* 函 数 返 回:无* 作 者:LC* 备 注:无******************************************************************/void errorLog(int num){while (1){printf("ERROR%drn",num);}}/******************************************************************* 函 数 名 称:parseGpsBuffer* 函 数 说 明:解析GPS发送过来的数据* 函 数 形 参:无* 函 数 返 回:无* 作 者: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); //解析错误}else{subString++;if ((subStringNext = strstr(subString, ",")) != NULL){char usefullBuffer[2];switch(i){case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break; //获取UTC时间case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break; //获取UTC时间case 3:memcpy(Save_Data.latitude, subString, subStringNext - subString);break; //获取纬度信息case 4:memcpy(Save_Data.N_S, subString, subStringNext - subString);break; //获取N/Scase 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break; //获取经度信息case 6:memcpy(Save_Data.E_W, subString, subStringNext - subString);break; //获取E/Wdefault: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); //解析错误}}}}}/******************************************************************* 函 数 名 称:printGpsBuffer* 函 数 说 明:输出解析后的数据* 函 数 形 参:无* 函 数 返 回:无* 作 者:LC* 备 注:无******************************************************************/void printGpsBuffer(void){// uint8_t buff[100]={0};if (Save_Data.isParseData){Save_Data.isParseData = 0;//在广东深圳进行测量,发现UTC时间存在8小时误差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);//串口显示经度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");}}}
移植现象:
注意室内大概率无法定位,所以最好外接屏幕去空旷地带测试!
模块移植成功案例代码:
链接:https://pan.baidu.com/s/1Zqe1B8ncdZA2cpboYM-kgA?pwd=LCKF
提取码:LCKF
1425