📄 gps_display_release.c
字号:
/*
; 使用AVR单片机解析出GPSRM数据段的信息,提取时间、经纬度、指示出南北半球及东西经、日期、以及当前数据是否有效的标识位,
; 并将这些信息显示在1602液晶屏上。
;
; 网站: http://www.ruixuedz.cn
;email: unaided@tom.com
; 作者: 老蒋
*/
#include <AVR_PQ1A.h> //包含自定义常量头文件
#include <avr/interrupt.h>
uchar buf[500]; //串口接受数据缓冲区
uint readCount=0; //串口解析数据计数
uint writeCount=0; //串口接受数据计数
uchar Time[6]; //gps时间
uchar Date[6]; //gps日期
uchar Status; //gps有效性
uchar Latitude[9]; //gps纬度
uchar NSIndicator; //gps南北半球标识位
uchar Longitude[10];//gps经度
uchar EWIndicator; //gps东西经标识位
uchar Speed[4]; //gps速度
/*******************************************
函数名称: Uart_init
功 能: 异步串口初始化
参 数: baud--设置的波特率
返回值 : 无
********************************************/
void Uart_init(uint baud)
{
baud=MCLK/16/baud-1; //波特率最大为65K
UCSRB=0x00;
UCSRA=0x00; //控制寄存器清零
UCSRC=(1<<URSEL)|(0<<UPM0)|(3<<UCSZ0); //选择UCSRC,异步模式,禁止校验,1位停止位,8位数据位
UBRRL=baud;
UBRRH=baud>>8; //设置波特率
UCSRB=(1<<TXEN)|(1<<RXEN)|(1<<RXCIE); //接收、发送使能,接收中断使能
sei(); //全局中断开放
DDRD|=0X02; //配置TX为输出(很重要)
}
/*******************************************
函数名称: Uart_sendB
功 能: 异步串口发送一个字节
参 数: sendB--发送的字节数据
返回值 : 无
********************************************/
void Uart_sendB(uchar sendB)
{
while(!(UCSRA&(1<<UDRE))); //等待发送缓冲区为空
UDR=sendB; //发送数据
while(!(UCSRA&(1<<TXC))); //等待发送完毕
UCSRA|=1<<TXC; //清除发送完毕状态位
}
/*******************************************
函数名称: Uart_sentstr
功 能: 异步串口发送一个字符串
参 数: sendpt--发送的数组指针
返回值 : 无
********************************************/
void Uart_sentstr(uchar *sendpt)
{
while(*sendpt) //字符串未结束则继续发送
{
Uart_sendB(*sendpt++);
}
}
/*******************************************
函数名称: Uart_RX
功 能: 异步串口接收
参 数: 无
返回值 : 无
********************************************/
ISR(USART_RXC_vect)
{
UCSRB&=~BIT(RXCIE); //关闭接收中断
buf[writeCount]=UDR; //将接收到的数据存入全局数组
++writeCount;
if(writeCount > 499)
writeCount = 0;
UCSRB|=BIT(RXCIE); //使能接收中断
}
/*******************************************
函数名称: Read_byte
功 能: 从接受缓冲区中读取一个字节
参 数: 无
返回值 : temp--读取到的数据
********************************************/
uchar Read_byte(void)
{
uchar temp;
while(readCount == writeCount)
{
Delayms(10);
}
temp = buf[readCount];
++readCount;
if(readCount > 499)
readCount = 0;
return temp;
}
/*******************************************
函数名称: LCD1602_portini
功 能: 初始化1602液晶用到的IO口
参 数: 无
返回值 : 无
********************************************/
void LCD1602_portini(void)
{
LCDa_CTRL_DDR |= BIT(LCDa_RS)|BIT(LCDa_RW)|BIT(LCDa_E);//配置控制管脚为输出
LCDa_DATA_DDR |= 0xFF;//配置数据管脚为输出
}
/*******************************************
函数名称: LCD1602_readbyte
功 能: 从1602液晶读出一个字节数据或者指令
参 数: DatCmd--为iDat时是数据,为iCmd时是指令
返回值 : dByte--读回的数据或者指令
********************************************/
uchar LCD1602_readbyte(uchar DatCmd)
{
uchar dByte;
if (DatCmd == iCmd) //指令操作
LCDa_CLR_RS;
else
LCDa_SET_RS;
LCDa_SET_RW; //读操作
LCDa_SET_E;
LCDa_DATA_DDR=0x00; //数据总线定义为输入
dByte=LCDa_DI; //读数据或者指令
Delayms(1); //时序调整
LCDa_CLR_E;
LCDa_DATA_DDR|=0xff; //数据总线还原为输出
return dByte;
}
/*******************************************
函数名称: LCD1602_sendbyte
功 能: 向1602液晶写入一个字节数据或者指令
参 数: DatCmd--为iDat时是数据,为iCmd时是指令
dByte--为写入1602的数据或者指令
返回值 : 无
********************************************/
void LCD1602_sendbyte(uchar DatCmd, uchar dByte)
{
if (DatCmd == iCmd) //指令操作
LCDa_CLR_RS;
else
LCDa_SET_RS; //数据操作
LCDa_CLR_RW; //写操作操作
LCDa_SET_E;
LCDa_DO = dByte; //写入数据
Delayms(1);
LCDa_CLR_E;
}
/*******************************************
函数名称: LCD1602_sendstr
功 能: 向1602液晶写入一个字符串
参 数: ptString--字符串指针
返回值 : 无
********************************************/
void LCD1602_sendstr(uchar *ptString)
{
while((*ptString)!='\0') //字符串未结束就一直写
{
LCD1602_sendbyte(iDat, *ptString++);
}
}
/*******************************************
函数名称: LCD1602_clear
功 能: 1602液晶清屏
参 数: 无
返回值 : 无
********************************************/
void LCD1602_clear(void)
{
LCD1602_sendbyte(iCmd,LCDa_CLS);//写入清屏指令
Delayms(40);// 清屏指令写入后,2ms 的延时是很必要的!!!
}
/*******************************************
函数名称: LCD1602_readBF
功 能: 1602液晶清屏
参 数: 无
返回值 : busy--为1时是忙状态,为0时可以接收指令
********************************************/
uchar LCD1602_readBF(void)
{
uchar busy;
busy=LCD1602_readbyte(iCmd); //读回BF标志(忙标志)和地址
if(busy&0x80) //如果忙返回正在忙的状态
busy=1;
else //如果不忙,可以写入
busy=0;
return busy;
}
/*******************************************
函数名称: LCD1602_gotoXY
功 能: 移动到指定位置
参 数: Row--指定的行
Col--指定的列
返回值 : 无
********************************************/
void LCD1602_gotoXY(uchar Row, uchar Col)
{
switch (Row) //选择行
{
case 1:
LCD1602_sendbyte(iCmd, LCDa_L1 + Col); break; //写入第1行的指定列
case 2:
LCD1602_sendbyte(iCmd, LCDa_L2 + Col); break; //写入第2行的指定列
default:
break;
}
}
/*******************************************
函数名称: LCD1602_initial
功 能: 1602液晶初始化
参 数: 无
返回值 : 无
********************************************/
void LCD1602_initial(void)
{
Delayms(100); //上电后等待内部复位
LCD1602_portini(); //端口初始化
LCD1602_sendbyte(iCmd, LCDa_FUNCTION); //功能、模式设定,具体的设定功能可以看C:\icc\include\AVR_PQ1A.H里面的常量定义
while(LCD1602_readBF()); //等待不忙为止
LCD1602_sendbyte(iCmd, LCDa_ON); //打开显示
while(LCD1602_readBF()); //等待不忙为止
LCD1602_clear(); //清屏
while(LCD1602_readBF()); //等待不忙为止
LCD1602_sendbyte(iCmd, LCDa_ENTRY); //输入模式设定
}
/*******************************************
函数名称: clear_gprmc
功 能: 清空gprmc显示缓冲区
参 数: 无
返回值 : 无
********************************************/
void clear_gprmc(void)
{
uchar i;
for(i=0; i<6; i++)
{
Time[i] = '0';
Date[i] = '0';
}
for(i=0; i<9; i++)
{
Latitude[i] = '0';
}
for(i=0; i<10; i++)
{
Longitude[i] = '0';
}
for(i=0; i<4; i++)
{
Speed[i] = '0';
}
Status = '0';
NSIndicator = '0';
EWIndicator = '0';
}
/*******************************************
函数名称: Parse_gprmc
功 能: 解析GPRMC字段
参 数: 无
返回值 : 无
********************************************/
void Parse_gprmc(void)
{
uchar i;
uchar temp;
clear_gprmc();
Read_byte();
temp = Read_byte();
if(',' != temp)
{
Time[0] = temp;
for(i=0; i<5; i++)
{
Time[i+1] = Read_byte();
}
Read_byte();
Read_byte();
Read_byte();
Read_byte();
}
Status = Read_byte();
Read_byte();
temp = Read_byte();
if(',' != temp)
{
Latitude[0] = temp;
for(i=0; i<3; i++)
{
Latitude[i+1] = Read_byte();
}
Read_byte();
for(i=0; i<5; i++)
{
Latitude[4+i] = Read_byte();
}
Read_byte();
}
temp = Read_byte();
if(',' != temp)
{
NSIndicator = temp;
Read_byte();
}
temp = Read_byte();
if(',' != temp)
{
Longitude[0] = temp;
for(i=0; i<4; i++)
{
Longitude[i+1] = Read_byte();
}
Read_byte();
for(i=0; i<5; i++)
{
Longitude[5+i] = Read_byte();
}
Read_byte();
}
temp = Read_byte();
if(',' != temp)
{
EWIndicator = temp;
Read_byte();
}
temp = Read_byte();
if(',' != temp)
{
Speed[0] = temp;
Read_byte();
for(i=0; i<3; i++)
{
Speed[1+i] = Read_byte();
}
Read_byte();
}
Read_byte();
temp = Read_byte();
if(',' != temp)
{
Date[0] = temp;
for(i=0; i<5; i++)
{
Date[i+1] = Read_byte();
}
}
}
/*******************************************
函数名称: Display_gprmc
功 能: 显示GPRMC字段信息
参 数: 无
返回值 : 无
********************************************/
void Display_gprmc(void)
{
uchar high,low,i;
high = Time[0];
low = Time[1];
low = low+8;
if(low > 57)
{
low = low - 10;
high = high + 1;
}
LCD1602_clear();
while(LCD1602_readBF());
LCD1602_gotoXY(1,0);
LCD1602_sendbyte(iDat,high);
LCD1602_sendbyte(iDat,low);
LCD1602_sendbyte(iDat,':');
LCD1602_sendbyte(iDat,Time[2]);
LCD1602_sendbyte(iDat,Time[3]);
LCD1602_sendbyte(iDat,':');
LCD1602_sendbyte(iDat,Time[4]);
LCD1602_sendbyte(iDat,Time[5]);
LCD1602_sendbyte(iDat,' ');
LCD1602_sendbyte(iDat,Status);
while(LCD1602_readBF());
LCD1602_gotoXY(2,0);
LCD1602_sendbyte(iDat,Date[4]);
LCD1602_sendbyte(iDat,Date[5]);
LCD1602_sendbyte(iDat,'.');
LCD1602_sendbyte(iDat,Date[2]);
LCD1602_sendbyte(iDat,Date[3]);
LCD1602_sendbyte(iDat,'.');
LCD1602_sendbyte(iDat,Date[0]);
LCD1602_sendbyte(iDat,Date[1]);
Delayms(50000);
LCD1602_clear();
while(LCD1602_readBF());
LCD1602_gotoXY(1,0);
LCD1602_sendbyte(iDat,Latitude[0]);
LCD1602_sendbyte(iDat,Latitude[1]);
LCD1602_sendbyte(iDat,'.');
for(i=0; i<7; i++)
{
LCD1602_sendbyte(iDat,Latitude[2+i]);
}
LCD1602_sendbyte(iDat,' ');
LCD1602_sendbyte(iDat,NSIndicator);
while(LCD1602_readBF());
LCD1602_gotoXY(2,0);
LCD1602_sendbyte(iDat,Longitude[0]);
LCD1602_sendbyte(iDat,Longitude[1]);
LCD1602_sendbyte(iDat,Longitude[2]);
LCD1602_sendbyte(iDat,'.');
for(i=0; i<7; i++)
{
LCD1602_sendbyte(iDat,Longitude[3+i]);
}
LCD1602_sendbyte(iDat,' ');
LCD1602_sendbyte(iDat,EWIndicator);
Delayms(50000);
}
/*******************************************
函数名称: Read_gprmc
功 能: 读取GPRMC字段
参 数: 无
返回值 : 无
********************************************/
void Read_gprmc(void)
{
uchar temp = 0;
temp = Read_byte();
if(temp == '$')
{
Read_byte();
Read_byte();
temp = Read_byte();
if(temp == 'R')
{
temp = Read_byte();
if(temp == 'M')
{
temp = Read_byte();
if(temp == 'C')
{
Parse_gprmc();
Display_gprmc();
}
}
}
}
}
/*******************************************
函数名称: main
功 能:
参 数: 无
返回值 : 无
********************************************/
int main(void)
{
Board_init( ); //初始化开发板
Uart_init(9600); //初始化串口,设置波特率
LCD1602_initial();
while(LCD1602_readBF());
LCD1602_gotoXY(1,0);
LCD1602_sendstr("AVR_PQ1A BOARD");
while(1)
{
Read_gprmc();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -