加入收藏 | 设为首页 | 会员中心 | 我要投稿 | RSSRSS-巴斯仪表网
您当前的位置:首页 > 电子发烧 > 单片机学习

基于C8051F040简易GPS导航仪的实现源程序

时间:2013-09-02  来源:123485.com  作者:9stone

/***********
** Project name:   GPS_LCD Nvigation System Experiment
**
** Descriptions:   Undergraduate Group Project of Navigation & Control
**       
** Created by:    GPS_LCD Nvigation System Design Group
**
** Major:                Navigation & Control, Beihang University
**
** Supervisor:            Professor Zhanghai, Zhang Liyong
**
** Created Date:   11 Jan 2007
**
***************/
#include <C8051F040.h>
#include <stdio.h>
#include <stdlib.h>
#include<absacc.h>
#define baud rate 4800
#define N 100
#define HANG 20
#define LIE 12
#define dlcd XBYTE[0x8000]/*定义送数据的地址*/
#define clcd1 XBYTE[0xa000]/*定义送指令的地址,行地址*/
#define clcd2 XBYTE[0xc000]/*定义送指令的地址,列地址*/
#define clcd3 XBYTE[0xe000]/*定义送指令的地址,设置显示页和操作页*/

typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned long ulong;
typedef struct {uint x; uint y;}point;
sfr16 RCAP2=0xca;
sfr16 RCAP3=0xca;
sfr16 RCAP4=0xca;
sfr16 TMR2=0xcc;
xdata uchar GPS_infor[N];//处理缓冲区
xdata uchar GPS_buff[N];//接收区
xdata uchar GPS_sec[HANG][LIE];//2维数组
xdata uchar GPS_sec_temp1[11];//中间变量1
xdata uchar GPS_sec_temp2[5];//中间变量2
xdata uchar mode[LIE];
xdata ulong longitude=0;//纬度
xdata ulong latitude=0;//经度
xdata ulong lol=0;//经度低位
xdata ulong loh=0;//经度高位
xdata ulong lal=0;//纬度低位
xdata ulong lah=0;//纬度高位
xdata uint  xx,yy;
uint  i,j;
uchar i1;
uchar  k,p,q;
uchar is_front,is_end,length;//判别参数
uchar color;
int xdata  data_col[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};//区域填充交点存储数组

void Clearlcd(uchar color,uchar ppage);/*清屏*/
void Draw_point(uint x,uint y,uchar point_color);//画点子程序
void Draw_line(point point_a,point point_b,uchar line_color);//画线子程序
void Fill_in(point *peak,int mun,uchar fill_color);//区域填充子程序
void Draw_rectangle(int x1,int y1,int x2,int y2,uchar color);
void Draw_position(uint color);
void delay1ms(uint time);
void Get_color(uint x,uint y);

int node(point *peak,int row,int num,uchar color);//交点求取子程序
void sort_data(int *node_in,int num);//排序子程序
int drop_data(int *node_in,int num);//重点去除子程序
void Draw_line2(uint row,uint col_s,uint col_f,uchar color);//画水平线子程序
uint max(uint x,uint y){return (x>y?x:y);}
uint min(uint x,uint y){return (x<y?x:y);}
void EMI_ini();
void uart0_ini();
void t2_ini();
void t2_baud(uint rate);
void config (void);
void para_clear();
void SendChar(uchar tt);


void EMI_ini()
{
    SFRPAGE   = EMI0_PAGE;
 EMI0CF = 0x37;
 EMI0TC = 0xFF;
}

