目的
想利用gps模块给stm32进行授时,同时利用秒脉冲来进行时间校正
1、GPS模块相关介绍
—简介
使用的GPS模块VG7669T160N0MA,购于沃进科技,该定位模块是基于中科微基第四代低功耗 GNSS SOC 单芯片 AT6558R。
—引脚位置图
—引脚说明
—数据帧介绍
模块通过 UART 作为主要输出通道,按照 NMEA0183 的协议格式输出,具体信息请参照《CASIC 多模卫星导航接收机协议规范》。
下面是通过串口打印的信息:
$GNGGA,021345.000,3958.53189,N,11625.31442,E,6,08,6.8,108.0,M,-9.8,M,,*57
$GNGLL,3958.53189,N,11625.31442,E,021345.000,A,E*42
$GNGSA,A,3,10,28,32,,,,,,,,,,10.0,6.8,7.3,1*00
$GNGSA,A,3,06,09,16,39,42,,,,,,,,10.0,6.8,7.3,4*0B
$GPGSV,2,1,05,10,77,278,43,15,,,32,23,,,28,28,29,233,37,0*61
$GPGSV,2,2,05,32,50,304,16,0*54
$BDGSV,2,1,06,06,63,241,36,09,51,235,34,13,,,29,16,71,246,36,0*43
$BDGSV,2,2,06,39,75,262,37,42,67,327,38,0*72
$GNRMC,021345.000,A,3958.53189,N,11625.31442,E,0.26,0.00,221124,,,E,V*0D
我们只需要关注RMC这条消息就行,具体参数说明如下:
2、程序设计
gps.h
#ifndef __GPS_H
#define __GPS_H
#include "sys.h"
#define BOOL int
#define TRUE 1
#define FALSE 0
typedef struct Data
{
char GPS_Buffer[200];//数据接收
BOOL isGetData;//接收数据是否完成
char *UTCTime;//时间戳
char *latitude;//纬度
char *N_S;//南北
char *longitude;//经度
char *E_W;//东西
BOOL isParseData;//是否解析完成
BOOL isUsefull;//是否为有效数据位
}Data;
void gps_init(void);
void parseGpsBuffer(void);
void printfGpsBuffer(void);
#endif
gps.c
#include "gps.h"
#include "usart.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/*
$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
<1> UTC 时间,hhmmss(时分秒)格式
<2> 定位状态,A=有效定位,V=无效定位
<3>纬度ddmm.mmmm(度分)格式(前面的0也将被传输)
<4> 纬度半球N(北半球)或S(南半球)
<5>经度dddmm.mmmm(度分)格式(前面的0也将被传输)
<6> 经度半球E(东经)或W(西经)
<7>地面速率(000.0~999.9节,前面的0也将被传输)
<8>地面航向(000.0~359.9度,以真北为参考基准,前面的0也将被传输)
<9> UTC 日期,ddmmyy(日月年)格式
<10>磁偏角(000.0~180.0度,前面的0也将被传输)
<11> 磁偏角方向,E(东)或W(西)
<12>模式指示(仅NMEA01833.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)
*/
const short int USART1_MAX_RECV_LEN = 200;
char USAR1_RX_BUF[USART1_MAX_RECV_LEN];
const short int GPS_Buffer_Length = 200;
struct Data Save_Data;
volatile unsigned long long stm32UTCTime;//ms级utc时间
void parseGpsBuffer(void){
char *subString;
char *subStringNext;
int i = 0;
char *dot;
char *milliseconds;
long seconds;
int milliseconds_val;
if(Save_Data.isGetData)
{
Save_Data.isGetData = FALSE;
printf("*****************\r\n");
printf("%s",Save_Data.GPS_Buffer);
for(i = 0; i <= 6; i++){
if(i == 0){
if((subString = strstr(Save_Data.GPS_Buffer, ",")) == NULL)
printf("解析错误");
}
else{
subString++;//到达解析数据中逗号的下一位
if((subStringNext = strstr(subString, ",")) != NULL)
{
char usefullBuffer[2];
switch(i){
case 1:
//利用subStringNext和subString的首地址相减来确定指针开辟空间的大小,以防指针不合法。
Save_Data.UTCTime = (char *)malloc((subStringNext - subString)*sizeof(char));
memcpy(Save_Data.UTCTime, subString, subStringNext - subString);
if ((subStringNext - subString) > 0 && !isspace(Save_Data.UTCTime[0])) {
// Save_Data.UTCTime是以秒为单位的时间戳字符串,目的是要转成ms为单位,赋值给stm32UTCTime
dot = strchr(Save_Data.UTCTime, '.'); //移除字符串中的小数点,可以通过替换为 '\0' 来实现
if (dot != NULL) {
*dot = '\0'; // 将小数点替换为字符串终止符
milliseconds = dot + 1; // 毫秒部分是原小数点后面的字符串
seconds = strtol(Save_Data.UTCTime, NULL, 10); //将秒部分(移除前导零)和毫秒部分拼接起来转换秒部分为长整型
milliseconds_val = atoi(dot + 1); // 转换毫秒部分为整型
stm32UTCTime = (unsigned long long)(seconds * 1000 + milliseconds_val); // 将秒和毫秒部分相加,得到最终的毫秒级时间戳
*dot = '.'; // 做完处理了,将小数点替换回去,因为后面打印还要用到Save_Data.UTCTime
printf("\r\n授时成功,stm32UTCTime = %llu\r\n", stm32UTCTime);
}
}
break;
case 2: memcpy(usefullBuffer, subString, subStringNext - subString); break;
case 3: Save_Data.latitude = (char *)malloc((subStringNext - subString)*sizeof(char));
memcpy(Save_Data.latitude, subString, subStringNext - subString);
break;
case 4: Save_Data.N_S = (char *)malloc((subStringNext - subString)*sizeof(char));
memcpy(Save_Data.N_S, subString, subStringNext - subString);
break;
case 5: Save_Data.longitude = (char *)malloc((subStringNext - subString)*sizeof(char));
memcpy(Save_Data.longitude, subString, subStringNext - subString);
break;
case 6: Save_Data.E_W = (char *)malloc((subStringNext - subString)*sizeof(char));
memcpy(Save_Data.E_W, subString, subStringNext - subString);
break;
default: break;
}
subString = subStringNext;
Save_Data.isParseData = TRUE;
if(usefullBuffer[0] == 'A')
Save_Data.isUsefull = TRUE;
else if(usefullBuffer[0] == 'V')
Save_Data.isUsefull = FALSE;
}
else{
printf("解析错误2");
}
}
}
}
}
void printfGpsBuffer(void){
if(Save_Data.isParseData){
Save_Data.isParseData = FALSE;
printf("Save_Data.UTCTime = %s\r\n", Save_Data.UTCTime);//打印数据
free(Save_Data.UTCTime);//释放空间
if(Save_Data.isUsefull){
Save_Data.isUsefull = FALSE;
printf("Save_Data.latitude = %s\r\n", Save_Data.latitude);
free(Save_Data.latitude);
printf("Save_Data.N_S = %s\r\n", Save_Data.N_S);
free(Save_Data.N_S);
printf("Save_Data.longitude = %s\r\n", Save_Data.longitude);
free(Save_Data.longitude);
printf("Save_Data.E_W = %s\r\n", Save_Data.E_W);
free(Save_Data.E_W);
printf("GPS DATA is usefull!\r\n\r\n");
}
else
{
printf("Save_Data.latitude = %s\r\n", Save_Data.latitude);
free(Save_Data.latitude);
printf("Save_Data.N_S = %s\r\n", Save_Data.N_S);
free(Save_Data.N_S);
printf("Save_Data.longitude = %s\r\n", Save_Data.longitude);
free(Save_Data.longitude);
printf("Save_Data.E_W = %s\r\n", Save_Data.E_W);
free(Save_Data.E_W);
printf("GPS DATA is not usefull!\r\n\r\n");
}
}
}
//初始化1pps引脚
void pps_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//GPIOA3初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不带上下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
//初始化为低电平
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
}
//外部中断3服务程序,精准校时
void EXTI3_IRQHandler(void)
{
unsigned long long ms;
unsigned long long seconds_full;
unsigned int seconds;
unsigned long total_minutes;
unsigned int minutes;
unsigned int hours;
printf("\r\n秒脉冲来了,stm32UTCTime = %09llu\r\n", stm32UTCTime);
//stm32UTCTime的格式是hhmmssmmm(小时小时分钟分钟秒秒毫秒毫秒毫秒)
ms = stm32UTCTime % 1000; // 提取毫秒部分
seconds_full = stm32UTCTime / 1000; // 提取秒及以上部分
seconds = seconds_full % 100; // 提取秒
total_minutes = seconds_full / 100; // 首先计算总的分钟数(包括小时的部分)
hours = total_minutes / 100; // 提取小时
minutes = total_minutes % 100; // 提取分钟
// 秒数加一,处理进位
seconds++;
if (seconds >= 60) {
seconds = 0;
minutes++;
if (minutes >= 60) {
minutes = 0;
hours++;
// 处理小时超过24的逻辑
if (hours >= 24) {
hours = 0;
}
}
}
// 重新组合时间戳,毫秒部分清零
stm32UTCTime = ((unsigned long long)hours * 10000 + minutes * 100 + seconds) * 1000;
printf("\r\n时间校正了,stm32UTCTime = %09llu\r\n", stm32UTCTime);
// 清除中断标志位
EXTI_ClearITPendingBit(EXTI_Line3);
}
//外部中断初始化程序,初始化PA3为中断输入.
void EXTI3_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource3);//PA3 连接到中断线3
/* 配置EXTI_Line3*/
EXTI_InitStructure.EXTI_Line = EXTI_Line3;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//中断线使能
EXTI_Init(&EXTI_InitStructure);//配置
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;//外部中断3
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
NVIC_Init(&NVIC_InitStructure);//配置
}
void gps_sleep_mode_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//GPIOA2初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
//初始化为高电平
GPIO_SetBits(GPIOA,GPIO_Pin_2);
}
void gps_init(void)
{
uart1_init(9600);
pps_Init();
gps_sleep_mode_Init();
EXTI3_Init();
stm32UTCTime = 120000123;
}
usart.h
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "stm32f4xx_conf.h"
#include "sys.h"
#define USART_REC_LEN 200 //定义最大接收字节数 200
#define EN_USART6_RX 1 //使能(1)/禁止(0)串口6接收
extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_STA; //接收状态标记
//如果想串口中断接收,请不要注释以下宏定义
void uart6_init(u32 bound);
#endif
void uart1_init(u32 bound);
usart.c
#include "sys.h"
#include "usart.h"
#if SYSTEM_SUPPORT_OS
#include "includes.h" //ucos 使用
#endif
//
//********************************************************************************
//V1.3修改说明
//支持适应不同频率下的串口波特率设置.
//加入了对printf的支持
//增加了串口接收命令功能.
//修正了printf第一个字符丢失的bug
//V1.4修改说明
//1,修改串口初始化IO的bug
//2,修改了USART_RX_STA,使得串口最大接收字节数为2的14次方
//3,增加了USART_REC_LEN,用于定义串口最大允许接收的字节数(不大于2的14次方)
//4,修改了EN_USART1_RX的使能方式
//V1.5修改说明
//1,增加了对UCOSII的支持
//
//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART6->SR&0X40)==0);//循环发送,直到发送完毕
USART6->DR = (u8) ch;
return ch;
}
#endif
#if EN_USART6_RX //如果使能了接收
//串口6中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0; //接收状态标记
//初始化IO 串口6,PC6-tx,PC7-rx
//bound:波特率
void uart6_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE); //使能GPIOC时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6,ENABLE);//使能USART6时钟
//串口6对应引脚复用映射
GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_USART6);
GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_USART6);
//USART6端口配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //GPIOC6与GPIOC7
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOC,&GPIO_InitStructure); //初始化PA9,PA10
//USART6 初始化设置
USART_InitStructure.USART_BaudRate = bound;//波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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(USART6, &USART_InitStructure); //初始化串口1
USART_Cmd(USART6, ENABLE); //使能串口6
//USART_ClearFlag(USART1, USART_FLAG_TC);
#if EN_USART6_RX
USART_ITConfig(USART6, USART_IT_RXNE, ENABLE);//开启相关中断
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART6_IRQn;//串口1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
#endif
}
uint16_t USART_RxData, USART_RxFlag;
uint8_t USART_GetRxFlag(void)
{
if(USART_RxFlag == 1)
{
USART_RxFlag =0;
return 1;
}
return 0;
}
uint8_t USART_GetRxData(void)
{
return USART_RxData;
}
void USART6_IRQHandler(void) //串口1中断服务程序
{
//判断串口接收中断标志是否被置位
if(USART_GetITStatus(USART6 ,USART_IT_RXNE) == SET)
{
USART_RxData = USART_ReceiveData(USART6);
printf("\r\n接收到的字符为%02X\r\n", USART_RxData);
USART_RxFlag =1;
//清楚中断标志
USART_ClearITPendingBit(USART6 ,USART_FLAG_RXNE);
}
}
#endif
void uart1_init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
//串口1对应引脚复用映射
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
//USART1端口配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10
//USART1 初始化设置
USART_InitStructure.USART_BaudRate = bound;//波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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); //初始化串口1
USART_Cmd(USART1, ENABLE); //使能串口1
}
test.h
#ifndef __TEST_H
#define __TEST_H
#include "sys.h"
void gps_test(void);
#endif
test.c
#include "sys.h"
#include "test.h"
#include "delay.h"
#include "usart.h"
#include "math.h" //数学公式
#include <stdio.h>
#include <string.h>
#include "gps.h"
extern short int point1;//接收长度
extern const short int USART1_MAX_RECV_LEN;
extern char USAR1_RX_BUF[200];
extern const short int GPS_Buffer_Length;
short int point1;
extern struct Data Save_Data;
void gps_test()
{
unsigned short int USART_RxData;
gps_init();
while(1)
{
if(USART_GetFlagStatus(USART1 ,USART_FLAG_RXNE) == SET)
{
USART_RxData = USART_ReceiveData(USART1);
printf("%c", USART_RxData);
if(USART_RxData == '$'){
point1 = 0;
}
USAR1_RX_BUF[point1++] = USART_RxData;
if(USAR1_RX_BUF[0] == '$' && USAR1_RX_BUF[4] == 'M' && USAR1_RX_BUF[5] == 'C'){
if(USART_RxData == '\n'){
memcpy(Save_Data.GPS_Buffer, USAR1_RX_BUF, point1);
//“$GNRMC,032223.000,A,3958.52548,N,11625.35966,E,0.39,193.54,211124,,,A,V*0A”
//strcpy(Save_Data.GPS_Buffer, "$GNRMC,235659.123,A,3958.52548,N,11625.35966,E,0.39,193.54,211124,,,A,V*0A\n");
Save_Data.isGetData = TRUE;
point1 = 0;
memset(USAR1_RX_BUF, 0, USART1_MAX_RECV_LEN);
parseGpsBuffer();
printfGpsBuffer();
}
}
if(point1 >= USART1_MAX_RECV_LEN)
{
point1 = USART1_MAX_RECV_LEN;
}
}
}
}
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "math.h" //数学公式
#include "test.h"//测试代码在这里,记得在main初始化相关模块
//STM32F4主时钟: HSE_VALUE * N / (M*P) = 25M* 336 /(25*2) = 168MHz
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart6_init(115200); //初始化串口usrt6,波特率为115200
printf("\r\ngps测试开始\r\n");
gps_test();
printf("\r\n测试结束\r\n");
while(1);
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/panaohan/article/details/144027358
|
共1人点赞
|