|
' 原来的gps制作帖太长太乱了,重新开个帖。 效果见图。接线图和烧片文件见rar。 需要注意的是:烧写芯片时,熔丝需要设置使用内部8mhz的rc振荡器。声明:由于使用了rc振荡器,所以可能会造成频率不稳定,从而无法正确对gps数据进行解码。我测试的情况是,可以非常稳定的工作。如果你的程序不能稳定工作,可以考虑外接8m晶体振荡器,并对熔丝进行相应设置。 我系统装了adobe 的dpf制作软件也不好使,所以直接上ddb文件了,protel99se格式的,好心人给转成pdf吧。 说明 1、本例子需要使用速率为9600bps的gps,并且需要有gpzda语句输出,gps需要使用nema0183协议输出。 2、本次例子删除了原所有版权显示信息,取消所以硬件设置、软件设置。本例子将只发布这一版代码,不再发布适合多种gps接口速率、多种速度单位、多种时间信息语句选择、多种mcu型号的版本。 3、如有需要,将公开除12864驱动部分以外的完整代码。 感谢bg6agb帮忙转换电路图为pdf文件。 源代码,使用winavr-20070122编译调试通过。 (由于论坛bug,源代码需要使用“引用回复”才可见——非开玩笑) - /*************************************
- gps解码程序
- 作者:bg4uvr
- 最后更新:
- 2007.03.30
- 1.5版
- 1、改为使用12864点阵屏显示
- ***************************************/
- //包含头文件
- #include <avr/io.h>
- #include <util/delay.h>
- #include <avr/pgmspace.h>
- #include <avr/interrupt.h>
- #include <avr/eeprom.h>
- #include "ks0108.h"
- #define time_area 8
- //gps数据存储数组
- unsigned char jd[10]={"00000.0000"}; //经度
- unsigned char jd_a='*' //经度方向
- unsigned char wd[9]={"0000.0000"}; //纬度
- unsigned char wd_a='*' //纬度方向
- unsigned char time[6]={"000000"}; //时间
- unsigned char date[6]={"000000"}; //日期
- unsigned char speed[5]; //速度
- unsigned char high[6]; //高度
- unsigned char angle[5]; //方位角
- unsigned char use_sat[2]={"00"}; //使用的卫星数
- unsigned char total_sat[2]={"00"}; //天空中总卫星数
- //串口中断需要的变量
- unsigned char seg_count; //逗号计数器
- unsigned char dot_count; //小数点计数器
- unsigned char byte_count; //位数计数器
- unsigned char cmd_number; //命令类型
- unsigned char mode; //0:结束模式,1:命令模式,2:数据模式
- volatile unsigned char buf_full; //1:整句接收完成,相应数据有效。0:缓存数据无效。
- unsigned char cmd[5]; //命令类型存储数组
- //显示需要的变量
- unsigned char dsp_count; //刷新次数计数器
- unsigned char time_count;
- volatile unsigned char high_num,a_num,s_num;
- void init_set(void);
- void sys_init(void);
- unsigned char week(unsigned char year, unsigned char mon, unsigned char day);
- int main(void)
- {
- unsigned char i;
- unsigned char bhour=0,bday=0,bmonth=0;
- unsigned int byear=0;
- sys_init();
- while(1){
- if(buf_full==0) //无gps信号时
- {
- dsp_count++;
- _delay_ms(10);
- if(dsp_count>=200){
- clean_screen(); //清屏
- str_58_disp(0,0,pstr("no gps connect.."),0);
- while(buf_full==0);
- clean_screen();
- dsp_count=0;
- }
- }
- else{ //有gps信号时
- if(buf_full|0x01){ //gga语句
- ascii_58_disp(0,0,jd_a,0); //显示经度
- for(i=0;i<3;i++){
- ascii_58_disp(0,(i+1)*6,jd[i],0);
- }
- ascii_58_disp(0,24,'.',0);
- for(i=3;i<10;i++){
- ascii_58_disp(0,(i+2)*6,jd[i],0);
- }
- ascii_58_disp(1,0,wd_a,0); //显示纬度
- for(i=0;i<2;i++){
- ascii_58_disp(1,(i+2)*6,wd[i],0);
- }
- ascii_58_disp(1,24,'.',0);
- for(i=2;i<9;i++){
- ascii_58_disp(1,(i+3)*6,wd[i],0);
- }
- ascii_58_disp(2,96,use_sat[0],0); //显示接收卫星数
- ascii_58_disp(2,102,use_sat[1],0);
- ascii_58_disp(2,108,'/',0);
- str_58_disp(2,0,pstr("hi:"),0);
- if(high_num<6) //高度显示
- {
- for(i=0;i<(6-high_num);i++)
- {
- ascii_58_disp(2,(3+i)*6,0x20,0);
- }
- }
- for(i=0;i<high_num;i++)
- {
- ascii_58_disp(2,(9-high_num+i)*6,high[i],0);
- }
- str_58_disp(2,54,pstr("m u/t:"),0);
- buf_full&=~0x01;
- dsp_count=0;
- }
- if(buf_full|0x02){ //gsv语句
- ascii_58_disp(2,114,total_sat[0],0);
- ascii_58_disp(2,120,total_sat[1],0);
- buf_full&=~0x02;
- dsp_count=0;
- }
- if(buf_full|0x04)
- {
- str_58_disp(0,78,pstr("ag:"),0);//方位角显示
- if(a_num<5)
- {
- for(i=0;i<(5-a_num);i++)
- {
- ascii_58_disp(0,(16+i)*6,0x20,0);
- }
- }
- for(i=0;i<a_num;i++)
- {
- ascii_58_disp(0,(21-a_num+i)*6,angle[i],0);
- }
- str_58_disp(1,78,pstr("sp:"),0); //速度显示
- if(s_num<5)
- {
- for(i=0;i<(5-s_num);i++)
- {
- ascii_58_disp(1,(16+i)*6,0x20,0);
- }
- }
- for(i=0;i<s_num;i++)
- {
- ascii_58_disp(1,(21-s_num+i)*6,speed[i],0);
- }
- buf_full&=~0x04;
- dsp_count=0;
- }
- if(buf_full|0x08){
- if(bhour!=((time[0]-0x30)*10+time[1]-0x30)+time_area){
- bhour=((time[0]-0x30)*10+time[1]-0x30)+time_area; //北京时间转换
- bday=(date[0]-0x30)*10+date[1]-0x30;
- bmonth=(date[2]-0x30)*10+date[3]-0x30;
- byear=(date[4]-0x30)*10+date[5]-0x30+2000;
- if(bhour>=24){ //如果小时数大于24
- bhour-=24; //小时数减24
- bday++; //日期数加1
- switch(bday){ //判断日期
- case 29: //普通年的2月份
- if((!((byear%400==0)||((byear%4==0)&&(byear%100!=0)))&&(bmonth==2))){
- bday=1;
- bmonth++;
- }
- break;
- case 30: //如果是闰年的2月
- if(((byear%400==0)||((byear%4==0)&&(byear%100!=0)))&&(bmonth==2)){
- bday=1;
- bmonth++;
- }
- break;
- case 31:
- if((bmonth==4)||(bmonth==6)||(bmonth==9)||(bmonth==11)){
- bday=1;
- bmonth++;
- }
- break;
- case 32:
- bday=1;
- bmonth++;
- if(bmonth>=13){
- byear++;
- bmonth=1;
- }
- break;
- }
- }
- }
- ascii_58_disp(3,0,ƈ',0);
- ascii_58_disp(3,6,Ɔ',0);
- ascii_58_disp(3,12,(byear%100)/10+0x30,0);
- ascii_58_disp(3,18,byear%10+0x30,0);
- ascii_58_disp(3,24,'/',0);
- ascii_58_disp(3,30,bmonth/10+0x30,0);
- ascii_58_disp(3,36,bmonth%10+0x30,0);
- ascii_58_disp(3,42,'/',0);
- ascii_58_disp(3,48,bday/10+0x30,0);
- ascii_58_disp(3,54,bday%10+0x30,0);
-
- switch(week(byear%100,bmonth,bday)){
- case 0:
- str_58_disp(3,120,pstr("7"),0);
- break;
- case 1:
- str_58_disp(3,120,pstr("1"),0);
- break;
- case 2:
- str_58_disp(3,120,pstr("2"),0);
- break;
- case 3:
- str_58_disp(3,120,pstr("3"),0);
- break;
- case 4:
- str_58_disp(3,120,pstr("4"),0);
- break;
- case 5:
- str_58_disp(3,120,pstr("5"),0);
- break;
- case 6:
- str_58_disp(3,120,pstr("6"),0);
- break;
- }
- if(bhour/10!=0)
- {
- ascii_58_disp(3,66,bhour/10+0x30,0);
- num1632_disp(4,0,bhour/10,0);
- }
- else
- {
- ascii_58_disp(3,66,0x20,0);
- num1632_disp(4,0,11,0);
- }
- ascii_58_disp(3,72,bhour%10+0x30,0);
- ascii_58_disp(3,78,':',0);
- ascii_58_disp(3,84,time[2],0);
- ascii_58_disp(3,90,time[3],0);
- ascii_58_disp(3,96,':',0);
- ascii_58_disp(3,102,time[4],0);
- ascii_58_disp(3,108,time[5],0);
-
- num1632_disp(4,1,bhour%10,0);
- num1632_disp(4,2,10,0);
- num1632_disp(4,3,time[2]-0x30,0);
- num1632_disp(4,4,time[3]-0x30,0);
- num1632_disp(4,5,10,0);
- num1632_disp(4,6,time[4]-0x30,0);
- num1632_disp(4,7,time[5]-0x30,0);
-
- buf_full&=~0x08;
- dsp_count=0;
- }
- }
- }
- }
- //计算星期
- unsigned char week(unsigned char year, unsigned char mon, unsigned char day)
- {
- const prog_uchar weekdays[] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
- // 31 28 31 30 31 30 31 31 30 31 30
- return (6-1 + (year>>2) + year + weekdays[mon-1] + day + (((year & 3) || mon > 2)? 1 : 0)) % 7;
- //完整的计算星期的公式:
- //(year>>2) - (year / 100) + (year/400) + year +
- // weekdays[mon-1] + day + ((!isleap(year) || mon > 2)? 1 : 0)) % 7;
- }
- //usart 初始化
- void init_usart(void)
- {
- ucsrc = (1<<ursel) | 0x06; //异步,8位数据,无奇偶校验,一个停止位,无倍速
- ubrrl= (f_cpu/9600/16-1)%256; //ubrr= (f_cpu/(baudrate*16))-1;
- ubrrh= (f_cpu/9600/16-1)/256;
- ucsra = 0x00; //使能接收中断,使能接收,使能发送
- ucsrb = (1<<rxcie)|(1<<rxen)|(1<<txen);
- sei(); //总中断允许
- }
- //系统初始化
- void sys_init()
- {
- lcd_reset(); //初始化lcd
- clean_screen();
- init_usart(); //初始化串口
- }
- //串口接收中断
- signal(sig_uart_recv) //串口接收中断服务程序
- {
- unsigned char tmp;
- tmp=udr;
- switch(tmp){
- case '$':
- cmd_number=0; //命令类型清空
- mode=1; //接收命令模式
- byte_count=0; //接收位数清空
- break;
- case ',':
- seg_count++; //逗号计数加1
- byte_count=0;
- break;
- case '*':
- switch(cmd_number){
- case 1:
- buf_full|=0x01;
- break;
- case 2:
- buf_full|=0x02;
- break;
- case 3:
- buf_full|=0x04;
- break;
- case 4:
- buf_full|=0x08;
- break;
- }
- mode=0;
- break;
- default:
- if(mode==1){
- //命令种类判断
- cmd[byte_count]=tmp; //接收字符放入类型缓存
- if(byte_count>=4){ //如果类型数据接收完毕,判断类型
- if(cmd[0]=='g'){
- if(cmd[1]=='p'){
- if(cmd[2]=='g'){
- if(cmd[3]=='g'){
- if(cmd[4]=='a'){
- cmd_number=1;
- mode=2;
- seg_count=0;
- byte_count=0;
- high_num=0;
- }
- }
- else if(cmd[3]=='s'){
- if(cmd[4]=='v'){
- cmd_number=2;
- mode=2;
- seg_count=0;
- byte_count=0;
- }
- }
- }
- else if(cmd[2]=='r'){
- if(cmd[3]=='m'){
- if(cmd[4]=='c'){
- cmd_number=3;
- mode=2;
- seg_count=0;
- byte_count=0;
- a_num=0;
- s_num=0;
- }
- }
- }
- else if(cmd[2]=='z'){
- if(cmd[3]=='d'){
- if(cmd[4]=='a'){
- cmd_number=4;
- mode=2;
- seg_count=0;
- byte_count=0;
- }
- }
- }
- }
- }
- }
- }
- else if(mode==2){
- //接收数据处理
- switch (cmd_number){
- case 1: //类型1数据接收。gpgga
- switch(seg_count){
- case 2: //纬度处理
- if(byte_count<9){
- wd[byte_count]=tmp;
- }
- break;
- case 3: //纬度方向处理
- if(byte_count<1){
- wd_a=tmp;
- }
- break;
- case 4: //经度处理
- if(byte_count<10){
- jd[byte_count]=tmp;
- }
- break;
- case 5: //经度方向处理
- if(byte_count<1){
- jd_a=tmp;
- }
- break;
- case 7: //定位使用的卫星数
- if(byte_count<2){
- use_sat[byte_count]=tmp;
- }
- break;
- case 9: //高度处理
- if(byte_count<6){
- high[byte_count]=tmp;
- high_num++;
- }
- break;
- }
- break;
- case 2: //类型2数据接收。gpgsv
- switch(seg_count){
- case 3: //天空中的卫星总数
- if(byte_count<2){
- total_sat[byte_count]=tmp;
- }
- break;
- }
- break;
- case 3: //类型3数据接收。gprmc
- switch(seg_count){
- case 7: //速度处理
- if(byte_count<5){
- speed[byte_count]=tmp;
- s_num++;
- }
- break;
- case 8: //方位角处理
- if(byte_count<5){
- angle[byte_count]=tmp;
- a_num++;
- }
- break;
- }
- break;
- case 4: //类型4数据接收。gpzda
- switch(seg_count){
- case 1:
- if(byte_count<6){ //时间处理
- time[byte_count]=tmp;
- }
- break;
- case 2:
- if(byte_count<2){
- date[byte_count]=tmp;
- }
- break;
- case 3:
- if(byte_count<2){
- date[byte_count+2]=tmp;
- }
- break;
- case 4:
- if((byte_count<4)&&(byte_count>1)){
- date[byte_count+2]=tmp;
- }
- break;
- }
- break;
- }
- }
- byte_count++; //接收数位加1
- break;
- }
- }
- /*
- $gpgga,024518.00,3153.7225,n,12111.9951,e,1,04,1.48,-00009,m,007,m,,*4c
- $gpgll,3153.7225,n,12111.9951,e,024518.00,a,a*63
- $gpvtg,000.0,t,004.7,m,000.0,n,000.0,k,a*20
- $gpgsa,a,2,04,08,17,20,,,,,,,,,1.48,1.48,0.03*08
- $gpgsv,2,1,08,04,15,231,38,08,29,218,42,11,49,043,,19,09,082,*76
- $gpgsv,2,2,08,27,14,198,29,28,71,316,,17,32,300,36,20,45,124,43*70
- $gprmc,024518.00,a,3153.7225,n,12111.9951,e,000.0,000.0,280107,04.7,w,a*12
- $gpzda,024519.45,28,01,2007,,*62
- */
- /*
- 012345678901234567890
- e121.22.2231 ag:112.1
- n 23.23.2341 sp:234.1
- hi:12345.5m u/t:03/12
- 2007/12/13 23[s:23]53 7
- */
' 12345
|