基于avr单片机做的gps定位仪
效果图如下:

下面是电路图工程文件大家可以自己修改
下面是所有的制作资料下载:
电路图文件
多用途定位仪(电路).zip
(973.64 KB, 下载次数: 90)
描述:多用途定位仪电路原理图、PCB源文件
源代码
多用途定位仪(程序).zip
(442.56 KB, 下载次数: 87)
描述:多用途定位仪源代码
文档:
手册与文档.7z
(5.17 MB, 下载次数: 99)
以下是部分预览(完整版请下载本帖附件):
通过GPS模块实现对当前时间、位置、速度、航向、海拔等数据的测量;采用HMC5883L三轴地磁传感器和ADXL345三轴加速度传感器实现电子罗盘功能,并能对磁偏角和倾角带来的误差进行补偿;采用12864显示屏对测量的数据进行显示;利用单片机和相关电路进行控制,完成对“基于GPS的多用途定位仪”的设计与制作。
1.可精确显示当前的日期、时间;
2.可测量并显示当前状态经纬度坐标值、海拔、地面高度、速度及航向;
3.可实现罗盘的功能对方向进行测量,并能对磁偏角和倾角进行带来的误差进行补偿,同时还可以测量并显示当前的倾角;
4.可做出实验样品进行展示;
摘要 摘要GPS是英文Global Positioning System(全球定位系统)的简称。由于GPS技术具有全天候、高精度和自动检测的特点,作为先进的测量手段和新的生产力在通信、通讯、气象、勘探、导航、遥感、大地测量、地球动力等众多领域得到极其广泛的应用。现在GPS的外形设计已经转向便携式发展,逐步踏入寻常百姓的生活中。 本次设计采用以GPS和电子罗盘相结合的方式,用电子罗盘来弥补GPS在静态和一些特殊自然环境下无法使用的缺陷,从而实现真正地多用途。设计以ATmega16单片机为控制核心,12864液晶显示屏为显示方式,采用了GPS模块(M-87)、HMC5883L三轴地磁传感器、ADXL345三轴加速度传感器从而实现了对时间、经纬度坐标、高度、海拔、速度、航向、方向、和倾角等数据的测量。本设计主要应用于航海、野外测量以及车辆的定位与导航等诸多方面。 目录 摘要 Abstract 第1章绪论 1.1 研究的背景及意义 1.2研究现状 1.2.2发展现状 1.3研究技术的发展方向及研究成果 1.3.1 GPS技术应用发展方向 1.3.2研究的主要方向 1.4本文的结构安排 第2章总体方案及硬件电路设计 2.1 系统框架 2.2总体设计思想 2.3单片机最小系统介绍 2.3.1 ATmega16单片机概述 2.3.2 ATmega16引脚介绍 2.4电源模块介绍 2.4.1 LM7805主要性能 2.5 12864显示模块介绍 2.5.1 12864概述 2.5.2 12864接口描述 2.6 GPS模块通信接口介绍 2.6.1 GPS模块简介 2.6.2串口通讯协议介绍 2.6.3单片机串口简介 2.7电子罗盘模块通信接口介绍 2.7.1 HMC5883L三轴地磁传感器介绍 2.7.2 ADXL345三轴加速度传感器介绍 2.7.3 I2C通信协议介绍 2.7.4单片机I2C通信介绍 2.8本章小结 第3章软件系统设计与编程 3.1 GPS部分软件设计 3.1.1 NMEA 0183协议介绍 3.1.2单片机数据接收与处理 3.2 电子罗盘部分软件设计 3.2.1 电子罗盘简介 3.2.2单片机数据接收与处理 3.2.3磁偏角补偿 3.2.4倾角补偿 3.2.5外部磁场干扰补偿补偿 3.3 主程序设计 3.4本章小结 第4章调试 4.1软件调试 4.1.1 单片机程序开发环境介绍 4.1.2单片机程序烧录环境介绍 4.1.3串口调试助手介绍 4.1.4 GPS模块辅助调试工具调试 4.2 硬件调试 4.2.1 PCB设计软件介绍 4.2.2实际电路调试 4.3本章小结 结论 参考文献 致谢 附录1 附录2 附录3 附录4 附录5
第1章绪论
1.1 研究的背景及意义GPS是英文Global Positioning System(全球定位系统)的简称。它的含义是利用卫星的测时和测距进行导航,以构成全球卫星定位系统。现在国际上公认将这一系统简称:GPS。 自古以来,人类从没有停止过对空间定位和导航的研究,从最简单的星历法,到指南针、航海表,一直到1978年2月22日第一颗GPS试验卫星的入轨运行,开创了以导航卫星为动态已知点的无线电导航定位的新时代。GPS卫星所发送的导航定位信号,是一种可供无数用户共享的空间信息资源。陆地、海洋和空间的广大用户,只要持有一种能够接收、跟踪、变换和测量GPS信号的接收机,就可以全天时、全天候和全球性地测量运动载体的七维状态参数和三维状态参数。其用途之广,影响之大,是任何其他无线电接收设备望尘莫及的。不仅如此,GPS卫星的入轨运行,还为大地测量学、地球动力学、地球物理学、天体力学、载人航天学、全球海洋学和全球气象学提供了一种高精度、全天时、全天候的测量新技术。
1.2.1 研究发展现状
(1)卫星系统的更新与多个卫星定位系统共存将明显改善卫星导航定位的精度和可靠性,广泛性更为明显。
(2)双频高精度测地型接收机将继续高度垄断在几个技术领先的GPS厂家手中,在一定时期内继续保持其绝对优势
(3)单频测地型接收机和导航接收机OEM板产业将扩散到世界各地生产,虽是低档次的GPS产品,但用途广、用户多、市场大。把GPS单频OEM板的生产技术也转让出口,因而推动了世界各地企业投资GPS-OEM的生产事业。
(4)陆地导航定位产品将成为发展最快的GPS产业。 1.3.2研究的主要方向由前文可见GPS技术已经延伸到各个领域的方方面面,它给我的生活带来相当多的便利。但当设备处于静止状态下或者比较偏僻的山区无法接收到GPS信号时就无法准确及时的测量出当前的方向。所以本设计在基于GPS强大优点的前提下,融合的电子罗盘的功能进而解决的GPS的一些弊端。本研究的主要方向是设计一个基于单片机的便携式GPS设备,能够测量常用的多种数据,且能适应诸多不同的环境和用途。 1.4本文的结构安排本文共分为4章,对项目的叙述结构安排如下: 第1章中结合项目背景与国内外GPS定位系统研究现状分析项目的选题依据,以研究意义等,同时对GPS系统做简单的介绍。 第2章主要介绍整个系统的硬件电路设计,包括单片机最小系统,电源模块,12864显示部分,GPS模块通信,电子罗盘模块通信等部分。 第3章主要介绍了软件系统的设计及程序的编写思想,包括GPS通信数据的解析,和电子罗盘数据的采集。 第4章主要介绍了整个调试过程中软件调试部分和硬件调试部分。
第2章总体方案及硬件电路设计
2.1 系统框架系统框架如图2-1所示:
系统整体电路如图2-2所示 2.2总体设计思想本项目所设计这款基于GPS的多用途定位仪主要包括六个部分:电源部分、12864显示部分、GPS模块部分、ATmega16单片机部分、HMC5883L三轴地磁传感器部分和ADXL345三轴加速度传感器部分,通过GPS模块实现对当前时间、位置、速度、航向、海拔等数据的测量;采用HMC5883L三轴地磁传感器和ADXL345三轴加速度传感器实现电子罗盘功能,即对方向的测量,并能对磁偏角和倾角带来的误差进行补偿;采用12864显示屏对测量的数据进行分屏显示;利用ATmega16单片机和相关电路对整个系统进行控制,从而完成对“基于GPS的多用途定位仪”的设计与制作。 2.3单片机最小系统介绍
本电路设计采用ATmega16单片机作为核心控制器,它的最小系统如图2-3所示,包括芯片、复位电路、时钟电路。该芯片为低电平复位,故复位电路设计为如图方式。芯片自带内部时钟,可以设置为1MHz、2MHz、4MHz、8MHz,单其内部时钟精度不高,故我们外接了外部时钟电路,采用8MHz频率石英晶振。 2.3.1 ATmega16单片机概述ATmega16是基于增强的AVR RISC结构的低功耗8 位CMOS微控制器。由于其先进的指令集以及单时钟周期指令执行时间,ATmega16 的数据吞吐率高达1 MIPS/MHz,从而可以减缓系统在功耗和处理速度之间的矛盾。它的AVR内核具有丰富的指令集和32个通用工作寄存器。所有的寄存器都直接与运算逻单元(ALU)相连接,使得一条指令可以在一个时钟周期内同时访问两个独立的寄存器。这种结构大大提高了代码效率,并且具有比普通的CISC微控制器最高至10倍的数据吞吐率。 ATmega16有如下特点:16K字节的系统内可编程Flash(具有同时读写的能力,即RWW),512字节EEPROM,1K字节SRAM,32个通用I/O 口线,32 个通用工作寄存器,用于边界扫描的JTAG接口,支持片内调试与编程,三个具有比较模式的灵活的定时器/ 计数器(T/C),片内/外中断,可编程串行USART,有起始条件检测器的通用串行接口,8路10位具有可选差分输入级可编程增益(TQFP 封装)的ADC ,具有片内振荡器的可编程看门狗定时器,一个SPI串行端口,以及六个可以通过软件进行选择的省电模式。 本芯片是以Atmel 高密度非易失性存储器技术生产的。片内ISP Flash 允许程序存储器通过ISP串行接口,或者通用编程器进行编程,也可以通过运行于AVR内核之中的引导程序进行编程。引导程序可以使用任意接口将应用程序下载到应用Flash存储区(ApplicationFlash Memory)。在更新应用Flash存储区时引导Flash区(Boot Flash Memory)的程序继续运行,实现了RWW 操作。通过将8位RISC CPU 与系统内可编程的Flash集成在一个芯片内, ATmega16成为一个功能强大的单片机,为许多嵌入式控制应用提供了灵活而低成本的解决方案。ATmega16具有一整套的编程与系统开发工具,包括:C语言编译器、宏汇编、程序调试器/ 软件仿真器、仿真器及评估板。
2.3.2 ATmega16引脚介绍图2-4 ATmega16单片机引脚图 图2-4为ATmega16单片机引脚图: (1)VCC 电源正 (2)GND 电源地 (3)端口A(PA7..PA0) 端口A 做为A/D转换器的模拟输入端。端口A 为8位双向I/O 口,具有可编程的内部上拉电阻。其输出缓冲器具有对称的驱动特性,可以输出和吸收大电流。作为输入使用时,若内部上拉电阻使能,端口被外部电路拉低时将输出电流。在复位过程中,即使系统时钟还未起振,端口A处于高阻状态。 (4)端口B(PB7..PB0) 端口B为8位双向I/O口,具有可编程的内部上拉电阻。其输出缓冲器具有对称的驱动特性,可以输出和吸收大电流。作为输入使用时,若内部上拉电阻使能,端口被外部电路拉低时将输出电流。在复位过程中,即使系统时钟还未起振,端口B处于高阻状态。端口B 也可以用做其他不同的特殊功能. (5)端口C(PC7..PC0)端口C为8位双向I/O口,具有可编程的内部上拉电阻。其输出缓冲器具有对称的驱动特性,可以输出和吸收大电流。作为输入使用时,若内部上拉电阻使能,端口被外部电路拉低时将输出电流。在复位过程中,即使系统时钟还未起振,端口C处于高阻状态。如果JTAG接口使能,即使复位出现引脚 PC5(TDI)、PC3(TMS)与PC2(TCK)的上拉电阻被激活。端口C也可以用做其他不同的特殊功能. (6)端口D(PD7..PD0)端口D为8位双向I/O口,具有可编程的内部上拉电阻。其输出缓冲器具有对称的驱动特性,可以输出和吸收大电流。作为输入使用时,若内部上拉电阻使能,则端口被外部电路拉低时将输出电流。在复位过程中,即使系统时钟还未起振,端口D处于高阻状态。端口D也可以用做其他不同的特殊功能. (7)RESET 复位输入引脚。持续时间超过最小门限时间的低电平将引起系统复位。持续时间小于门限间的脉冲不能保证可靠复位。 (8)XTAL1 反向振荡放大器与片内时钟操作电路的输入端。 (9)XTAL2 反向振荡放大器的输出端。 (10)AVCC AVCC是端口A与A/D转换器的电源。不使用ADC时,该引脚应直接与VCC连接。使用ADC时应通过一个低通滤波器与VCC连接。 (11)AREF A/D 的模拟基准输入引脚。 2.4电源模块介绍整个电路系统中,各个模块均可由5V供电正常工作,故统一采用5V供电以简化电路。设计采用稳压芯片LM7805作为电源稳压核心。电路如图2-5所示,输入可为6V~18V的直流电源,其中C1、C2为输入输出端的滤波电容,C3、C4为高频信号的耦合电容,可以改善负载的瞬态响应。
2.4.1 LM7805主要性能
LM7805是三端正电源稳压电路,它的封装形式为TO-220,如图2-6所示。它的应用非常广泛,内部有电流限制以及过热保护和安全工作区保护,使它基本上不会损坏。如果能提供足够的散热片,它就能偶提供大于1.5A的输出电流。
2.512864显示模块介绍本设计中显示部分采用12864显示模块,它与单片机采用并行连接方式,其电路接口如图2-7所示:
2.5.1 12864概述带中文字库的128X64是一种具有4位/8位并行、2线或3线串行多种接口方式,内部含有国标一级、二级简体中文字库的点阵图形液晶显示模块;其显示分辨率为128×64, 内置8192个16*16点汉字,和128个16*8点ASCII字符集.利用该模块灵活的接口方式和简单、方便的操作指令,可构成全中文人机交互图形界面。可以显示8×4行16×16点阵的汉字. 也可完成图形显示.低电压低功耗是其又一显著特点。由该模块构成的液晶显示方案与同类型的图形点阵液晶显示模块相比,不论硬件电路结构或显示程序都要简洁得多,且该模块的价格也略低于相同点阵的图形液晶模块。其基本特性: (1)低电源电压(VDD:+3.0--+5.5V) (2)显示分辨率:128×64点 (3)内置汉字字库,提供8192个16×16点阵汉字(简繁体可选) (4)内置128个16×8点阵字符 (5)2MHZ时钟频率 (6)显示方式:STN、半透、正显 (7)驱动方式:1/32DUTY,1/5BIAS (8)视角方向:6点 (9)背光方式:侧部高亮白色LED,功耗仅为普通LED的1/5—1/10 (10)通讯方式:串行、并口可选 (11)内置DC-DC转换电路,无需外加负压 (12)无需片选信号,简化软件设计 (13)工作温度: 0℃ - +55℃ ,存储温度: -20℃ - +60℃ 2.5.2 12864接口描述12864显示屏引脚数为20个,其引脚功能描述如图2-8所示:
图2-8 12864显示屏引脚介绍 2.6GPS模块通信接口介绍本设计采用的是集成的GPS接收模块HOLUX M-87,它采用串口通讯,每隔1秒钟更新一次数据,其电路连接方式如图2-9所示:
2.6.1 GPS模块简介本设计采用的GPS模块为HOLUX M-87如图2-10所示,它是一种根据低耗电Mediatek GPS 解决方案设计的超小型25.4 x 25.4 x 7mm GPS引擎机板。它对于导航应用提供高达 -159dBm的绝佳灵敏度与快速的第一次定位时间。M-89是内嵌在使用于GPS服务的PDA、PND、行动电话、可携式装置设计中的最佳选择。使用与汽车导航、船只导航、舰队管理、AVL和定位服务、自动导航、个人导航或旅游装置、追踪装置/系统和地图装置应用。它具有如下特点: - 采用MTK主芯片,可同时接收32个卫星,感度-158D。
- 更新速率: 1HZ
- 接收码: L1,C/A 码
- 时间标示: 1脉波/秒, GPS时间 +/-0.1秒误差
- 支持通讯协议:NMEA-0183 v2.2版本规格输出
- 芯片内建1920 次/频率硬件,提高接收传送搜寻卫星讯号
- 运算程序:ARM7/TDMI
- 处理速度:49 MHZ
- 内建闪存 4Mb
- 最低追踪信号感度:-142dBm
2.6.2串口通讯协议介绍串口是计算机上一种非常通用设备通信的协议。大多数计算机包含两个基于RS232的串口。串口同时也是仪器仪表设备通用的通信接口;很多GPIB兼容的设备也带有RS-232口。同时,串口通信协议也可以用于获取远程采集设备的数据。 串口通信的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。比如IEEE488定义并行通行状态时,规定设备线总长不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。 典型地,串口用于ASCII码字符的传输。通信使用3根线完成:地线,发送,接收。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但是不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通行的端口,这些参数必须匹配: a,波特率:这是一个衡量通信速度的参数。它表示每秒钟传送的bit的个数。例如300波特表示每秒钟发送300个bit。当我们提到时钟周期时,我们就是指波特率例如如果协议需要4800波特率,那么时钟是4800Hz。这意味着串口通信在数据线上的采样率为4800Hz。通常电话线的波特率为14400,28800和36600。波特率可以远远大于这些值,但是波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。 b,数据位:这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据不会是8位的,标准的值是5、7和8位。如何设置取决于你想传送的信息。比如,标准的ASCII码是0~127(7位)。扩展的ASCII码是0~255(8位)。如果数据使用简单的文本(标准ASCII码),那么每个数据包使用7位数据。每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。 c,停止位:用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。 d,奇偶校验位:在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。如果是奇校验,校验位为1,这样就有3个逻辑高位。高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。 2.6.3单片机串口简介ATmega16 单片机带有一个全双工的通用同步/异步串行收发模块USART,该接口是一个高度灵活的串行通讯设备。其主要特点如下: (1)全双工操作,可同时进行收发操作 (2)支持同步或异步操作 (3)支持5、6、7、8 和9 位数据位,1 位或者2 位停止位的串行数据帧结构 (4)三个完全独立的中断,TX 发送完成,TX 发送数据寄存器空,RX 接收完成 (5)支持多机通讯模式 ATmega16 单片机控制串口的相关寄存器有六个,分别是:数据寄存器(UDR)、控制和状态寄存器(UCSRA,UCSRB,UCSRC)、波特率寄存器(UBRRL 和UBRRH)。在进行通信之前首先要对USART 进行初始化。初始化过程通常包括波特率的设定,帧结构的设定,以及根据需要使能接收器或发送器。对于中断驱动的USART 操作,在初始化时首先要清零全局中断标志位( 全局中断被屏蔽)。 串口初始化流程:使用串口->使能接收 ->使能发送->波特率->奇偶校验->数据位数->中断。 2.7电子罗盘模块通信接口介绍本设计电子罗盘功能的实现是通过两个传感器,即HMC5883L三轴地磁传感器和ADXL345三轴加速度传感器。HMC5883L三轴地磁传感器负责对地球的磁场的测量以检测方向,ADXL345三轴加速度传感器则负责对地球重力的测量的检测用于实现对设备倾角的检测,进而对电子罗盘的参数做出倾角补偿来减小误差。HMC5883L和ADXL345均采用I2C通信方式,其在系统中的电路连接如图2-11所示:
2.7.1HMC5883L三轴地磁传感器介绍
霍尼韦尔 HMC5883L是一种表面贴装的高集成模块如图2-12所示,并带有数字接口的弱磁传感器芯片,应用于低成本罗盘和磁场检测领域。HMC5883L包括最先进的高分辨率HMC118X 系列磁阻传感器,并附带霍尼韦尔专利的集成电路包括放大器、自动消磁驱动器、偏差校准、能使罗盘精度控制在1~2°的12位模数转换器.简易的I2C 系列总线接口。HMC5883L是采用无铅表面封装技术,带有16 引脚,尺寸为3.0X3.0X0.9mm。HMC5883L的所应用领域有手机、笔记本电脑、消费类电子、汽车导航系统和个人导航系统。
HMC5883L采用霍尼韦尔各向异性磁阻(AMR)技术,该技术的优点是其他磁传感器技术所无法企及。这些各向异性传感器具有在轴向高灵敏度和线性高精度的特点.传感器带有的对于正交轴低敏感行的固相结构能用于测量地球磁场的方向和大小,其测量范围从毫高斯到8高斯(gauss)。霍尼韦尔的磁传感器在低磁场传感器行业中是灵敏度最高和可靠性最好的传感器。 它具有以下特点: (1)三轴磁阻传感器和ASIC 都被封装在3.0×3.0×0.9mm LCC 表面装配中 (2)12-bit ADC 与低干扰AMR 传感器,能在±8 高斯的磁场中实现5 毫高斯分辨率 (3)内置自检功能 (4)低电压工作(2.16-3.6V) 和超低功耗(100uA) (5)内置驱动电路,I2C 数字接口,无引线封装结构 (6)磁场范围广(+/-8Oe),最大输出频率可达160Hz (7)是体积小高集成产品。只需添加一个微处理器接口,外加两个外部SMT 电容。专为大批量、成本敏感的OEM 生产而设计,易于装配并与高速SMT 装配件兼容 (8)适用于电池供电的应用场合,带置位/复位和偏置驱动器用于消磁、自测和偏移补偿 (9)适用于消费类电子设备应用中通用双线串行数据接口,能应用于个人导航系统和LBS 2.7.2 ADXL345三轴加速度传感器介绍ADXL345是一款小而薄的超低功耗3轴加速度计,分辨率高(13位),测量范围达± 16g。数字输出数据为16位二进制补码格式,可通过SPI(3线或4线)或I2C数字接口访问。ADXL345非常适合移动设备应用。它可以在倾斜检测应用中测量静态重力加速度,还可以测量运动或冲击导致的动态加速度。其高分辨率(3.9mg/LSB),能够测量不到1度的倾斜角度变化。 该器件提供多种特殊检测功能。活动和非活动检测功能通过比较任意轴上的加速度与用户设置的阈值来检测有无运动发生。敲击检测功能可以检测任意方向的单振和双振动作。自由落体检测功能可以检测器件是否正在掉落。这些功能可以独立映射到两个中断输出引脚中的一个。正在申请专利的集成式存储器管理系统采用一个32级先进先出(FIFO)缓冲器,可用于存储数据,从而将主机处理器负荷降至最低,并降低整体系统功耗。 低功耗模式支持基于运动的智能电源管理,从而以极低的功耗进行阈值感测和运动加速度测量。ADXL345采用3 mm × 5 mm × 1 mm,14引脚小型超薄塑料封装。如图2-13所示:
它具有以下特性: - 超低功耗:VS = 2.5 V时(典型值),测量模式下低至23ìA,待机模式下为0.1_A
- 用户可选的分辨率:10位固定分辨率,全分辨率,分辨率随g范围提高而提高,±16g时高达13位
- SPI(3线和4线)和I2C数字接口
- 宽温度范围(-40°C至+85℃)
- 抗冲击能力:10,000 g
- 小而薄:3 mm× 5 mm× 1 mm,LGA封装
- 应用范围广:手机,医疗器械,游戏和定点设备,工业仪器仪表,个人导航设备
2.7.3 I2C通信协议介绍I2C(Inter -Integrated Circuit)总线是一种由Philips公司开发的两线式串行总线,用于连接微控制器及其外围设备。I2C总线产生于在80年代,最初为音频和视频设备开发。由于其简单性,如今方泛用于微控制器与各种功能模块的连接,可以说是学单片机的人,入门之后,必定要涉及到的。 I2C 总线实际上已经成为一个国际标准在超过100 种不同的IC 上实现,而且得到超过50 家公司的许可,正因为其简单和应用广泛,因此其功能也越来不满足人们的要求,其速度也从原来的100Kbit/S,增加了快速模式,其速度达 400Kbit/S,再后来也增加了高速模式,其速度更达3.4Mbit/S。 I2C 总线是一种用于IC器件之间连接的双向二线制总线,所谓总线它上面可以挂多少器件,并且通个两根线连接,占用空间非常的小,总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持4个组件。它的另一优点是多主控,只要能够进行接收和发送的设备都可以成为主控制器,当然多个主控不能同一时间工作。 I2C总线有两根信号线,一根为SDA(数据线),一根为SCL(时钟线)。任何时候时钟信号都是由主控器件产生。I2C总线在传送数据的过程中,主要有三种控制信号:起始信号,结不信号,应答信号: (1)起始信号:当SCL为高电平时,SDA由高电平转为低电平时,开始传送数据 (2)结束信号:当SCL为高电平时,SDA由低电平转为高电平时,结束数据传送 (3)应答信号:接收数据的器件在接收到8bit数据后,向发送数据的器件发出低电平信号,表示已收到数据。这个信号可以是主控器件发出,也可以是从动器件发出。总之由接收数据的器件发出。 2.7.4单片机I2C通信介绍ATmega16 单片机带有一个半双工的通用同步串行收发模块TWI(I2C),该接口是一个高度灵活的串行通讯设备。其主要特点如下: - 简单,但是强大而灵活的通讯接口,只需要两根线
- 支持主机和从机操作
- 器件可以工作于发送器模式或接收器模式
- 7 位地址空间允许有128 个从机
- 支持多主机仲裁
- 高达400 kHz 的数据传输率
- 可以抑制总线尖峰的噪声抑制器
- 完全可编程的从机地址以及公共地址
ATmega16 单片机控制I2C通信的相关寄存器有五个,分别是:比特率寄存器(TWBR)、控制寄存器(TWCR)、状态寄存器(TWSR)、数据寄存器(TWDR)、地址寄存器(TWAR)。在进行通信之前首先要对TWI(I2C)进行初始化。初始化过程通常包括波特率的设定,帧结构的设定,以及根据需要主机、从机模式的设置。对于中断驱动的I2C操作,在初始化时首先要清零全局中断标志位( 全局中断被屏蔽)。 TWI(I2C)通信发送流程如下: (1)设定数据传输波特率 ==》 《== 应答信号 (2)发送START信号,等待应答 ==》 《==应答信号 (3)发送芯片地址,等待应答 ==》 《==应答信号 (4)发送数据的绝对地址,等待应答 ==》 《==应答信号 (5)发送要写入的数据,等待应答 ==》 《==应答信号 (6)发送STOP信号,释放总线 ==》 数据写入成功 TWI(I2C)通信接收流程如下: (1)设定数据传输波特率 ==》 《== 应答信号 (2)发送START信号,等待应答 ==》 《==应答信号 (3)发送芯片地址,等待应答 ==》 《==应答信号 (4)发送数据的绝对地址,等待应答 ==》 《==应答信号 (5)发送RESTART信号,等待应答 ==》 《==应答信号 (6)发送芯片地址并注明读操作,等待应答 ==》 《==应答信号 (7)读取数据,等待应答 ==》 《==应答信号 (8)发送STOP信号,释放总线 ==》 数据读操作成功 2.8本章小结本章讲述了整体硬件电路的设计方案,先介绍了整个电路的整体框架,然后依次介绍了电路的单片机最小系统模块、电源模块、显示模块、GPS模块和电子罗盘模块,同时对相关的电子元件进行了简要介绍。
第3章软件系统设计与编程3.1 GPS部分软件设计GPS部分的软件设计主要是针对GPS模块发出的数据进行解析,提取出我们需要的数据。GPS模块的数据是以NEMA0183协议发出,故要想完成对数据的采集,必须掌握NEMA0183通信协议,同时将数据的格式进行转化,最终在12864显示屏上显示出来。 3.1.1 NMEA 0183协议介绍NMEA-0183是(National Marine Electronics Association)为海用电子设备制定的标准格式。它是在过去海用电子设备的标准格式0180和0182的基础上,增加了GPS接收机输出的内容而完成的。目前广泛采用的是Ver 2.00版本。现在除少数早期的GPS接收机外,几乎所有的GPS接收机均采用了这一格式。此协议是为了在不同的GPS导航设备中建立统一的RTCM标准。这种格式的广泛使用使得GPS接收模块的通用化和互换性大大提高。 这种格式所输出的语句采用的是ASCⅡ字符码,包含了纬度、经度、速度、日期、时间、航向、以及卫星信号情况等信息。语句多达10余种,由于在此次设计中只运用到了$GPRMC和$GPGGA定位数据语句,其结构为: $GPRMC,<1>,<2>,<2>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>*hh $GPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11>,<12>*hh 其中“GP”为交谈识别符;“RMC”为语句识别符;“GGA”为语句识别符;“hh”为校验和,其代表了“$”与“*”之间所有字符的按位异或值(不包括这两个字符)。 $GPRMC语句数据区的内容为: <1>定位点的协调世界时间(UTC),hhmmss(时分秒)格式; <2>定位状态,A=有效定位,V=无效定位; <3>定位点纬度,ddmm.mmmm(度分)格式; <4>纬度半球,N(北半球)或S(南半球); <5>定位点经度,dddmm.mmmm(度分)格式; <6>经度半球,E(东经)或W(西经); <7>地面速率,000.0节~999.9节; <8>地面航向,000.0度~359.9度; <9>UTC日期,ddmmyy(日月年)格式; <10>磁偏角,000.0度~180度; <11>磁偏角方向,E(东)或W(西)。 $GPGGA语句数据区的内容为: <1> UTC时间,hhmmss(时分秒)格式 <2>纬度ddmm.mmmm(度分)格式(前面的0也将被传输) <3>纬度半球N(北半球)或S(南半球) <4>经度dddmm.mmmm(度分)格式(前面的0也将被传输) <5>经度半球E(东经)或W(西经) <6> GPS状态:0=未定位,1=非差分定位,2=差分定位,6=正在估算 <7>正在使用解算位置的卫星数量(00~12)(前面的0也将被传输) <8> HDOP水平精度因子(0.5~99.9) <9>海拔高度(-9999.9~99999.9) <10>地球椭球面相对大地水准面的高度 <11>差分时间(从最近一次接收到差分信号开始的秒数,如果不是差分定位将为空 <12>差分站ID号0000~1023(前面的0也将被传输,如果不是差分定位将为空) 3.1.2单片机数据接收与处理经分析NMEA通讯协议所规定的通讯语句都已是以ASCII码为基础的,NMEA-0183协议语句的数据格式如下:“$”为语句起始标志;“,”为域分隔符;“ *”为校验和识别符,其后面的两位数为校验和,代表了“$”和“*”之间所有字符的按位异或值(不包括这两个字符);“/”为终止符,所有的语句必须以来结束,也就是ASCII 字符的“回车”(十六进制的0D)和“换行”(十六进制的0A)。 在单片机串口接收到数据后,先判别是否为语句引导头“$”,然后接收信息内容,在收到换行符后代表这一行的数据接收结束。然后再根据语句标识区分出信息类别以对收到的ASCII码进行处理显示。处理的内容有一些方面: 1.时间,这个是格林威治时间,是世界时间(UTC),我们需要把它转换成北京时间(BTC),BTC 和UTC 差了8 个小时,要在这个时间基础上加8 个小时。 2.定位状态,在接收到有效数据前,这个位是‘V’,后面的数据都为空,接到有效数据后,这个位是‘A’,后面才开始有数据。 3.纬度,我们需要把它转换成度分秒的格式,计算方法: 如接收到的纬度是:4546.40891 4546.40891 / 100 = 45.4640891 可以直接读出45 度 4546.40891–45 * 100 = 46.40891 可以直接读出46 分 46.40891–46 = 0.40891 * 60 = 24.5346 读出24 秒 所以纬度是:45 度46 分24 秒。 4.南北纬,这个位有两种值‘N’(北纬)和‘S’(南纬) 5.经度的计算方法和纬度的计算方法一样 6.东西经,这个位有两种值‘E’(东经)和‘W’(西经) 7.速率,这个速率值是海里/时,单位是节,要把它转换成千米/时,根据:1 海里=1.85 公里,把得到的速率乘以1.85。 8.航向,指的是偏离正北的角度 9.日期,这个日期是准确的,不需要转换 相关程序代码见附录5。 3.2 电子罗盘部分软件设计3.2.1 电子罗盘简介本设计采用HMC5883L三轴地磁传感器和ADXL345三轴加速度传感器共同实现电子罗盘的功能,如图3-1所示。三轴地磁传感器用来实现对地球磁场的测量,进而检测出当前的方向。三轴加速度传感器用来实现对当前设备倾角的测量,进而对电子罗盘进行倾角误差补偿。
3.2.2单片机数据接收与处理HMC5883L三轴地磁传感器和ADXL345三轴加速度感器均采用I2C通信。其中HMC5883L的写操作地址为0X3C,读操作地址为0X3D。ADXL345的写操作地址为0XA6,读操作地址为0XA7。 HMC5883L采用连续测量模式,在连续测量模式下,装置不断进行测量,并将数据更新至数据寄存器。RDY升高,此时新数据放置在所有三个寄存器。在上电或写入模式或配置寄存器后,第一次测量可以在三个数据输出寄存器经过一个2/fDO后设置,随后的测量可用一个频率fDO进行, fDO为数据输出的频率。该传感器一共有六个数据寄存器,地址从0X03到0X08,分别为X轴,Z轴,Y轴数据的高八位和低八位数据寄存器。ADXL345也采用连续测量模式,在该模式下,其内部数据数据不断更新,共有6个数据寄存器,地址从0X32到0X37,分别为X轴、Y轴、Z轴数据的低八位和高位。
地球的磁场强度大约为0.5至0.6高斯并且具有一个平行于地球表面的成份它始终指向磁北这是所有磁罗盘的制作基础此处的关键词是“平行于地球表面”和“磁北”地球磁场可用图3-2中所示的双极模型模拟表示该图图示了北半球中地球磁场向下指向北方在赤道处它水平指向北方并且在南半球中向上指向北方在任何情况下地球磁场的方向始终指向磁北被用来确定罗盘方向的正是这磁场中平行于地球表面的分量磁场与地球表面的夹角被称为磁倾角或倾角(如图3-3) 在北半球中磁倾角大约为朝北70°在确定方位角或罗盘指向时只使用地球磁场的X 和Y 分量地球磁场的垂直部分忽略不计,故方位角的计算公式为: 方位角=arcTan(y/x)(方位角为当前方向和正北方向的顺时针夹角)。
3.2.3磁偏角补偿磁偏角,即磁北线与真北线之间的夹角。根据规定,磁针指北极N向东偏则磁偏角为正,向西偏则磁偏角为负。经查表秦皇岛当地的磁偏角约为7.5度,故当方位角大于0小于352.5度时需加上7.5度,当方位角大于352.5度小于360度时需减去7.5度。程序如下所示: angle= atan2(Y_h,X_h) * 57.3 + 180; // angle in degrees
if(angle>=0&&angle<352.5)
angle=angle+7.5;
elseif(angle>=352.5&&angle<360)
angle=angle-352.5; 3.2.4倾角补偿大多数情况下不总是将罗盘限制在平面和水平面上它们通常用手安装在飞机或不平整地面上的汽车上由于罗盘并不总是水平于地球表面这使得确定方位角或行进方向变得更加困难由倾斜角产生的误差很大程度上取决于倾斜角的大小纠正罗盘倾斜的典型方法是使用倾角仪或倾斜传感器确定横滚角和俯仰角术语横滚和俯仰通常用在航空学上: 横滚是指围绕X 或前进方向的旋转俯仰是指围绕Y 或左-右方向的旋转。如图3-4所示:
为对罗盘的倾斜作补偿了解横滚和俯仰状况只是成功的一半此时磁力计必须依赖于所有的三条磁轴线(XYZ) 这样地球磁场可以完全转回到水平方向下图展示了以观察者或汽车的朝右或朝前水平方向为基准的罗盘的横滚角(θ)和俯仰角(φ) 运用下列旋转方程式可以将X Y 和Z 磁场强度读数换算回到水平面(XH, YH): XH=X*cos(φ)+Y*sin(θ)*sin(φ)-Z*cos(θ)*sin(φ) YH=Y*cos(θ)+Z*sin(θ) 方位角=arcTan(YH/XH) 3.2.5外部磁场干扰补偿补偿
当罗盘在没有任何铁质金属的空旷区域内工作时不会对地球磁场产生任何干扰然而事实上罗盘都被安装在附近很可能存在铁质材料的汽车飞机和平台里铁质金属效应将会干扰或弯曲地球磁场这会改变罗盘方向这种效应可看作是地球磁场中增加的一个磁场如果把罗盘牢固地装在汽车里就可算出铁效应并把它从磁场强度读数中减去。
图3-5显示了罗盘在水平面里作圆形旋转时的X和Y磁场强度读数在本示例中地球磁场没有受到铁的干扰读数取自霍尼韦尔HMR2300智能型数字磁力计其中每个计数代表67微高斯在X和Y平面中的地球磁场强度值读到2800个计数约为190毫高斯当用X 和Y 读数作图时就形成一个圆其中心在0,0点处对每个读数确定一个方位角此图显示了在旋转过程中根据X和Y方向的sine和cose输出值。
如果将磁力计安装在汽车上发动机和车体的影响将会干扰地球磁场驾驶汽车作环形运动就会产生如图3-6所示的曲线,请注意这里的XY图形不是一个圆(有点椭圆) 而它偏移0,0点为-480和-795个计数这偏移和椭圆效应是汽车对地球磁场固定干扰的结果这干扰可系统地确定并可将它们应用于随后的XY读数中以消除汽车的影响。 为补偿汽车的干扰可确定两个定标因数Xsf 和Ysf 来将椭圆改为圆,于是可计算偏移值Xoff 和Yoff 将圆中心定在0,0 原点在对汽车干扰作补偿时用来计算方位角的X Y 值如下: X 值=Xsf*X 读数+Xoff Y 值=Ysf*Y 读数+Yoff 可使用简单的标定(校准)方法来确定偏移和定标因数值: 1.把罗盘安装在汽车里并在水平面上驾车作环形运动 2.找出X和Y磁力读数的最大和最小值 3.用这四个数值确定X 和Y 定标因数(Xsf Ysf) 以及零偏移值(Xoff Yoff) Xsf=1 或(Y 最大-Y 最小)/(X 最大-X 最小) 以较大的数值为准 Ysf=1 或(X 最大-Y 最小)/(Y 最大-Y 最小) 以较大的数值为准 Xoff=[(X 最大-X 最小)/2-X 最大]*Xsf Yoff=[(Y 最大-Y 最小)/2-Y 最大]*Ysf 补偿的情况如图3-7所示:
3.3 主程序设计
主程序设计流程图如图3-8所示,具体程序见附录:
3.4本章小结本章讲述了整体软件设计方案,首先介绍了GPS模块通信程序的编写、相关测量数据的提取以及数据格式的转换,然后介绍了电子罗盘部分通信和数据处理程序的编写,并且对电子罗盘的磁偏角补偿、倾角补偿和外部磁场干扰补偿的方法进行的阐述,最后介绍了整体程序的设计思路。
第4章调试4.1软件调试在软件调试过程中,先后用到了ICCAVR开发环境,PROGISP烧程环境,在调试GPS模块时用到了串口调试助手和J-Nav GPSAnalyzer。 4.1.1 单片机程序开发环境介绍自ATMEL公司的AT90系列单片机诞生以来有很多第三方厂商为AT90系列开发了用于程序开发的C语言工具,ICCAVR就是ATMEL公司推荐的第三方C编译器之一。ICCAVR是一种符合ANSI标准的C语言来开发MCU(单片机)程序的一个工具,功能合适、使用方便、技术支持好,它主要有以下几个特点: 1.ICCAVR是一个综合了编辑器和工程管理器的集成工作环境(IDE); 2.源文件全部被组织到工程之中,文件的编辑和工程的构筑也在这个环境中完成,错误显示在状态窗口中,并且当你点击编译错误时,光标自动跳转到错误的那一行; 3.该工程管理器还能直接产生 INTEL HEX格式文件的烧写文件(该格式的文件可被大多数编程器所支持,可以直接下载到芯片中使用)和符合 AVRStudio的调试文件(COFF格式)。 4.ICCAVR是一个综合了编辑器和工程管理器的集成开发环境(IDE),可在Win XP和Win 7等环境下运行。开发界面如图4-1所示:
4.1.2单片机程序烧录环境介绍本设计采用ASP下载方式,使用的是超级下载工具PROGISP。该工具具有以下特性: 1.支持所有的AVR芯片的编程,支持AT89S51,AT89S52 2.支持自定义并口下载编程器 3.支持自定义串口的下载编程器 4.支持STK500编程器 5.支持USBASP编程器 6.支持并口的并行编程器 7.支持USBProg编程器 8.支持自定义编程芯片 9.支持自定义编程熔丝信息提示信息 10.支持USBProg的在线升级(通过USB口) 11.支持USBProg-C实现脱机下载 12.支持命令行方式,可以直接嵌入其他IDE中使用 13.绿色软件,无需安装,占用资源少 14.支持自定义汉化信息提示 其工作界面如图4-2所示:
4.1.3串口调试助手该软件一个很好而小巧的串口调试助手,支持常用的300-115200bps波特率,能设置校验、数据位和停止位,能以ASCII码或十六进制接收或发送任何数据或字符(包括中文),可以任意设定自动发送周期,并能将接收数据保存成文本文件,能发送任意大小的文本文件。
其工作界面如图4-3所示:
4.1.4 GPS模块辅助调试工具调试在GPS的调试过程中,本设计使用的是软件J-Nav GPSAnalyzer进行辅助调试的。该软件可以帮助我确定GPS模块是否正常工作,其工作界面如图4-4所示:
4.2 硬件调试4.2.1 PCB设计软件介绍Altium Designer 提供了唯一一款统一的应用方案,其综合电子产品一体化开发所需的所有必须技术和功能。Altium Designer 在单一设计环境中集成板级和FPGA系统设计、基于FPGA和分立处理器的嵌入式软件开发以及PCB版图设计、编辑和制造。并集成了现代设计数据管理功能,使得Altium Designer成为电子产品开发的完整解决方案-一个既满足当前,也满足未来开发需求的解决方案。
软件的工作界面如图4-5所示:
4.2.2实际电路调试在实际调试过程中,制作了多块实验电路板,该电路实现了预期的所有功能。图4-6为实验电路的正面:
图4-7为实验电路的背面:
图4-8为完整的实验电路板:
所有的数据分为三屏显示,第一屏显示时间和经纬度坐标,第二屏显示速度、航向、高度、海拔,第三屏显示方位角(即顺时针方向和正北方向的夹角)、X轴和Y轴的倾角。 图4-9为显示的第一屏数据:
图4-10为显示的第二屏数据:
图4-11为显示的第三屏的数据:
4.3本章小结本章介绍了整个设计的软件和硬件调试过程。软件调试部分介绍了单片机的开发环境、程序烧录环境、串口调试助手和GPS辅助调试软件及使用方法。硬件调试部分则介绍了PCB设计软件及实际制作的实验电路板的一些情况。
结论随着GPS技术的应用越来越广泛,GPS设备的普及速度也将大大加快,在我们国内GPS产业才刚刚起步,GPS产业的兴起势必也将大大的推进GPS技术在民间的应用。当前GPS技术已在各个领域发挥了至关重要重要的作用,为促进我们的生活和人类的发展作出了不可估量的贡献。 不过由于其自身技术的限制和一些特定环境的限制,使得GPS设备还存在种种的弊端。这次设计针对这些弊端提出一种解决思路,即采用GPS和电子罗盘相结合的方式,从而解决了在静态和特殊地理环境下GPS无法准确定位的情况,具有很大的使用价值。 所设计的多用途定位仪具有以下特点: 1.采用ATmega16单片机,采用5V电压工作,系统工作稳定,成本低廉。 2.采用LCD12864大屏幕进行中文显示,使得相关的测量数据的显示更加清晰易懂,各屏数据间只需一个按键即可相互切换。 3.应用范围广泛,由于测量显示的数据非常多,包括:时间、坐标、速度、航向、高度、海拔、方向和倾角。故该仪器可用航海、野外旅行、车载导航等诸多方面。 4.采用GPS加电子罗盘的方式克服了单纯的GPS设备在静态情况和没有GPS信号的情况下无法准确及时测量当前方向的问题。 综上所述,实验完成了预期的目标,不过由于时间和技术的原因,此系统设计还存在很多不足之处,如程序设计上缺乏灵活性、测量的精度上也有待提高、设备的耗电量也比较大、整体布局也有不合理的地方,今后将在这些方面进一步改进。
附录: 一、任务书中本阶段工作目标与任务要求 1.对ATmega16单片机的学习和使用; 2.学习并熟练在单片机上进行C语言程序的编写和调试; 3.完成对整个控制电路的设计与制作; 4.单片机和GPS模块、HMC5883L三轴地磁传感器以及ADXL345三轴加速度传感器的通信,并能将所需要的数据从中采集出来; 5.学习128*64显示屏的使用,并能将所需的数据进行显示; 6.寻找合适的算法,以解决外界各种干扰因素给电子罗盘和GPS带来的误差,尽可能提高设备的精度; 二、目前已完成任务情况 1.ATmega16,ICCAVR的学习和使用及相关单片机控制电路的设计
本设计采用ATmega16为控制核心,该芯片使用的开发环境为ICCAVR,图1为该软件的工作界面: 图1 ICCAVR开发环境工作环境 图2为当前设计的整体实验电路:
图2系统整体电路图 2.GPS,HMC5883L,ADXL345的使用并搭建实验电路,进行数据采集 图3为GPS模块和单片机的通信接口电路:
图3 GPS通信接口电路
图5为HMC5883L和ADXL345和单片机通信的接口电路: 图5电子罗盘接口电路 3.LCD屏128*64的使用并搭建实验电路进行显示实验
图6为12864显示屏的接口电路: 图6 12864接口电路
4.制作整体实验电路进行调试并根据结果对电路和程序进行整改 图7为制作的实际实验电路板: 图7实验电路板 三、存在的问题和拟解决方法 1.功耗问题,整个电路功耗较大:改良电路设计,寻找功耗更低的原件和显示屏,同时在程序上予以优化。 2.电子罗盘的精度问题:更加合理布局电路板,查阅资料,寻找更加合适的算法,从程序上对外界的干扰予以补偿以提高精度。
附录:gps信息提取程序:
- /*************************************************
- 函数名称:GPS_RMC_Parse
- 作用:提取$GPRMC的信息
- *************************************************/
- int GPS_RMC_Parse(char *line,GPS_INFO *GPS)
- {
- uchar ch,status,tmp;
- float lati_cent_tmp, lati_second_tmp;
- float long_cent_tmp, long_second_tmp;
- float speed_tmp;
- char *buf=line;
- ch=buf[5];
- status = buf[GetComma(2, buf)];
- if (ch == 'C') //如果第五个字符是C,($GPRMC)
- {
- if (status == 'A') //如果数据有效,则分析
- {
- GPS -> NS = buf[GetComma(4, buf)];
- GPS -> EW = buf[GetComma(6, buf)];
- GPS->latitude = Get_Double_Number(&buf[GetComma(3, buf)]);
- GPS->longitude = Get_Double_Number(&buf[GetComma( 5, buf)]);
- GPS->latitude_Degree = (int)GPS->latitude / 100; //分离纬度
- lati_cent_tmp = (GPS->latitude - GPS->latitude_Degree * 100);
- GPS->latitude_Cent = (int)lati_cent_tmp;
- lati_second_tmp = (lati_cent_tmp - GPS->latitude_Cent) * 60;
- GPS->latitude_Second = (int)lati_second_tmp;
- GPS->longitude_Degree = (int)GPS->longitude / 100; //分离经度
- long_cent_tmp = (GPS->longitude - GPS->longitude_Degree * 100);
- GPS->longitude_Cent = (int)long_cent_tmp;
- long_second_tmp = (long_cent_tmp - GPS->longitude_Cent) * 60;
- GPS->longitude_Second = (int)long_second_tmp;
- speed_tmp = Get_Float_Number(&buf[GetComma(7, buf)]); //速度(单位:海里/时)
- GPS->speed=speed_tmp* 1.85; //1海里=1.85公里
- GPS->direction = Get_Float_Number(&buf[GetComma(8, buf)]); //角度
- GPS->D.hour = (buf[7] - '0') * 10 + (buf[8] - '0'); //时间
- GPS->D.minute = (buf[9] - '0') * 10 + (buf[10] - '0');
- GPS->D.second = (buf[11] - '0') * 10 + (buf[12] - '0');
- tmp = GetComma(9, buf);
- GPS->D.day = (buf[tmp + 0] - '0') * 10 + (buf[tmp + 1] - '0'); //日期
- GPS->D.month = (buf[tmp + 2] - '0') * 10 + (buf[tmp + 3] - '0');
- GPS->D.year = (buf[tmp + 4] - '0') * 10 + (buf[tmp + 5] - '0')+2000;
-
- UTC2BTC(&GPS->D);
- return 1;
- }
- }
- return 0;
- }
- /************************************************
- 函数名称:GPS_GGA_Parse
- 作用:提取GPGGA的数据
- *************************************************/
- int GPS_GGA_Parse(char *line,GPS_INFO *GPS)
- {
- uchar ch, status;
- char *buf = line;
- ch = buf[4];
- status = buf[GetComma(2, buf)];
- if (ch == 'G') //$GPGGA
- {
- if (status != ',')//只有有数据就采集
- {
- GPS->height_sea = Get_Float_Number(&buf[GetComma(9, buf)]);
- GPS->height_ground = Get_Float_Number(&buf[GetComma(11, buf)]);
- return 1; //有数据返回1
- }
- }
- return 0; //无数据返回0
- }
- 2.系统主程序
- /*****************************************
- 中断名称: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 == '') //如果接收到换行
- {
- rev_buf[num] = '';
- rev_start = 0;
- rev_stop = 1;
- gps_flag = 1;
- num = 0;
- }
- }
- UCSRB|=BIT(RXCIE);
- }
- /***************************************
- 函数名称: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); //选择电源模式参考pdf24页
- I2C_write(ADXL_SLA_W,0x2E,0x80); //使能 DATA_READY 中断
- I2C_write(ADXL_SLA_W,0x2C,0x08); //速率设定为12.5 参考pdf13页
- 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) //如果接收完一行
- {
- 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;
- }
- }
- }
- 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] != '')
- {
- line1[0+i]=time[i];//显示年
- i++;
- }
- }
- /*******************显示月****************************/
- Int_To_Str(GPS.D.month,time);
- if(strlen(time)==2)
- {
- i = 0;
- while(time[i] != '')
- {
- line1[6+i]=time[i];
- i++;
- }
- }
- /*************************显示日*****************************/
- Int_To_Str(GPS.D.day,time);
- if(strlen(time)==2)
- {
- i = 0;
- while(time[i] != '')
- {
- line1[10+i]=time[i];
- i++;
- }
- }
- /**********************显示小时*************************/
- Int_To_Str(GPS.D.hour,time);
- if(strlen(time)==2)
- {
- i = 0;
- while(time[i] != '')
- {
- line2[0+i] =time[i];
- i++;
- }
- }
- /***********************显示分钟************************/
- Int_To_Str(GPS.D.minute,time);
- if(strlen(time)==2)
- {
- i = 0;
- while(time[i] != '')
- {
- line2[4+i]=time[i];
- i++;
- }
- }
-
- /**********************显示秒*********************/
- Int_To_Str(GPS.D.second,time);
- if(strlen(time)==2)
- {
- i = 0;
- while(time[i] != '')
- {
- 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] != '')
- {
- line3[6+i]=info[i];
- i++;
- }
- Int_To_Str(GPS.latitude_Cent,info); //纬分
- if(strlen(info)==2)
- { //只有正常显示纬分,才显示纬秒
- i = 0;
- while(info[i] != '')
- {
- line3[9+i]=info[i];
- i++;
- }
- Int_To_Str(GPS.latitude_Second,info); //纬秒
- if(strlen(info)==2)
- {
- i = 0;
- while(info[i] != '')
- {
- 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] != '')
- {
- line4[5+i]=info[i];
- i++;
- }
- Int_To_Str(GPS.longitude_Cent,info); //经分
- if(strlen(info)==2)
- {
- i = 0;
- while(info[i] != '')
- {
- line4[9+i]=info[i];
- i++;
- }
- Int_To_Str(GPS.longitude_Second,info); //经秒
- if(strlen(info)==2)
- {
- i = 0;
- while(info[i] != '')
- {
- 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] !='')
- {
- line5[5+i]=Info[i];
- i++;
- }
- line5[5+i]=0X2E;
- fla = fla - integar; //显示小数部分
- fla = fla * 10; // 显示 0.1
- integar = (int) fla;
- fla = fla - integar; // 改变fla的值,使fla总是小于1
- line5[6+i]= integar+0x30;
- fla = fla*10; // 显示 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] !='')
- {
- line6[6+i]=Info[i];
- i++;
- }
- line6[6+i]=0X2E;
- fla = fla - integar; //显示小数部分
- fla = fla * 10; // 显示 0.1
- integar = (int) fla;
- fla = fla - integar; // 改变fla的值,使fla总是小于1
- line6[7+i]= integar+0x30;
- fla = fla*10; // 显示 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] !='')
- {
- line7[6+i]=Info[i];
- i++;
- }
- line7[6+i]=0X2E;
- fla = fla - integar; //显示小数部分
- fla = fla * 10; // 显示 0.1
- integar = (int) fla;
- fla = fla - integar; // 改变fla的值,使fla总是小于1
- line7[7+i]= integar+0x30;
- fla = fla*10; // 显示 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] !='')
- {
- line8[6+i]=Info[i];
- i++;
- }
- line8[6+i]=0X2E;
- fla = fla - integar; //显示小数部分
- fla = fla * 10; // 显示 0.1
- integar = (int) fla;
- fla = fla - integar; // 改变fla的值,使fla总是小于1
- line8[7+i]= integar+0x30;
- fla = fla*10; // 显示 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);
- }
复制代码
|