首页 > 编程学习 > 基于ATmega16单片机和GPS的多用途定位仪设计

目录
摘要 I
Abstract II
第1章绪论 1
1.1 课题研究的背景及意义 1
1.2国内外研究现状 1
1.2.1 外国研究发展现状 1
1.2.2国内研究发展现状 2
1.3课题研究技术的发展方向及研究成果 3
1.3.1 GPS技术应用发展方向 3
1.3.2课题研究的主要方向 4
1.4本文的结构安排 4
第2章总体方案及硬件电路设计 6
2.1 系统框架 6
2.2总体设计思想 7
2.3单片机最小系统介绍 7
2.3.1 ATmega16单片机概述 8
2.3.2 ATmega16引脚介绍 9
2.4电源模块介绍 10
2.4.1 LM7805主要性能 11
2.5 12864显示模块介绍 11
2.5.1 12864概述 12
2.5.2 12864接口描述 12
2.6 GPS模块通信接口介绍 13
2.6.1 GPS模块简介 14
2.6.2串口通讯协议介绍 14
2.6.3单片机串口简介 16
2.7电子罗盘模块通信接口介绍 17
2.7.1 HMC5883L三轴地磁传感器介绍 17
2.7.2 ADXL345三轴加速度传感器介绍 18
2.7.3 I2C通信协议介绍 19
2.7.4单片机I2C通信介绍 20
2.8本章小结 22
第3章软件系统设计与编程 23
3.1 GPS部分软件设计 23
3.1.1 NMEA 0183协议介绍 23
3.1.2单片机数据接收与处理 24
3.2 电子罗盘部分软件设计 26
3.2.1 电子罗盘简介 26
3.2.2单片机数据接收与处理 26
3.2.3磁偏角补偿 27
3.2.4倾角补偿 28
3.2.5外部磁场干扰补偿补偿 29
3.3 主程序设计 31
3.4本章小结 31
第4章调试 32
4.1软件调试 32
4.1.1 单片机程序开发环境介绍 32
4.1.2单片机程序烧录环境介绍 33
4.1.3串口调试助手介绍 34
4.1.4 GPS模块辅助调试工具调试 34
4.2 硬件调试 35
4.2.1 PCB设计软件介绍 35
4.2.2实际电路调试 35
4.3本章小结 38
结论 39
参考文献 40
致谢 42
附录 43

1.3.2课题研究的主要方向
由前文可见GPS技术已经延伸到各个领域的方方面面,它给我的生活带来相当多的便利。但当设备处于静止状态下或者比较偏僻的山区无法接收到GPS信号时就无法准确及时的测量出当前的方向。所以本设计在基于GPS强大优点的前提下,融合的电子罗盘的功能进而解决的GPS的一些弊端。本课题研究的主要方向是设计一个基于单片机的便携式GPS设备,能够测量常用的多种数据,且能适应诸多不同的环境和用途。
1.4本文的结构安排
本文共分为4章,对课题的叙述结构安排如下:
第1章中结合课题背景与国内外GPS定位系统研究现状分析课题的选题依据,以研究意义等,同时对GPS系统做简单的介绍。
第2章主要介绍整个系统的硬件电路设计,包括单片机最小系统,电源模块,12864显示部分,GPS模块通信,电子罗盘模块通信等部分。
第3章主要介绍了软件系统的设计及程序的编写思想,包括GPS通信数据的解析,和电子罗盘数据的采集。
第4章主要介绍了整个调试过程中软件调试部分和硬件调试部分。
随着GPS技术的应用越来越广泛,GPS设备的普及速度也将大大加快,在我们国内GPS产业才刚刚起步,GPS产业的兴起势必也将大大的推进GPS技术在民间的应用。当前GPS技术已在各个领域发挥了至关重要重要的作用,本文转载自http://www.biyezuopin.vip/onews.asp?id=14752为促进我们的生活和人类的发展作出了不可估量的贡献。
不过由于其自身技术的限制和一些特定环境的限制,使得GPS设备还存在种种的弊端。这次设计针对这些弊端提出一种解决思路,即采用GPS和电子罗盘相结合的方式,从而解决了在静态和特殊地理环境下GPS无法准确定位的情况,具有很大的使用价值。
课题所设计的多用途定位仪具有以下特点:
1.采用ATmega16单片机,采用5V电压工作,系统工作稳定,成本低廉。
2.采用LCD12864大屏幕进行中文显示,使得相关的测量数据的显示更加清晰易懂,各屏数据间只需一个按键即可相互切换。
3.应用范围广泛,由于测量显示的数据非常多,包括:时间、坐标、速度、航向、高度、海拔、方向和倾角。故该仪器可用航海、野外旅行、车载导航等诸多方面。
4.采用GPS加电子罗盘的方式克服了单纯的GPS设备在静态情况和没有GPS信号的情况下无法准确及时测量当前方向的问题。

