上手正点原子ATK-MO1218 GPS-北斗双定位模块(江科协stm32F103C8T6读取,附源码)

   一. 项目简介

          之前大二的时候跟同学做了一个跟GPS定位相关的项目,当时好像我负责的部分有两套方案,一套是直接用esp32+GPS,读取坐标和时间直接上传阿里云服务器,另一套是STM32读取GPS坐标,然后再用其他wifi模块上传数据。其实我已经把第一套方案做出来了后面一想我用esp32读取GPS数据是直接用了别人写好的解析库,平台局限性太大了,不好移植到其他芯片,所以后面我又把第二套方案做了做(基于江科协的代码,相信很多小伙伴都是看的这套教程),本来刚开始我也是想找一找有没有开源的写好的代码,结果在csdn,github上找了一圈,要不就是只介绍没代码,要不就是纯软件库,移植到keil上一顿报错,所以只能自己手搓一个暴力解析协议的代码了。

在此之前,对这个正点原子GPS模块不太熟悉的朋友可以先看这篇文章

https://blog.csdn.net/weixin_46158019/article/details/130979900

esp32读取坐标上传云

模块图片(推荐带这个三米的有源天线)

注意:在室内大概率是接收不到信号的,所以刚开始我是用截取了一段模块有效的数据帧然后通过串口模块连接电脑来模拟模块发送数据,在这里我也建议大家先用串口模块模拟一下,先用电脑来发送数据,因为我代码里也用的是串口来调试模块的,可以看到数据错误信息。

$CFANT,0*42
$GNGGA,084411.000,2519.05255,N,11024.91052,E,1,11,1.7,209.3,M,-19.8,M,,0000*68
$GNGLL,2519.05255,N,11024.91052,E,084411.000,A,A*4E
$GNGSA,A,3,13,15,24,29,,,,,,,,,3.3,1.7,2.8*2B
$GNGSA,A,3,206,207,209,210,216,236,240,,,,,,3.3,1.7,2.8*1D
$GNRMC,084411.000,A,2519.05255,N,11024.91052,E,000.0,000.0,150624,,,A*7D
$GNVTG,000.0,T,,M,000.0,N,000.0,K,A*13
$GNZDA,084411.000,15,06,2024,00,00*46

我截取的一段有效数据

我这里将用stm32F103C8T6最小系统板来接受协议中的'RMC'数据帧

不说废话了,上代码

1.首先修改一下江科大的serial.c文件,特别是中断那里,我这里解析的是协议中的'RMC'数据帧。

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>
#include "Serial.h"

extern char Rawdata[73];
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
uint8_t ReBuf[128];


void Serial_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 38400;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1, &USART_InitStructure);
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_Cmd(USART1, ENABLE);
}

void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}

void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Array[i]);
	}
}

void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)
	{
		Serial_SendByte(String[i]);
	}
}

uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y --)
	{
		Result *= X;
	}
	return Result;
}

void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
	}
}

int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);
	return ch;
}

void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;
	va_start(arg, format);
	vsprintf(String, format, arg);
	va_end(arg);
	Serial_SendString(String);
}

uint8_t Serial_GetRxFlag(void)
{
	if (Serial_RxFlag == 1)
	{
		Serial_RxFlag = 0;
		return 1;
	}
	return 0;
}

uint8_t Serial_GetRxData(void)
{
	return Serial_RxData;
}

