文章目录
- 一、简介
- 二、硬件准备
- 1、元器件清单
- 2、接线说明
- 三、软件准备
一、简介
接上一篇树莓派与GPS模块的那些事儿,本篇是将NEO-6M GPS
模块用于STC12C5A60S2
,通过单片机来获取解析GPS
数据,并将其显示在LCD1602
上,程序来源于购买模块送的资料包,采用了8位总线的方式。
二、硬件准备
1、元器件清单
名称 | 数量 |
STC12C5A60S2 | 1 |
51最小系统板 | 1 |
LCD1602 | 1 |
11.0591M晶振 | 1 |
B10K电位器 | 1 |
NEO-6M GPS | 1 |
USB转TTL | 1 |
面包板 | 1 |
6x6x5 按键开关 | 1 |
当然其实这个清单有多余的部分,其实完全可以不用最小系统板,直接插在面包板上即可,我这里是为了自己方便,但结果是整个接线看起来都乱糟糟的。
STC12C5A60S2:
51最小系统板原理图:
2、接线说明
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
显示时间、海拔以及经纬度,点击按钮,切换至第二页,显示日期和地面速率。