#include<iom16v.h>
#include<stdio.h>
#include<macros.h>
#include<math.h>
#include<string.h>
#include"Delay.h"
#include"12864.h"
#include"I2C.h"
#include"GPS.h"
#pragma interrupt_handler ext_INT0:2
#pragma interrupt_handler uart_rx:12
#define  uchar unsigned char
#define  uint  unsigned int
#define  mclk  8000000
/******ADXL345读写地址,ADDRESS引脚接地*********/
#define ADXL_SLA_W               0XA6  //从机地址,主机写操作
#define ADXL_SLA_R               0XA7  //从机地址,主机读操作 
/**********HMC5883L读写地址************************/
#define HMC_SLA_W               0X3C  //从机地址,主机写操作
#define HMC_SLA_R               0X3D  //从机地址,主机读操作 

/*************全局变量**********************/
uchar init1[] = {"BASE-MCU GPS终端"};  
uchar init2[] = {"GPS 初始化......"};
uchar init3[] = {"搜索定位卫星...."};
uchar line1[]={"    年  月  日  "};
uchar line2[]={"  时  分  秒    "};
uchar line3[]={"纬度:   .  .    "};
uchar line4[]={"经度:   .  .    "};
uchar line5[]={"速度: 000000km/h"};
uchar line6[]={"航向: 000000  度"};
uchar line7[]={"高度: 000000 M  "};
uchar line8[]={"海拔: 000000 M  "};
uchar line9[]={"angle:000.0     "};
uchar line10[]={"X 轴倾角: 00.0  "};
uchar line11[]={"Y 轴倾角: 00.0  "};
uchar line12[]={"                "};

GPS_INFO   GPS;  //GPS信息结构体
char rev_buf[80];        //接收缓存     
uchar rev_start = 0;     //接收开始标志      
uchar rev_stop  = 0;     //接收停止标志     
uchar gps_flag = 0;      //GPS处理标志    
uchar change_page = 0;   //换页显示标志    
uchar num = 0;           //字符串数组位数
uchar direction_data[5];
uchar ge,shi,bai,qian,wan;


/*******************函数声明*****************/
void uart_init(uint baud);
void uart_sendB(uchar data);
void init_int0(void);
void GPS_Init(void);
void GPS_DisplayOne(void);
void GPS_DisplayTwo(void);