void USART1_IRQHandler(void)        //这里修改一下串口中断函数,进行协议解析
{
	uint8_t Redata;
	static uint8_t count=0;
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		Redata = USART_ReceiveData(USART1);
		ReBuf[count++]=Redata;
		
		if(count==1&&(ReBuf[0]!='$'))
			count=0;
		if(count==6)
			if (!( ReBuf[3] == 'R' && ReBuf[4] == 'M' && ReBuf[5] == 'C')) 
			{
				count=0;
			}
		if(count>=72)
		{
			count=0;
			for(int i=0;i<72;i++)
			{
				Rawdata[i]=ReBuf[i];
				
			}
			Rawdata[72]='\0';
		}			
	
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

2.新建一个gps.c和gps.h文件

#ifndef __GPS_H
#define __GPS_H

#include "stm32f10x.h"                  // Device header
#include <stdlib.h> // 包含 atof 函数的头文件
#include <Serial.h>
#include <string.h>

struct Redata_String{
	
	char UTC_s[12];
	char Invalid;
	char latitude_s[12];
	char N_S;
	char longitude_s[12];
	char E_W;
	
};

struct Redata_float{
	
	uint32_t UTC_t;
	uint8_t UTC_hour;
	uint8_t UTC_min;
	uint8_t UTC_sec;
	double latitude_f;
	char N_S ;
	double longitude_f;
	char E_W ;
	
};

void Debug_show(struct Redata_String *raw,struct Redata_float *Processed);
void GPSdata_process(struct Redata_String *raw,struct Redata_float *processed);
void GPS_Init(struct Redata_float *Processed);

#endif


#include "gps.h"


char Rawdata[73];

void GPS_Init(struct Redata_float *Processed)
{
	Processed->E_W=' ';
	Processed->N_S=' ';
}

void GPSdata_process(struct Redata_String *raw,struct Redata_float *Processed)
{
	int i,temp;
	double t;
	raw->Invalid=Rawdata[18];
	if(raw->Invalid=='V')
	{
		Serial_SendString("The location is invalid\r\n");
		memset(Rawdata, 0, sizeof(Rawdata));
	}
	else if(raw->Invalid=='A')
	{
		for(i=7;i<13;i++)
			raw->UTC_s[i-7]=Rawdata[i];
		raw->UTC_s[6]='\0';
		for(i=20;i<30;i++)
			raw->latitude_s[i-20]=Rawdata[i];
		raw->latitude_s[10]='\0';
		
		raw->N_S=Rawdata[31];
		
		for(i=33;i<44;i++)
			raw->longitude_s[i-33]=Rawdata[i];
		raw->longitude_s[11]='\0';
		
		raw->E_W=Rawdata[45];
		
		memset(Rawdata, 0, sizeof(Rawdata));
		
		Processed->UTC_t=atoi(raw->UTC_s);
		Processed->UTC_hour=Processed->UTC_t/10000;
		Processed->UTC_min=(Processed->UTC_t-10000*Processed->UTC_hour)/100;
		Processed->UTC_sec=Processed->UTC_t-10000*Processed->UTC_hour-100*Processed->UTC_min;
		Processed->UTC_hour=Processed->UTC_hour+8; //模块返回的是本初子午线的时间,我这里加8来转化为北京时间
		
		Processed->N_S=raw->N_S;
		Processed->E_W=raw->E_W;
		
		Processed->latitude_f=atof(raw->latitude_s);
		Processed->longitude_f=atof(raw->longitude_s);
		
		temp=(int)Processed->latitude_f;
		t=(double)(Processed->latitude_f-temp+temp%100);
		Processed->latitude_f=(double)(temp/100+t/60);
		
		temp=(int)Processed->longitude_f;
		t=(double)(Processed->longitude_f-temp+temp%100);
		Processed->longitude_f=(double)(temp/100+t/60);
		
	}
	
}

void Debug_show(struct Redata_String *raw,struct Redata_float *Processed)
{
	Serial_SendString(Rawdata);
	Serial_SendString(raw->latitude_s);
	Serial_SendByte(raw->N_S);
	Serial_SendString("\r\n");
	Serial_SendString(raw->longitude_s);
	Serial_SendByte(raw->E_W);
	Serial_SendString("\r\n");
	Serial_SendString(raw->UTC_s);
	Serial_SendString("\r\n");
	Serial_SendByte(Processed->UTC_hour);
	Serial_SendByte(' ');
	Serial_SendByte(Processed->UTC_min);
	Serial_SendByte(' ');
	Serial_SendByte(Processed->UTC_sec);
	Serial_SendString("\r\n");
}

最后放出main文件来进行一个简单的示例,用OLED展示经纬度和实时时间

#include "stm32f10x.h"                  // Device header
#include <Delay.h>
#include <OLED.h>
#include <Serial.h>
#include "gps.h"
#include "LED.h"



struct Redata_String GPS_raw;
struct Redata_float  GPS_data;

int main(void )
{
	Serial_Init();
	OLED_Init();
	LED_Init();
	GPS_Init(&GPS_data);
	OLED_Clear();
	
	while(1)
	{
		
		Delay_ms(900);
		LED_ON();
		Delay_ms(100);
		LED_OFF();
		GPSdata_process(&GPS_raw,&GPS_data);
		Debug_show(&GPS_raw,&GPS_data);
		OLED_ShowNum(1,1,GPS_data.UTC_hour,2);
		OLED_ShowNum(1,5,GPS_data.UTC_min,2);
		OLED_ShowNum(1,9,GPS_data.UTC_sec,2);
		OLED_ShowFNum(2,1,GPS_data.latitude_f);//新建了一个OLED可以显示浮点数的函数
		OLED_ShowChar(2,9,GPS_data.N_S);
		OLED_ShowFNum(3,1,GPS_data.longitude_f);
		OLED_ShowChar(3,9,GPS_data.E_W);
	}
}

因为是暑假在家最后的效果演示也找不到视频,身边也没有实物,只能先欠着了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值