/************************串口初始化配制*****************************/
void uart0_ini()
{
    SFRPAGE = UART0_PAGE;
    SADEN0 = 0x00;// SADEN0为UART0从机地址控制寄存器,0表示相应位地址不参加过滤,即该位地址值为0或1均为有效地址
    SADDR0 = 0x00;// SADDR0为UART0从机地址设置寄存器
    SSTA0 = 0x15;// SMOD0=1,UART0波特率2分频允许,此时在使用T1至T4为波特率发生定时器时,计算公式为BandRate=ft/16,ft为T1至T4的溢出率
 //TX0时钟源为T2,RX0时钟源为T2
    SCON0 = 0x50;//工作在模式1,为8bit可变波特率通讯
    SCON0 &= 0xFC;  //将TI0和RI0清零
 t2_ini();//初始化UART0的波特率产生定时器T2
}

/*************************定时器2初始化配制****************************/
void t2_ini()
{
 SFRPAGE=TMR2_PAGE;
 TMR2CF = 0x10;  // T2为外部时钟的8分频,计数方向为增值计数
   TMR2CN = 0x04;  // TR2置1,启动定时器
}

/*************************定时器2产生波特率为4800bps*************************/
void t2_baud(uint rate)
{
 uint count;
 SFRPAGE = TMR2_PAGE;
 count=22118400/8/16/rate;
 RCAP2=~count+1;//RCAP2用于存放定时器重载值,TMR2是计数寄存器
 TMR2=RCAP2;
}

void config()
{
 uchar n;

 WDTCN = 0xDE;          //禁止看门狗
    WDTCN = 0xAD;
 
 SFRPAGE = CONFIG_PAGE;
 XBR0 = 0x34;          //将PCA0至PCA5和UART0配置到端口
 XBR1 = 0x00; 
 XBR2 = 0x44;         //全局弱上拉开启,将XBAR打开;TX1,RX1配置到端口
  XBR3 = 0x00; 
  P0MDOUT = 0xFF;
  P1MDOUT = 0xFF;
  P1MDIN = 0xFF; 
 P4MDOUT = 0xff;
 P5MDOUT = 0xff;
 P7MDOUT = 0xff;
 SFRPAGE = CONFIG_PAGE; //晶振配置,系统时钟采用采用内部晶振微调后8分频
  CLKSEL  = 0x00;       //系统时钟采用内部晶振
 OSCXCN  = 0x67;      //外部晶振配置:外部石英晶振模式,不分频,并配置合适的驱动电流
 for(;n<255;n++)
 while((OSCXCN&0x80)==0);//查询XTLVLD是否为1,等待外部晶振稳定振荡
 CLKSEL  = 0x00;         //选择内部晶振
 OSCICN  = 0x83;
 SFRPAGE=0x0F;
 SFRPGCN=0x01;
 IE=0x90;//若UART0使用中断方式则应该开全局中断
}//端口与时钟配置函数

/*********************采用查询方式串口输出**************************/
void SendChar(uchar tt)
{
 SBUF0=tt;
 while(TI0==0);
 TI0=0;
}

/*****************************参数清零*****************************/
void para_clear()
{
 i=0;
 j=0;
 p=0;
 q=0;
 k=0;
}

/*****************************GPS码分割函数*****************************/
void GPS_div()
{
 para_clear();
 for(k=0;k<=length;k++)           //利用',',将数组进行分割,存到二维数组div中
     {
  if(GPS_infor[k]!=','){GPS_sec[p][q]=GPS_infor[k];q++;}
  else {p++;q=0;}
  }
}

/**********************通过串口输出接收进来的GPS数据*******************/
void GPS_out()
{
 p=2;//纬度部分
 for(q=0;GPS_sec[p][q]!='/0';q++)
   {
       SFRPAGE=0;
   SendChar(GPS_sec[p][q]);
  }
 SendChar('*');
 p=4;//经度部分
 for(q=0;GPS_sec[p][q]!='/0';q++)
   {
       SFRPAGE=0;
   SendChar(GPS_sec[p][q]);
      }
 SendChar('*');
}