void Init_hmc5883(void);
void Multiple_read(void);
void conversion(uint temp_data);
void Init_ADXL345(void);
/*****************************************
函数名称:GPS_Init
作用:GPS模块初始化显示
******************************************/
void GPS_Init(void)
{
	send_string(0, 0, init1);
	send_string(0, 1, init2);
	send_string(0, 2, init3);
}
/************************************
函数名称:uart_init
作用:初始化串口
*************************************/
void uart_init(uint baud)
{
   UCSRB=0x00; 
   UCSRA=0x00; 		    //控制寄存器清零
   UCSRC=(1<<URSEL)|(0<<UPM0)|(3<<UCSZ0);   
                                                        //选择UCSRC,异步模式,禁止                        
                                                     //   校验,1位停止位,8位数据位
   baud=mclk/16/baud-1	;   //波特率最大为65K
   UBRRL=baud; 					     	  
   UBRRH=baud>>8; 		   //设置波特率
   UCSRB=(1<<TXEN)|(1<<RXEN)|(1<<RXCIE); 
                                                       //接收、发送使能,接收中断使能
   SREG=BIT(7);	                //全局中断开放
   DDRD|=0X02;	                //配置TX为输出(很重要)

}
/****************************************
函数名称:uart_sendB
作用:串口发送数据
****************************************/
void uart_sendB(uchar data)
{
   while(!(UCSRA&(BIT(UDRE)))) ;
   UDR=data;
   while(!(UCSRA&(BIT(TXC))));
   UCSRA|=BIT(TXC);
}
/*****************************************
中断名称:uart_rx
作用:串口接收数据
******************************************/
void uart_rx(void)
{
    uchar ch;
	UCSRB&=~BIT(RXCIE);
	ch = UDR;     
		if ((ch == '$') && (gps_flag == 0))  //如果收到字符'$',便开始接收           
		{
			rev_start = 1;
			rev_stop  = 0;
		}
	
		if (rev_start == 1)  //标志位为1,开始接收            
		{
			rev_buf[num++] = ch;  //字符存到数组中           
			if (ch == '\n')     //如果接收到换行           
			{
				rev_buf[num] = '\0';
				rev_start = 0;
				rev_stop  = 1;
				gps_flag = 1;
				num = 0;
			}
		}
	UCSRB|=BIT(RXCIE);
}
/*****************************************
中断名称:ext_INT0
作用:外部输入中断
*****************************************/
void ext_INT0(void)
{	 
	 uchar temp;
	 delayms(10);
	 GICR&=~BIT(6);
	 temp=PIND&BIT(2);
	 if(temp==0x00)
	 {
	  	change_page++;
        if(change_page==3)
	    change_page=0;
	 } 
	 GICR|=BIT(6);
}
/*******************************************
函数名称:init_int0
作用:进行外部中断初始化
********************************************/
void init_int0(void)
{	 
	 
	 MCUCR|=0X02;
	 GICR|=BIT(6);
	 SREG|=BIT(7);
	 
	 DDRD&=~BIT(2);
	 PORTD|=BIT(2);
}
/***************************************
函数名称:Init_hmc5883
作用:初始化芯片hmc5883
****************************************/
void Init_hmc5883(void)
{	 
	//I2C_write(0x00,0x70);
	//I2C_write(0x01,0x40);
	I2C_write(HMC_SLA_W,0X02,0X00);
	
}
/***********************************************
函数名称:Init_ADXL345
作用:初始化ADXL345
*************************************************/
void Init_ADXL345(void)
{	 
	 I2C_write(ADXL_SLA_W,0x31,0x0B);   //测量范围,正负16g,13位模式
	 I2C_write(ADXL_SLA_W,0x2D,0x08);   //选择电源模式   
	 I2C_write(ADXL_SLA_W,0x2E,0x80);   //使能 DATA_READY 中断
	 I2C_write(ADXL_SLA_W,0x2C,0x08);   //速率设定为12.5 
	 I2C_write(ADXL_SLA_W,0x1E,0x00);   //X 偏移量 
	 I2C_write(ADXL_SLA_W,0x1F,0x00);   //Y 偏移量 
	 I2C_write(ADXL_SLA_W,0x20,0x05);   //Z 偏移量 
}

/**********************************
函数名称:Multiple_read_hmc5883
作用:读取X,Y,Z,六个寄存中的值
************************************/
void Multiple_read(void)
{	 
	 uchar i;
	 int x,y,z;
	 int a,b;
	 double temp1,temp2;
	 double angle,angle_x,angle_y;
	 double X_h,Y_h;
	 
	 x=I2C_read(ADXL_SLA_W,ADXL_SLA_R,0x33)<<8|I2C_read(ADXL_SLA_W,ADXL_SLA_R,0x32);
	 y=I2C_read(ADXL_SLA_W,ADXL_SLA_R,0x35)<<8|I2C_read(ADXL_SLA_W,ADXL_SLA_R,0x34);
	 z=I2C_read(ADXL_SLA_W,ADXL_SLA_R,0x37)<<8|I2C_read(ADXL_SLA_W,ADXL_SLA_R,0x36); 
	 
	 angle_x=atan2((double)x,(double)z);
	 angle_y=atan2((double)y,(double)z);
	 
	 temp1=angle_x*(180/3.14159265)*10;
	 if(angle_x<0)
	 {
	 temp1=-temp1;
	 line10[9]='-';
	 }
	 else
	 line10[9]=' ';
	 conversion(temp1);
	 line10[10]=bai;
	 line10[11]=shi;
	 line10[13]=ge;
	 
	 temp2=angle_y*(180/3.14159265)*10;
	 if(angle_y<0)
	 {
	 temp2=-temp2;
	 line11[9]='-';
	 }
	 else
	 line11[9]=' ';
	 conversion(temp2);
	 line11[10]=bai;
	 line11[11]=shi;
	 line11[13]=ge;
	 for(i=0;i<6;i++)
	 {
	    direction_data[i]=I2C_read(HMC_SLA_W,HMC_SLA_R,0x03+i);
	 }
	 x=direction_data[0]<<8|direction_data[1]; //Combine MSB and LSB of X Data output register
     
	 z=direction_data[2]<<8|direction_data[3]; //Combine MSB and LSB of Z Data output register
     
	 y=direction_data[4]<<8|direction_data[5]; //Combine MSB and LSB of Y Data output register
	 
	 X_h=(double)x*cos(angle_y)+(double)y*sin(angle_x)*sin(angle_y);
	 X_h=X_h-(double)z*cos(angle_x)*sin(angle_y);
	 Y_h=(double)y*cos(angle_x)+(double)z*sin(angle_x); 
	 
	 angle= atan2(Y_h,X_h) * 57.3 + 180; // angle in degrees
     if(angle>=0 && angle<352.5)
	 angle=angle+7.5;
	 else if(angle>=352.5 && angle<360)
	 angle=angle-352.5;
	 angle*=10;
	 conversion(angle);
	 line9[6]=qian;
	 line9[7]=bai;
	 line9[8]=shi;
	 line9[10]=ge;
}
/******************************************
函数名称:conversion
作用:对读出的数据进行转化
*********************************************/
void conversion(uint temp_data)  
{  
    wan=temp_data/10000+0x30 ;
    temp_data=temp_data%10000;   //取余运算
	qian=temp_data/1000+0x30 ;
    temp_data=temp_data%1000;    //取余运算
    bai=temp_data/100+0x30   ;
    temp_data=temp_data%100;     //取余运算
    shi=temp_data/10+0x30    ;
    temp_data=temp_data%10;      //取余运算
    ge=temp_data+0x30; 	
}

