文章目录

  • 一、简介
  • 二、硬件准备
  • 1、元器件清单
  • 2、接线说明
  • 三、软件准备



一、简介

  接上一篇树莓派与GPS模块的那些事儿,本篇是将NEO-6M GPS模块用于STC12C5A60S2,通过单片机来获取解析GPS数据,并将其显示在LCD1602上,程序来源于购买模块送的资料包,采用了8位总线的方式。

esp12f接线图_NEO-6M GPS

二、硬件准备

1、元器件清单

名称

数量

STC12C5A60S2

1

51最小系统板

1

LCD1602

1

11.0591M晶振

1

B10K电位器

1

NEO-6M GPS

1

USB转TTL

1

面包板

1

6x6x5 按键开关

1

  当然其实这个清单有多余的部分,其实完全可以不用最小系统板,直接插在面包板上即可,我这里是为了自己方便,但结果是整个接线看起来都乱糟糟的。

STC12C5A60S2:

esp12f接线图_NEO-6M GPS_02


51最小系统板原理图:

esp12f接线图_STC12C5A60S2_03

2、接线说明

esp12f接线图_NEO-6M GPS_04

STC12C5A60S2

LCD1602

NEO-6M GPS

GND

VSS

GND

VCC

VDD

VCC

*

V0

*

P2.7

RS

*

P2.6

RW

*

P2.5

E

*

P0.0

D0

*

P0.1

D1

*

P0.2

D2

*

P0.3

D3

*

P0.4

D4

*

P0.5

D5

*

P0.6

D6

*

P0.7

D7

*

VCC

A

*

GND

K

*

P3.0

*

TXD

P3.1

*

RXD

B10K电位器

LCD1602

1

GND

2

A0

按键开关

STC12C5A60S2

1

GND

2

P3.7

三、软件准备

#include "main.h"
#include "LCD1602.h"
#include "GPS.h"

//定义变量
unsigned char KEY_NUM = 0;
bit Page = 0;
unsigned char xdata Display_GPGGA_Buffer[68];
unsigned char xdata Display_GPRMC_Buffer[68];
bit Flag_OV = 0;
bit Flag_Calc_GPGGA_OK = 0;
bit Flag_Calc_GPRMC_OK = 0;