/*************GGA码解码函数,得到latitude和longitude用整数类型存储***********/
void GGA_deal()
{
 para_clear();//整数小数同存,按单位统一到角度
 for (i=0;GPS_sec[2][i]!='.';i++) GPS_sec_temp1[i]=GPS_sec[2][i];//按.分割 移位
 for (j=i;j<=i+3;j++) GPS_sec_temp1[j]=GPS_sec[2][j+1];
 for (j=j;j<11;j++) GPS_sec_temp1[j]='/0';
 latitude=atol(GPS_sec_temp1);
 for (i=0;GPS_sec[4][i]!='.';i++) GPS_sec_temp1[i]=GPS_sec[4][i];  
 for (j=i;j<=i+3;j++) GPS_sec_temp1[j]=GPS_sec[4][j+1];
 for (j=j;j<11;j++) GPS_sec_temp1[j]='/0';
 longitude=atol(GPS_sec_temp1);
 lal=latitude%1000000;//取出角分
 lol=longitude%1000000;
 lah=latitude-lal;//取出角度
 loh=longitude-lol;
 lal=lal*100/60;//化角分为度
 lol=lol*100/60;
 latitude=lah+lal;//整合
 longitude=loh+lol;
 para_clear();
}

/************GPS信息解算,并在LCD屏幕上标出用户所在位置************/
void GPS_cau()
{
 point xdata aera_point[6]={{22,195},{40,195},{48,175},{48,127},{40,107},{22,107}};
 point xdata aera_pool[6]={{84,275},{94,245},{94,226},{60,232},{54,240},{70,250}};
 xx=(longitude-116334919)/53;//按经纬度边界计算LCD上画点位置
 yy=(latitude-39975169)/31;
    Get_color(xx,yy);

    //Draw_position(0xe3);
    //delay1ms(2000);

 //Draw_position(color);

    /*xx=xx+5;
 yy=yy+5;

    Get_color(xx,yy);
    Draw_position(0xfc);
 delay1ms(2000);
 
    Draw_position(color);*/

 for(i1=0;i1<10;i1++)
 {
 xx=xx+1;
    Get_color(xx,yy);
    Draw_position(0xfc);
 delay1ms(1000);
 
    Draw_position(color);
 }

 for(i1=0;i1<10;i1++)
 {
 yy=yy+1;
    Get_color(xx,yy);
    Draw_position(0xfc);
 delay1ms(1000);
 Draw_position(color);
 }

 for(i1=9;i1>0;i1--)
 {
 xx=xx-1;
    Get_color(xx,yy);
    Draw_position(0xfc);
 delay1ms(1000);
 Draw_position(color);
 }

 for(i1=9;i1>0;i1--)
 {
 yy=yy-1;
    Get_color(xx,yy);
    Draw_position(0xfc);
 delay1ms(1000);
 Draw_position(color);
 }

}

/************得到原来点的颜色值,以便进行覆盖************/
void Get_color(uint x,uint y)
{
   
 uchar high,low;

    high = (y&0xff00)>>8;
 low = y&0xff;

   clcd3=0x00;       //设定操作页和显示页 
 clcd1=x;      //设定行地址
 clcd2=high;  //设定列地址
 clcd2=low;
 color=dlcd;
}


/************画出用户位置,在LCD屏幕上用十字显示************/
void Draw_position(uint color)//画出所在点的位置
{
 Draw_point(xx,yy,color);
 Draw_point(xx-1,yy,color);
 Draw_point(xx+1,yy,color);
 Draw_point(xx,yy,color);
 Draw_point(xx,yy-1,color);
 Draw_point(xx,yy+1,color);
}
 

