1.项目硬件MCU采用AT89C52、GPS采用的是NE0-6M的GPS模块、显示模块采用LCD1602
2.项目软件代码
1.main.c
#include <intrins.h>
#include <stdio.h>
#include "delay.h"
#include "1602.h"// 定义串口引脚
sbit NEO_TX = P3^0; // NEO-6M 模块的 TX 引脚连接到 P1.0 引脚
sbit NEO_RX = P3^1; // NEO-6M 模块的 RX 引脚连接到 P1.1 引脚/**The UART1 stage1**/
#define STAGE_SOHE 0x01
#define STAGE_TYPE 0x02
#define STAGE_NONE 0x03
#define STAGE_DATA 0x04
#define BAUDRATE 9600 // 设置波特率为 9600bpsunsigned char Lin0_No[16]="N:000.000000 ";//显示北纬
unsigned char Lin1_Ea[16]="E:000.000000 ";//显示东经
unsigned char speed[8]="S:0.000";
unsigned long xdata time_20ms=0;unsigned char xdata devide_flag; //GPS数据逗号分隔符
unsigned char xdata speed_end; //收速度数据结束标志
unsigned char xdata dir_end; //收方向角数据结束标志
unsigned char xdata sysmode_GPS=0; //gps有效无效标志
unsigned char xdata ew_flag; //东西标志
unsigned char xdata ns_flag; //南北标志unsigned char xdata gps_infor_weijing[17]; //暂存经纬度 格式是以度分秒的是形式
unsigned char xdata gps_infor_speed[4]; //暂存速率
unsigned char xdata gps_infor_time[6]; //时间暂存
unsigned char xdata gps_infor_date[6]; //日期暂存
unsigned char xdata gps_infor_dir[3]; //方向暂存unsigned char xdata recv1_step=STAGE_SOHE; //串口1接收指令步骤
unsigned char xdata uart1_r_buf; //串口的缓存
unsigned char xdata rev1_buf_busy; //串口接收忙碌标志
unsigned char xdata temp1_buf[85]; //串口接收数组
unsigned int xdata record1=0;
unsigned char times = 0; //延时计数
void Init_Timer0(void);//定时器初始化
void UART_Init(void);void main (void)
{
unsigned char num=0;
unsigned long Mid_Du; //中间变量 暂存经纬度的整数部分 即度
unsigned long Mid_Fen; //中间变量 暂存经纬度的小数部分 即分 gps原始数据是度分秒格式
unsigned long Mid_Vale; 中间变量 暂存经纬度 并将其扩大了10000000倍
unsigned char i ;Init_Timer0(); //定时器0初始化
UART_Init();
lcd_init(); //初始化液晶
nms_delay(100); //延时有助于稳定while(1) //主循环
{
if(sysmode_GPS==1) //检测gps是否有效数据
{
sysmode_GPS=0; //清除有效位
times = 0; //防止gps数据未更新就误判断数据无效
Mid_Du=(gps_infor_speed[0]-0x30)*1000; //处理经度 暂存整数部分扩大10000000
Mid_Fen=(gps_infor_speed[1]-0x30)*100+(gps_infor_speed[2]-0x30)*10+(gps_infor_speed[3]-0x30);Mid_Vale=Mid_Du+Mid_Fen;
speed[0]='S';
speed[1]=':';
speed[2]=Mid_Vale/1000+0x30;; //将处理后的纬度填入字符串 并打印显示
speed[3]='.';
speed[4]=(Mid_Vale/100)%10+0x30;
speed[5]=(Mid_Vale/10)%10+0x30;
speed[6]=(Mid_Vale)%10+0x30;
}
else
{
times++;
if(times>4) //防止gps数据未更新就误判断数据无效
{
times = 0; //清零计数
Lin1_Ea[0]='G'; //无gps信号情况下 打印正在连接
Lin1_Ea[1]='P';
Lin1_Ea[2]='S';
Lin1_Ea[3]=' '; //将处理后的纬度填入字符串 并打印显示
Lin1_Ea[4]='L';
Lin1_Ea[5]='I';
Lin1_Ea[6]='N';
Lin1_Ea[7]='K';
Lin1_Ea[8]='I';
Lin1_Ea[9]='N';
Lin1_Ea[10]='G';
Lin1_Ea[11]='.';
for(i=0;i<12;i++) //数组重新填充
{
Lin0_No[i]=Lin1_Ea[i];
}
}}
LCD_write_string(0,0,speed);//显示第一行
// LCD_write_string(0,1,Lin1_Ea);//显示第二行
nms_delay(1000); //延时有助于稳定
}}
void Init_Timer0(void)
{
TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH0=(65536-20000)/256; //重新赋值 20ms
TL0=(65536-20000)%256;
EA=1; //总中断打开
ET0=1; //定时器中断打开
TR0=1; //定时器开关打开
}void Timer0_isr(void) interrupt 1
{
TH0=(65536-20000)/256; //重新赋值 20ms
TL0=(65536-20000)%256;time_20ms++;
}// 初始化串口
void UART_Init(void) {
TMOD |= 0x20; // 设置为模式 1,8 位自动重装载定时器
TH1 = 256 - (11059200UL / 12 / 32 / BAUDRATE); // 设置波特率
TL1 = TH1; // 初始值与 TH1 相同
TR1 = 1; // 启动定时器 1
SCON = 0x50; // 8 位数据,可变波特率
EA = 1; // 允许全局中断
ES = 1; // 允许串口中断
}void UART_SER (void) interrupt 4 //串行中断服务程序
{
if(RI) //判断是接收中断产生
{
RI=0; //标志位清零
uart1_r_buf=SBUF; //提取buf中的值
rev1_buf_busy=0x00; //判别 放置break问题
switch(recv1_step)
{
case STAGE_SOHE: if(uart1_r_buf == '$') //判断接收到了$ 具体原因参考GPS标准协议NMEA0183
{
rev1_buf_busy=0x01;
if(uart1_r_buf == '$') //再次查看接收的是否是$
{
recv1_step=STAGE_TYPE; //跳转到下一步
record1=0; //计数清零
}
else
{
recv1_step=STAGE_SOHE; //恢复初始化
record1=0;
}
}
break;
case STAGE_TYPE: if(rev1_buf_busy == 0x00)
{rev1_buf_busy=0x01;
temp1_buf[record1]=uart1_r_buf;
record1++;
if(record1 == 0x05)
{ //查看$GPRMC开头的命令行
if((temp1_buf[0] == 'G') && (temp1_buf[1] == 'P') && (temp1_buf[2] == 'V') && (temp1_buf[3] == 'T') && (temp1_buf[4] == 'G'))
{
recv1_step=STAGE_NONE; //跳转到下一步
record1=0;
}
else
{
recv1_step=STAGE_SOHE;//恢复初始化
record1=0;
}
}
}
break;
case STAGE_NONE: if(rev1_buf_busy == 0x00)//接收命令格式:$GPRMC,054347.00,A,3202.04770,N,11846.23632,E,0.000,0.00,221013,,,A*67
{
rev1_buf_busy=0x01;
record1++;record1=0;
devide_flag=2;
speed_end=0x00;
dir_end=0x00;
if(uart1_r_buf == 'T') //gps收到数据 且有效
{
recv1_step=STAGE_DATA; //跳转到下一步
}
// else
// {
// sysmode_GPS=0;
// recv1_step=STAGE_SOHE; //无效恢复初始化
// record1=0;
// }
}
break;
case STAGE_DATA: if(rev1_buf_busy == 0x00)
{
rev1_buf_busy=0x01;
record1++;
if(uart1_r_buf == ',') //判断逗号
{
devide_flag++; //逗号次数记录
record1=0;
}
if(devide_flag == 7)
{
if(speed_end == 0x00)
{
if((record1 > 0) && (uart1_r_buf != '.'))
{
gps_infor_speed[record1-1]=uart1_r_buf; //接收速率
}
else if(uart1_r_buf == '.')
{
record1--;
speed_end=0xff;
}
}
else if(speed_end == 0xff)
{
if((record1 > 1) && (record1 < 5))
gps_infor_speed[record1-1]=uart1_r_buf;}
}if(uart1_r_buf == 0x0d)
{
recv1_step=STAGE_SOHE; //接收完成 并信号确定
record1=0; //恢复初始化状态 为下一次准备
devide_flag=0;
sysmode_GPS=1; //置位 GPS 信号为正确
}
}
break;
}
}
if(TI) //如果是发送标志位,清零
TI=0;
}
delay.c
#include<delay.h>
/****************************************************
函数名称:nus_delay
功能描述:微秒级延时子程序
*****************************************************/
void nus_delay(uint nus)
{while(nus--)
{}
}
/****************************************************
函数名称:nms_delay
功能描述:毫秒级延时子程序
*****************************************************/
void nms_delay(uint nms)
{
while(nms--)
nus_delay(100);
}
1602.c
#include "1602.h"
#include "delay.h"
/****************************************************
函数名称:lcd_init
功能描述:LCD初始化说明:注意初始化过程并加上适当延时
后面LCD的显示方式可按实际需要修改
*****************************************************/
void lcd_init(void)
{
nms_delay(15);
LCD_write_onechar(0x38,0);
nms_delay(1);
LCD_write_onechar(0x38,0);
nms_delay(1);
LCD_write_onechar(0x38,0);
nms_delay(1);
LCD_write_onechar(0x38,0);
LCD_write_onechar(0x08,0); /*显示关闭*/
LCD_write_onechar(0x01,0); /*显示清屏*/
LCD_write_onechar(0x80,0); /*显示清屏*/
LCD_write_onechar(0x06,0); /*显示光标移动设置*/
nms_delay(1);;
LCD_write_onechar(0x0C,0); /*显示开及光标设置*/
}
/*函数名称:LCD_en_write
功能描述:EN端产生一个脉冲,写LCD*****************************************************/
void LCD_en_write(void)
{
LCD_EN=1;
nus_delay(150); //E脉冲周期最小150ns
LCD_EN=0;
}
/****************************************************
函数名称:wait_LCD_Ready
功能描述:判断LCD忙标志*****************************************************/
void wait_LCD_Ready(void)
{
// uchar temp1;
LCD_DATA=0XFF;
//判断LCD忙标志
//1为忙 0为空闲
LCD_RS=0;
LCD_RW=1; //读
LCD_EN=1;
nus_delay(2);
/* do
{
temp1=LCD_DATA;
temp1&=0x80;
}while(temp1); */
LCD_EN=0;
LCD_RS=1;
}/****************************************************
函数名称:LCD_write_onechar
功能描述:写一个字节到LCD
输 入: COMM(指令) DAT(显示数据)*****************************************************/
void LCD_write_onechar(uchar COMM,uchar DAT)
{
wait_LCD_Ready(); //等待LCD空闲
LCD_RW=0; //写
//写数据
if(COMM==0)
{
LCD_RS=1; //RS高电平向LCD写数据
LCD_DATA=DAT;
}
//写命令
else
{
LCD_RS=0;
LCD_DATA=COMM;
}
LCD_en_write();
nus_delay(2);
LCD_RW=1;
LCD_RS=1;
}/****************************************************
函数名称:LCD_write_string
功能描述:LCD字符串显示函数
输 入: x/y(X与Y坐标) *string(字符串首地址)*****************************************************/
void LCD_write_string(uchar X,uchar Y,uchar *string)
{
set_LCD_xy( X, Y ); //设置LCD显示坐标
while (*string)
{
LCD_write_onechar(0,*string );
string ++; //指向下一显示字符地址
}
}/****************************************************
函数名称:set_LCD_xy
功能描述:设置显示坐标
输 入: x/y(X与Y坐标)
输 出: 无说明: LMB1602第一行首地址为0x80
第二行为0xC0*****************************************************/
void set_LCD_xy(uchar x, uchar y )
{
uchar DIS_address;
if (y == 0)
DIS_address = 0x80 + x; //第一行X列
else
DIS_address = 0xc0 + x;
LCD_write_onechar( DIS_address, 0 ); //第二行X列
}
delay.h
#ifndef __DELAY_H_
#define __DELAY_H_//包含头文件
/**********************************///---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif#ifndef uint
#define uint unsigned int
#endif
/**********************************/void nus_delay(uint nus);
void nms_delay(uint nms);
#endif
1602.h
#ifndef __LCD_H_
#define __LCD_H_
/**********************************
当使用的是4位数据传输的时候定义,
使用8位取消这个定义
**********************************/
//#define LCD1602_4PINS/**********************************
包含头文件
**********************************/
#include <REGX52.H>
#//---重定义关键词---//
#define uchar unsigned char
#define uint unsigned int
#define LCD_DATA P0 //定义LCD的D0-D7所在端口
#define LCD_EN P2_7
#define LCD_RW P2_5 //LCD读写控制引脚
#define LCD_RS P2_6 //LCD指令或数据选择引脚
/**********************************/
//函数声明
void lcd_init(void);
void LCD_en_write(void);
void wait_LCD_Ready(void);
void set_LCD_xy(uchar x, uchar y );
void LCD_write_onechar(uchar COMM,uchar DAT);
void LCD_write_string(uchar X,uchar Y,uchar *string);#endif
以下是项目压缩包链接
链接:https://pan.baidu.com/s/12bTkK376gDewHu3UXWY8Uw?pwd=ntqs
提取码:ntqs
--来自百度网盘超级会员V4的分享