/*******************主函数***************************/
void main(void)
{	 
	uchar error_num = 0;
	DDRD|=BIT(6)|BIT(7);
	//PORTD|=BIT(6);
	
	uart_init(4800);  //初始化串口
	init_int0();
	delayms(100);
	
	LCD_init();     //初始化12864
	LCD_clear();
	
	TWI_init();    //初始化TWI通信
 
	GPS_Init();   //初始化GPS     
	rev_stop=0;
	PORTD|=BIT(7);
	while(1)
	{
		if (rev_stop)   //如果接收完一行         
		{        
			PORTD|=BIT(6);
			if (change_page==1)  //换页     
			{
				if (GPS_GGA_Parse(rev_buf, &GPS))  //解析GPGGA      
				{
					GPS_DisplayTwo();  //显示第二屏信息
					error_num = 0;
					gps_flag = 0;
					rev_stop  = 0;
				}
				else
				{
					error_num++;
					if (error_num >= 20) //如果数据无效超过20次               
					{
						error_num = 20;
						GPS_Init();     //返回初始化            
					}
					gps_flag = 0;
					rev_stop  = 0;
				}

			}
			else if(change_page==0)
			{
				if (GPS_RMC_Parse(rev_buf, &GPS)) //解析GPRMC         
				{
					GPS_DisplayOne();	  //显示GPS第一屏信息          
					error_num = 0;
					gps_flag = 0;
					rev_stop  = 0;
				}
				else
				{
					error_num++;
					if (error_num >= 20) //如果数据无效超过20次               
					{
						error_num = 20;
						GPS_Init();     //返回初始化          
					}
					gps_flag = 0;
					rev_stop  = 0;
				}
			}
			PORTD&=~BIT(6);
		}
		if(change_page==2)
		{	 
			 Init_ADXL345();
			 Init_hmc5883(); 
			 
			 Multiple_read();
			 send_string(0,0,line9);
			 send_string(0,1,line10);
			 send_string(0,2,line11);
			 send_string(0,3,line12);
			 delayms(40);
		}
	}
}
/*******************************************
函数名称:GPS_DisOne
作用:用来显示第一屏的数据
*******************************************/
void GPS_DisplayOne(void)
{
	uchar i = 0;
	char time[5];
	char info[10];
    /**************************显示年**************************/
	Int_To_Str(GPS.D.year,time);  //将年转换成字符串,存在time中
	if(strlen(time)==4)	  		 	//判断接收数据是否有效,有效则显示
	{
		i = 0;
		while(time[i] != '\0')
		{
			line1[0+i]=time[i];//显示年
			i++;
		}
	}
    /*******************************显示月****************************/
	Int_To_Str(GPS.D.month,time);
	if(strlen(time)==2)
	{
		i = 0;
		while(time[i] != '\0')
		{
			line1[6+i]=time[i];
			i++;
		}
	}
	/*************************显示日*****************************/
	Int_To_Str(GPS.D.day,time);
	if(strlen(time)==2)
	{
		i = 0;
		while(time[i] != '\0')
		{
			line1[10+i]=time[i];
			i++;	
		}
	}
    /*****************************显示小时*****************************/
	Int_To_Str(GPS.D.hour,time);
	if(strlen(time)==2)
	{
		i = 0;
		while(time[i] != '\0')
		{
			line2[0+i] =time[i];
			i++;
		}
	}
    /*******************************显示分钟****************************/
	Int_To_Str(GPS.D.minute,time);
	if(strlen(time)==2)
	{
		i = 0;
		while(time[i] != '\0')
		{
			line2[4+i]=time[i];
			i++;	
		}
	}
	
    /******************************显示秒*******************************/
	Int_To_Str(GPS.D.second,time);
	if(strlen(time)==2)
	{
		i = 0;
		while(time[i] != '\0')
		{
			line2[8+i]=time[i];
			i++;	
		}
	}
	
	/*********************************显示纬度******************************/
	if (GPS.NS == 'N')              //判断是北纬还是南纬
		line3[14]='N';
	else if (GPS.NS == 'S')
		line3[14]='S';
    Int_To_Str(GPS.latitude_Degree,info);  //纬度
	if(strlen(info)==2)
	{						  //只有正常显示纬度,才显示纬分
		i = 0;
		while(info[i] != '\0')
		{
			line3[6+i]=info[i];
			i++;
		}	

		Int_To_Str(GPS.latitude_Cent,info);  //纬分
		if(strlen(info)==2)
		{					  //只有正常显示纬分,才显示纬秒
			i = 0;
			while(info[i] != '\0')
			{
				line3[9+i]=info[i];
				i++;
			}

			Int_To_Str(GPS.latitude_Second,info);  //纬秒
			if(strlen(info)==2)
			{
				i = 0;
				while(info[i] != '\0')
				{
					line3[12+i]= info[i];
					i++;
				}
			}
		}	
	} 
	/********************************显示经度*********************************/
	if (GPS.EW == 'E')              //判断是东经还是西经
		line4[14]='E';
	else if (GPS.EW == 'W')
		line4[14]='w';
	Int_To_Str(GPS.longitude_Degree,info);  //经度
	if(strlen(info)==3)
	{
		i = 0;
		while(info[i] != '\0')
		{
			line4[5+i]=info[i];
			i++;
		}
		Int_To_Str(GPS.longitude_Cent,info);  //经分
		if(strlen(info)==2)
		{
			i = 0;
			while(info[i] != '\0') 
			{
				line4[9+i]=info[i];
				i++;
			}
		
			Int_To_Str(GPS.longitude_Second,info);  //经秒
			if(strlen(info)==2)
			{
				i = 0;
				while(info[i] != '\0') 
				{
					line4[12+i]=info[i];
					i++;
				} 
			}
		}
	}
	send_string(0,0,line1);
	send_string(0,1,line2);
	send_string(0,2,line3);
	send_string(0,3,line4); 
}	