/*****************初始化LCD上的电子地图***********************/
void Draw_LCD()
{
    point xdata aera_point[6]={{22,195},{40,195},{48,175},{48,127},{40,107},{22,107}};
 point xdata aera_pool[6]={{84,275},{94,245},{94,226},{60,232},{54,240},{70,250}};
 
 Clearlcd(0x03,0x11);  //清屏
 Clearlcd(219,0x01);

 Fill_in(aera_point,6,107);//新食堂
 Draw_line2(40,107,195,107);
 Draw_rectangle(3,0,104,10,0xe3);//西南边
 Draw_rectangle(110,0,231,10,0xe3);//东南边
 Draw_rectangle(161,16,231,86,109);//新主楼
 Draw_rectangle(110,16,155,86,109);//体育馆
 Draw_rectangle(176,71,216,31,0xfe);//新主楼天井
 Draw_rectangle(68,86,104,16,111);//篮球场
 Draw_rectangle(65,86,20,16,111);//操场
 Draw_rectangle(15,317,3,16,0xe3);// 西边
 Draw_rectangle(55,76,30,26,12);//操场草坪
 Draw_rectangle(145,162,231,92,109);//东南门区域
 Draw_rectangle(110,162,141,92,109);//办公区
 Draw_rectangle(110,290,231,164,30);//教学区
 Draw_rectangle(50,210,104,92,244);//生活区
 Draw_rectangle(20,216,104,290,16);//绿园
 Draw_rectangle(20,296,104,317,0xe3);//西北边
 Draw_rectangle(110,296,231,317,0xe3);//东北边
 Fill_in(aera_pool,6,0x03);//荷花池
}

/********************单片机主程序********************/
void main(void)
{
 int xdata flag=0;
 
 point a,b;
 a.x=107;
 a.y=0;
 b.x=107;
 b.y=320;
 
 config();//初始化
 EMI_ini();
 uart0_ini();
 t2_baud(baud_rate);
 para_clear();

    Draw_LCD(); //初始化LCD屏上的电子地图

  while(1)
 { 
  if(is_end==1)
    {
   GPS_div();
   GPS_out();
   GGA_deal();
   GPS_cau();
   is_end=0;
   para_clear();
    }
    }

}

/********************串口中断服务子程序********************/
void COMM() interrupt 4
{
 if(RI0==1)
 {
  GPS_buff[i]=SBUF0;       
  RI0=0;           
        if (GPS_buff[0]=='$') i++;//判断首位是否为$
  else para_clear();
  if ((GPS_buff[i-2]=='?') && (GPS_buff[i-1]=='/'))//判断是否为报尾,暂用?/代替0x0D 0x0A
    {
       is_end=1;
    length=i-1;
    for (j=0;j<=length;j++) GPS_infor[j]=GPS_buff[j];//建立缓冲区
    }
  if (i==100) i=0;//避免数组溢出
 }
}

/********************延时子程序********************/
void delay1ms(uint time){
 for (i=0;i<time;i++){
  for(j=0;j<1000;j++);
 }
}

/********************基本指令集清屏子程序********************/
void Clearlcd(uchar color,uchar ppage)
{
 uchar data k=0x00;
 clcd3=ppage;  /*设定显示页和操作页*/
 for(i=0;i<234;i++)
 {
  clcd1=i;  /*设定行地址*/
  clcd2=0x00;
  clcd2=0x00;  /*设定列地址*/
  for(j=0;j<80;j++)
  {
   dlcd=color; /*写颜色数据*/
   dlcd=color;
   dlcd=color;
   dlcd=color;
  }
  k=k+0x01;
 }
}

/*******************画点子程序********************/
void Draw_point(uint x,uint y,uchar point_color)
{
 uchar high,low;

 high = (y&0xff00)>>8;
 low = y&0xff;

 clcd3=0x00; //设定操作页和显示页 
 clcd1=x; /*设定行地址*/
 clcd2=high;  /*设定列地址*/
 clcd2=low;
  
 dlcd=point_color; /*写显示数据*/   
}