//****************************************************
//主函数
//****************************************************
void main()
{
	unsigned char i = 0;
	Init_LCD1602();
	LCD1602_write_com(0x80);						//指针设置
	LCD1602_write_word("Welcome to use!");  // 液晶显示屏初始化显示

	Delay_ms(1000);


	Uart_Init();

	while(1)
	{
		Scan_Key();
		if(Flag_GPS_OK == 1 && RX_Buffer[4] == 'G' && RX_Buffer[6] == ',' && RX_Buffer[13] == '.')			//确定是否收到"GPGGA"这一帧数据
		{
			for( i = 0; i < 68 ; i++)
			{
				Display_GPGGA_Buffer[i] = RX_Buffer[i];	
			}
			Hour = (Display_GPGGA_Buffer[7]-0x30)*10+(Display_GPGGA_Buffer[8]-0x30)+8;			//UTC时间转换到北京时间		UTC+8
																								//0x30为ASCII转换为数字
			if( Hour >= 24)				//溢出
			{
				Hour %= 24;				//获取当前Hour
				Flag_OV = 1;			//日期进位
			}
			else
			{
				Flag_OV = 0;
			}

			Min_High = Display_GPGGA_Buffer[9];
			Min_Low = Display_GPGGA_Buffer[10];
	
			Sec_High = Display_GPGGA_Buffer[11];
			Sec_Low = Display_GPGGA_Buffer[12];

			Flag_Calc_GPGGA_OK = 1;
		}

		if(Page == 0 && Flag_Calc_GPGGA_OK == 1)
		{
			LED1 = ~LED1;
			Flag_Calc_GPGGA_OK = 0;
			LCD1602_write_com(0x80);			//设置指针
			LCD1602_write_data(Hour/10+0x30);
			LCD1602_write_data(Hour%10+0x30);

			LCD1602_write_data(':');

			LCD1602_write_data(Min_High);
			LCD1602_write_data(Min_Low);

			LCD1602_write_data(':');
	
			LCD1602_write_data(Sec_High);
			LCD1602_write_data(Sec_Low);

			LCD1602_write_word("  ");
			
			LCD1602_write_data(Display_GPGGA_Buffer[54]);	
			LCD1602_write_data(Display_GPGGA_Buffer[55]);	
			LCD1602_write_data(Display_GPGGA_Buffer[56]);	
			LCD1602_write_data(Display_GPGGA_Buffer[57]);
			LCD1602_write_word("m");
	
			LCD1602_write_com(0x80+0x40);			//设置指针
			
			LCD1602_write_data(Display_GPGGA_Buffer[28]);			//N 或者 S

			LCD1602_write_data(Display_GPGGA_Buffer[17]);			//纬度
			LCD1602_write_data(Display_GPGGA_Buffer[18]);			//纬度
			LCD1602_write_data(0xdf);								//度
			LCD1602_write_data(Display_GPGGA_Buffer[19]);			//纬度
			LCD1602_write_data(Display_GPGGA_Buffer[20]);			//纬度
			LCD1602_write_word("'");								//秒
			
			LCD1602_write_data(Display_GPGGA_Buffer[42]);			//E 或者 W

			LCD1602_write_data(Display_GPGGA_Buffer[30]);			//经度
			LCD1602_write_data(Display_GPGGA_Buffer[31]);	
			LCD1602_write_data(Display_GPGGA_Buffer[32]);	
			LCD1602_write_data(0xdf);								
			LCD1602_write_data(Display_GPGGA_Buffer[33]);			
			LCD1602_write_data(Display_GPGGA_Buffer[34]);		
			LCD1602_write_word("'");

						
		}
		
		if(Flag_GPS_OK == 1 && RX_Buffer[4] == 'M' && RX_Buffer[52] == ',' && RX_Buffer[59] == ',')			//确定是否收到"GPRMC"这一帧数据
		{
			for( i = 0; i < 68 ; i++)
			{
				Display_GPRMC_Buffer[i] = RX_Buffer[i];	
			}

			Year_High = Display_GPRMC_Buffer[57];
			Year_Low = Display_GPRMC_Buffer[58];

			Month_High = Display_GPRMC_Buffer[55];
			Month_Low = Display_GPRMC_Buffer[56];

			Day_High = Display_GPRMC_Buffer[53];
			Day_Low = Display_GPRMC_Buffer[54];


			if(Flag_OV == 1)			//有进位
			{
				UTCDate2LocalDate();			//UTC日期转换为北京时间		
			}

			Flag_Calc_GPRMC_OK = 1;
		}

		if(Page == 1 && Flag_Calc_GPRMC_OK == 1)
		{
			LED1 = ~LED1;
			Flag_Calc_GPRMC_OK = 0;
			LCD1602_write_com(0x80);			//设置指针
			LCD1602_write_word("20");
			LCD1602_write_data(Year_High);
			LCD1602_write_data(Year_Low);
			LCD1602_write_data('-');
	
			LCD1602_write_data(Month_High);
			LCD1602_write_data(Month_Low);
			LCD1602_write_data('-');
	
			LCD1602_write_data(Day_High);
			LCD1602_write_data(Day_Low);
			
			
			LCD1602_write_com(0x80+0x40);			//设置指针
			LCD1602_write_word("Speed:");				//显示内容

			LCD1602_write_data(Display_GPRMC_Buffer[46]);		
			LCD1602_write_data(Display_GPRMC_Buffer[47]);		
			LCD1602_write_data(Display_GPRMC_Buffer[48]);			
			LCD1602_write_data(Display_GPRMC_Buffer[49]);	
			LCD1602_write_data(Display_GPRMC_Buffer[50]);
			
			LCD1602_write_word("m/s");				
		}		
	}
}
//****************************************************
//UTC日期与当地日期转换
//****************************************************
void UTCDate2LocalDate(void)
{
	Day = (Day_High - 0x30) * 10 + (Day_Low-0x30) + 1;		//日  加一
	Month = (Month_High - 0x30) * 10 + (Month_Low - 0x30);
	Year = 2000 + (Year_High - 0x30) * 10 + (Year_Low - 0x30);
	
	MaxDay = GetMaxDay(Month,Year);				//获取当月 天数 最大值
	if(Day > MaxDay)		//溢出
	{
		Day = 1;
		Month += 1;
		if(Month > 12)
		{
			Year+=1;
		}
	}

	Day_High = Day/10 + 0x30;				//转换日期值为ASCII
	Day_Low = Day%10 + 0x30;

	Month_High = Month/10 + 0x30;			//转换月份值为ASCII
	Month_Low = Month%10 + 0x30;

	Year_High = Year%100/10 + 0x30;			//转换年份值为ASCII
	Year_Low = Year%10 + 0x30;			
}

//****************************************************
//获取当月日期最大值
//****************************************************
unsigned char GetMaxDay(unsigned char Month_Value,unsigned int Year_Value)
{
	unsigned char iDays;
	switch(Month_Value)
	{
		case 1:
		case 3:
		case 5:
		case 7:
		case 8:
		case 10:
		case 12:
			{
				iDays = 31;
			}
			break;
		case 2:
			{
				//2月份比较特殊,需要根据是不是闰年来判断当月是28天还29天
				iDays = IsLeapYear(Year_Value)?29:28;
			}
			break;
		case 4:
		case 6:
		case 9:
		case 11:
			{
				iDays = 30;
			}
			break;
		default : break;
	}
	return(iDays);						
}

//****************************************************
//闰年检测
//****************************************************
bit IsLeapYear(unsigned int uiYear)
{
	return (((uiYear%4)==0)&&((uiYear%100)!=0))||((uiYear%400)==0);
}


//****************************************************
//按键扫描程序
//****************************************************
void Scan_Key()
{
	if( KEY4 == 0 )	 					//按键1扫描
	{
		Delay_ms(10);					//延时去抖
		if( KEY4 == 0 )
		{
			while(KEY4 == 0);			//等待松手
			KEY_NUM = 3;
			Page = ~Page;
			LCD1602_write_com(0X01);	//清屏
		}
	}
}
//****************************************************
//MS延时函数(12M晶振下测试)
//****************************************************
void Delay_ms(unsigned int n)
{
	unsigned int  i,j;
	for(i=0;i<n;i++)
		for(j=0;j<123;j++);
}

  实验结果为:一开始上电,LCD1602显示Welcome to use!,待到GPS模块成功获取定位信息,LCD1602显示时间、海拔以及经纬度,点击按钮,切换至第二页,显示日期和地面速率。

esp12f接线图_STC12C5A60S2_05

esp12f接线图_STC12C5A60S2_06