/********************************************
函数名称:GPS_DisplayTwo
作用:用来显示第二屏的数据
*********************************************/
void GPS_DisplayTwo(void)
{
    int integar;
	char Info[10];
	float fla;
	uchar i;
	
	/************************************显示速度部分*********************************/
	fla=GPS.speed;
	integar = (int)fla;             							// 显示整数部分
	Int_To_Str(fla,Info);  //显示整数部分
	i = 0;
	while(Info[i] !='\0')
	{
		line5[5+i]=Info[i];
		i++;
	}
	line5[5+i]=0X2E;
	fla = fla - integar; //显示小数部分
	fla =  fla * 10;     //0.1                   						// 显示 0.1
	integar = (int) fla;
	fla = fla - integar;				 						// 改变fla的值,使fla总是小于1
	line5[6+i]= integar+0x30; 	
	fla =  fla*10;	    //0.01					 						// 显示 0.01
	integar = (int) fla;
	fla = fla - integar;					 					// 改变fla的值,使fla总是小于1
	line5[7+i]=integar+0x30 ; 
	
    /*****************************************显示航向部分********************************/
	fla=GPS.direction;
	integar = (int)fla;             							// 显示整数部分
	Int_To_Str(fla,Info);  //显示整数部分
	i = 0;
	while(Info[i] !='\0')
	{
		line6[6+i]=Info[i];
		i++;
	}
	line6[6+i]=0X2E;			   
	fla = fla - integar; //显示小数部分
	fla =  fla * 10;     //0.1                   						// 显示 0.1
	integar = (int) fla;
	fla = fla - integar;				 						// 改变fla的值,使fla总是小于1
	line6[7+i]= integar+0x30; 	
	fla =  fla*10;	    //0.01					 						// 显示 0.01
	integar = (int) fla;
	fla = fla - integar;					 					// 改变fla的值,使fla总是小于1
	line6[8+i]=integar+0x30 ; 
	
	/******************************显示高度部分*****************************************/
	fla=GPS.height_ground;
	integar = (int)fla;             							// 显示整数部分
	Int_To_Str(fla,Info);  //显示整数部分
	i = 0;
	while(Info[i] !='\0')
	{
		line7[6+i]=Info[i];
		i++;
	}
	line7[6+i]=0X2E;			   
	fla = fla - integar; //显示小数部分
	fla =  fla * 10;     //0.1                   						// 显示 0.1
	integar = (int) fla;
	fla = fla - integar;				 						// 改变fla的值,使fla总是小于1
	line7[7+i]= integar+0x30; 	
	fla =  fla*10;	    //0.01					 						// 显示 0.01
	integar = (int) fla;
	fla = fla - integar;					 					// 改变fla的值,使fla总是小于1
	line7[8+i]=integar+0x30 ;
	
    /***************************显示海拔高度部分**********************************************/
	fla=GPS.height_sea;
	integar = (int)fla;             							// 显示整数部分
	Int_To_Str(fla,Info);  //显示整数部分
	i = 0;
	while(Info[i] !='\0')
	{
		line8[6+i]=Info[i];
		i++;
	}
	line8[6+i]=0X2E;			   
	fla = fla - integar; //显示小数部分
	fla =  fla * 10;     //0.1                   						// 显示 0.1
	integar = (int) fla;
	fla = fla - integar;				 						// 改变fla的值,使fla总是小于1
	line8[7+i]= integar+0x30; 	
	fla =  fla*10;	    //0.01					 						// 显示 0.01
	integar = (int) fla;
	fla = fla - integar;					 					// 改变fla的值,使fla总是小于1
	line8[8+i]=integar+0x30 ;
	
	send_string(0,0,line5);
	send_string(0,1,line6);
	send_string(0,2,line7);
	send_string(0,3,line8);
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Copyright © 2010-2022 mfbz.cn 版权所有 |关于我们| 联系方式|豫ICP备15888888号