/************************画线子程序**************************/
void Draw_line(point point_a,point point_b,uchar line_color)
{
 int i=0,temp=0;
 int dis_row=0,dis_col=0;
 int min_row=0,min_col=0,max_row=0,max_col=0;

 max_row=max(point_a.x,point_b.x);/*行最大值*/
 min_row=min(point_a.x,point_b.x);/*行最小值*/

 max_col=max(point_a.y,point_b.y);/*列最大值*/
 min_col=min(point_a.y,point_b.y);/*列最小值*/

 if ((max_row-min_row)>(max_col-min_col))//横向距离大于纵向距离,以横向基准画线
 {
  if (max_col==min_col)   //要求线段为垂线
  {
   for(i=min_row;i<=max_row;i++)
    Draw_point(i,min_col,line_color);
  }
  else
  {
   for(i=min_row;i<=max_row;i++)
   {
    temp=(int)((float)((float)point_b.y-point_a.y)/(float)((float)point_b.x-point_a.x)*
         ((float)i-point_a.x)+point_a.y);//两点法直线描述纵坐标计算公式
    Draw_point(i,temp,line_color);
   }
  }
 }
 else         //纵向距离大于横向距离,以纵向基准画线
 {
  if (max_row==min_row)
  {
   for(i=min_col;i<=max_col;i++) //要求线段为水平线
    Draw_point(min_row,i,line_color);
  }
  else
  {
   for(i=min_col;i<=max_col;i++)
   {
    temp=(int)((float)((float)point_b.x-point_a.x)/(float)((float)point_b.y-point_a.y)*
         ((float)i-point_a.y)+point_a.x);//两点法直线描述横坐标计算公式
    Draw_point(temp,i,line_color);
   }
  }
 }
 
}

/*****************************************************************
** Function name:   Fill_in
**
** Descriptions:   填充一个多边行区域
**
** input parameters:  peak:多边形的顶点坐标,顶点坐标必须按顺序给出
       num:顶点个数
       fill_color:填充颜色
**
** Returned value:   none
**        
** Created by:    qin
** Created Date:   2006/12/12
******************************************************************/
void Fill_in(point *peak,int num,uchar fill_color)
{
 int i1=0,j1=0,node_num=0;
 int xdata max_row,min_row;

 for(i1=0;i1<num;i1++)
 {
  j1=(i1+1)%num;
  Draw_line(*(peak+i1),*(peak+j1),fill_color);
 }

 max_row=peak->x;
 min_row=peak->x;
 for(i1=0;i1<num;i1++) //得到所有顶点中,行最大值,行最小值
 {
  if((peak+i1)->x>max_row)
   max_row=(peak+i1)->x;
  if((peak+i1)->x<min_row)
   min_row=(peak+i1)->x;
 }

 for(i1=min_row;i1<max_row;i1++)
 {
  node_num=node(peak,i1,num,fill_color);//行扫描填充,求得扫描线与轮廓外形的交点
  sort_data(data_col,node_num);  //交点按从小到大排序
  
  if((node_num%2)==1)
   node_num=drop_data(data_col,node_num);//交点为基数,去掉重复点
  
  for(j1=0;j1<node_num;j1=j1+2)
  {
   Draw_line2(i1,data_col[j1],data_col[j1+1],fill_color);//扫描区域水平线填充
  }  
 }
}

/*****************************************************************
** Function name:   node
**
** Descriptions:   求出扫描线与轮廓线的交点,交点值存放在全局变量data_col中
**
** input parameters:  peak:多边形顶点坐标
       row:扫描线的行值
       num:顶点的个数
       color:线段的颜色
**
** Returned value:   none
**        
** Created by:    qin
** Created Date:   2006/12/12
******************************************************************/
int node(point *peak,int row,int num,uchar color)
{
 int i2,j2,k=0;

 for(i2=0;i2<num;i2++)
 {
  j2=(i2+1)%num;
  if (((peak+j2)->x)!=((peak+i2)->x))
  {
   if((row>=min((peak+j2)->x,(peak+i2)->x))&&(row<=max((peak+j2)->x,(peak+i2)->x)))
   {
    data_col[k]=(int)((float)((float)(peak+j2)->y-(peak+i2)->y)/(float)((float)(peak+j2)->x-(peak+i2)->x)*
         ((float)row-(peak+i2)->x)+(peak+i2)->y);
    k=k+1;
   }
  }
  else
  {
   if((peak+i2)->x==row)
    Draw_line(*(peak+i2),*(peak+j2),color);
  }
 }
 return k;
}

