【CW32模块使用】NEO-6M GPS模块

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 255

unsigned 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复用

    // 配置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;               // 设置时钟源
    USART_InitStructure.USART_UclkFreq = 64000000;                      //设置USART时钟频率(和主频一致即可)
    USART_InitStructure.USART_StartBit = USART_StartBit_FE;             //RXD下降沿开始
    USART_InitStructure.USART_StopBits = USART_StopBits_1;              // 停止位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(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;
        else
                        return 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 2

typedef 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/S
        char longitude[longitude_Length];                //经度
        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

四、移植验证

在自己工程中的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("start\r\n");
        while(1)
        {
                parseGpsBuffer();
                printGpsBuffer();
        }
}

/******************************************************************
 * 函 数 名 称:errorLog
 * 函 数 说 明:错误日志打印
 * 函 数 形 参:num 要输出的错误码
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
******************************************************************/
void errorLog(int num)
{
        while (1)
        {
                  printf("ERROR%d\r\n",num);
        }
}

/******************************************************************
 * 函 数 名 称:parseGpsBuffer
 * 函 数 说 明:解析GPS发送过来的数据
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
******************************************************************/
void parseGpsBuffer(void)
{
        char *subString;
        char *subStringNext;
        char i = 0;
        if (Save_Data.isGetData)
        {
                Save_Data.isGetData = 0;
                printf("**************\r\n");
                printf("%s\r\n",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/S
                                                case 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break;        //获取经度信息
                                                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);        //解析错误
                                }
                        }
                }
        }
}

/******************************************************************
 * 函 数 名 称: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("\r\n");

        if(Save_Data.isUsefull)
        {
            Save_Data.isUsefull = 0;
            //串口显示纬度
            printf("Save_Data.latitude = ");
            printf("%s",Save_Data.latitude);


            //串口显示
            printf("Save_Data.N_S = ");
            printf("%s\r\n",Save_Data.N_S);

            //串口显示经度
            printf("Save_Data.longitude = ");
            printf("%s",Save_Data.longitude);
            printf("\r\n");

            //串口显示
            printf("Save_Data.E_W = ");
            printf("%s",Save_Data.E_W);
            printf("\r\n");


        }
        else
        {
            printf("GPS DATA is not usefull!\r\n");
        }

    }
}

移植现象:

注意室内大概率无法定位,所以最好外接屏幕去空旷地带测试!

模块移植成功案例代码:

链接:https://pan.baidu.com/s/1Zqe1B8ncdZA2cpboYM-kgA?pwd=LCKF

提取码:LCKF

作者:CW32生态社区

物联沃分享整理
物联沃-IOTWORD物联网 » 【CW32模块使用】NEO-6M GPS模块

发表回复