/*****************************************************************
** Function name:   sort_data
**
** Descriptions:   数组中值排序
**
** input parameters:  node_in:需要排序的数组指针
       num:数组中数据的个数
**
** Returned value:   none
**        
** Created by:    qin
** Created Date:   2006/12/12
******************************************************************/
void sort_data(int *node_in,int num)
{
 int temp,i3,j3;

 for(j3=num;j3>1;j3--)
 {
  for(i3=0;i3<j3-1;i3++)
  {
   if(node_in[i3]>node_in[i3+1])
   {
    temp=node_in[i3];
    node_in[i3]=node_in[i3+1];
    node_in[i3+1]=temp;
   }
  }
 }
}

/*****************************************************************
** Function name:   Draw_line2
**
** Descriptions:   画两点之间的水平线
**
** input parameters:  row:水平线所在的行
       col_s:起始列值
       col_f:结束列值
       color:线段的颜色
**
** Returned value:   none
**        
** Created by:    qin
** Created Date:   2006/12/12
******************************************************************/
void Draw_line2(uint row,uint col_s,uint col_f,uchar color)
{
 int i4=0;
 uchar high1,low1;

 high1 = (col_s&0xff00)>>8;
 low1 = col_s&0xff;

 clcd3=0x00;  
 clcd1=row; /*设定行地址*/
 clcd2=high1;  /*设定列地址*/
 clcd2=low1;

 for(i4=col_s;i4<=col_f;i4++)  
 {
  dlcd=color; /*写显示数据*/
 }  
}

/*****************************************************************
** Function name:   drop_data
**
** Descriptions:   去除重点
**
** input parameters:  node_in:需要去除重复点的数组指针
       num:数组中数据的个数
** Returned value:   去除重复点后节点的个数
**        
******************************************************************/
int drop_data(int *node_in,int num)
{
 int i5,j5,new_num=num;

 for(j5=0;j5<num;j5++)
 {
  if(node_in[j5]==node_in[j5+1])
  {
   for(i5=j5;i5<num-1;i5++)
    node_in[i5]=node_in[i5+1];
   num=num-1;
  }
 }
}

/******************************************************************
** Function name:   Draw_rectangle
**
** Descriptions:   画矩形子程序
**
** input parameters:  int x1,int y1,int x2,int y2 分别为矩形对角线两点坐标
**       
** Returned value:   去除重复点后节点的个数
**        
******************************************************************/
void Draw_rectangle(int x1,int y1,int x2,int y2,uchar color)
{
 int i6;
 int xdata max_x,min_x;

 max_x=max(x1,x2);
 min_x=min(x1,x2);

 for(i6=min_x;i6<max_x;i6++)
 {
  Draw_line2(i6,min(y1,y2),max(y1,y2),color);
 }
}


 

分享到:
来顶一下
返回首页
返回首页
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
栏目导航->单片机学习
  • 电子应用基础
  • 电源技术
  • 无线传输技术
  • 信号处理
  • PCB设计
  • EDA技术
  • 单片机学习
  • 电子工具设备
  • 技术文章
  • 精彩拆解欣赏
  • 推荐资讯
    使用普通运放的仪表放大器
    使用普通运放的仪表放
    3V与5V混合系统中逻辑器接口问题
    3V与5V混合系统中逻辑
    数字PID控制及其改进算法的应用
    数字PID控制及其改进
    恶劣环境下的高性价比AD信号处理数据采集系统
    恶劣环境下的高性价比
    栏目更新
    栏目热门