视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
电子指南针设计报告(正文)
2025-09-29 17:12:23 责编:小OO
文档
目  录

1.前 言

指南针是用以判别方位的一种简单仪器,是一种重要的导航工具,可应用在多种场合中。指南针的前身是中国古代四大发明之一的司南。主要组成部分是一根装在轴上可以自由转动的磁针。磁针在地磁场作用下能保持在磁子午线的切线方向上。磁针的北极指向地理的北极,利用这一性能可以辨别方向。常用于航海、大地测量等方面。

随着人们对指南针原理认识的不断深入,指南针也由先前笨重的“司南”发展到现在的便携式的指南针。但其基本构造是没有改变的,都是属于机械的指针式,其指示的机械结构基本上没有改变,都是利用某种支撑使得磁针能够受到地磁场的影响而自由的旋转。由于机械的先天因素导致了指针式指南针在便携性、灵敏度、精度以及使用寿命上都有一定的。由于国内外电子技术的飞速发展,特别是在磁传感器和专用芯片上的发展使能指南针的基本实现机理有了质的改变,不再是机械结构而采用了磁场传感器和专用处理器对磁场进行测量和处理后指示方向,这就是当前应用较为广泛的电子式指南针。

电子指南针内部结构固定,没有移动部分,可以简单地和其它电子系统接口,因此可代替旧的磁指南针。并以精度高、稳定性好等特点得到了广泛运用。本设计采用Honeywell公司的各向异性磁阻(AMR)传感器芯片HMC5883L。霍尼韦尔HMC5883L是一种表面贴装的高集成模块,并带有数字接口的弱磁传感器芯片,HMC5883L包括最先进的高分辨率HMC118X系列磁阻传感器,并附带霍尼韦尔专利的集成电路包括放大器、自动消磁驱动器、偏差校准、能使指南针精度控制在1°~2°的12位模数转换器。简易的I2C系列总线接口。HMC5883L采用霍各向异性磁阻(AMR)技术,该技术领先于这些各向异性传感器具有在轴向高灵敏度和线性高精度的特点。传感器具有的对正交轴的低灵敏度的固相结构能用于测量地球磁场的方向和大小,其测量范围从负8高斯到 8 高斯(gauss)。本文介绍了电子指南针的工作原理及电路硬件及软件的设计,同时给出了其抗干扰设计以及信号和数据的处理方法。

2.总体方案设计

如今电子技术发展飞速,电子指南针的设计也存在着多种方案选择,每种方案各有所长,因此我们要根据自己的实际情况选择相应的硬什设备进行电路设计。

2.1 传感器方案论证与选择

方案一:利用两轴磁传感器HMC1052

HMC1052是一个双轴线性磁传感器,和其它HMC10XX系列传感器一样,每个传感器都有一个由磁阻薄膜合金组成的惠斯通桥。当桥路加上供电电压,传感器将磁场强度转化为电压输出,包括环境磁场和测量磁场。HMC1052包含两个敏感元件,它们的敏感轴互相垂直。敏感元件A和B,共存于单硅芯片中,完全正交,且参数匹配。HMC1052的尺寸小,低工作电压,而且消除了两个敏感元件引起的非正误差。除了惠斯通电桥,HMC1052有两个位于芯片上的磁耦合带,偏置带和置位/复位带。敏感元件A和B,都有这两个带。置位/复位带,用于确保精度。偏置带,用于校正传感器,或偏置任何不想要的磁场。在标准的10针外形(MSOP)中,两个敏感元件可以上电,用于减少功耗。然而,却不能使用偏置带。若需要偏置带,可以用另一种封装的HMC1052。

图2.1 HMC1052传感器引脚图

方案二:采用Philips公司生产的KMZ52感应磁场传感器

KMZ52是Philips公司生产的一种磁阻传感器,是利用坡莫合金薄片的磁阻效应测量磁场的高灵敏度磁阻传感器。该磁阻传感器内置两个正交磁敏电阻桥、完整的补偿线圈和设置/复位线圈。补偿线圈的输出与当前测量结果形成闭环反馈,使传感器的灵敏度不受地域。这种磁阻传感器主要应用于导航、通用地磁测量和交通检测。该磁阻传感器在金属铝的表面沉积了一定厚度的高磁导率的坡莫合金,在翻转线圈和外界磁场两个力的作用下,电子改变运动方向,使得磁敏电阻的阻值发生变化。同时KMZ52的斑马条电阻成45°放置,这使得电子在正反向磁场力作用下有较好的对称性。由于加入了翻转磁场,KMZ52的变化曲线与普通的磁敏电阻不同,更加线性化。KMZ52磁阻传感器的核心部分是惠斯通电桥,是由4个磁敏感元件组成的磁阻桥臂。磁敏感元件由长而薄的坡莫合金薄膜制成。在外加磁场的作用下,磁阻的变化引起输出电压的变化。

图2.2 KMZ52传感器引脚图

方案三:使用霍尼韦尔HMC5883L各向异性磁阻传感电路

霍尼韦尔 HMC5883L 是一种表面贴装的高集成模块,并带有数字接口的弱磁传感器芯片,应用于低成本罗盘和磁场检测领域。HMC5883L 包括最先进的高分辨率HMC118X系列磁阻传感器,并附带霍尼韦尔专利的集成电路包括放大器、自动消磁驱动器、偏差校准、能使罗盘精度控制在1°~2°的12位模数转换器。简易的I2C 系列总线接口。HMC5883L 是采用无铅表面封装技术,带有16 引脚,尺寸为3.0×3.0×0.9mm。HMC5883L 的所应用领域有手机、笔记本电脑、消费类电子、汽车导航系统和个人导航系统。HMC5883L采用霍尼韦尔各向异性磁阻(AMR)技术,该技术领先于其他磁传感器技术。这些各向异性传感器具有在轴向高灵敏度和线性高精度的特点.传感器具有的对正交轴的低灵敏度的固相结构能用于测量地球磁场的方向和大小,其测量范围从毫高斯到8高斯(gauss)。霍尼韦尔的磁传感器在低磁场传感器行业中是灵敏度最高和可靠性最好的传感器。

图2.3 HMC5883L传感器引脚图

通过对比各传感器特点我们了解到它们的优缺点,HMC5883L三轴磁阻传感器和ASIC都被封装在一起了,不需要外接ASIC,而12-bit ADC与低干扰AMR传感器,能在±8高斯的磁场中实现2毫高斯的分辨率,且内置驱动器,显得更为优越。霍尼韦尔的磁传感器在低磁场传感器行业中是灵敏度最高和可靠性最好的传感器。综上我们选择传感器方案三,使用霍尼韦尔HMC5883L各向异性磁阻传感电路。

2.2 单片机方案选择

STC12C5A60S2/AD/PWM系列单片机是宏晶科技生产的单时钟/机器周期(1T)的单片机,是高速/低功耗/超强抗干扰的新一代8051单片机,指令代码完全兼容传统8051,但速度快8-12倍。内部集成MAX810专用复位电路,2路PWM,8路高速10位A/D转换(250K/S),针对电机控制,强干扰场合。

1.增强型8051 CPU,1T,单时钟/机器周期,指令代码完全兼容传统8051;

2.工作电压:STC12C5A60S2系列工作电压:5.5V-3.3V(5V单片机)STC12LE5A60S2系列工作电压:3.6V-2.2V(3V单片机);

3.工作频率范围:0-35MHz,相当于普通8051的0~420MHz;

4.用户应用程序空间8K /16K / 20K / 32K / 40K / 48K / 52K / 60K / 62K字节;

5.片上集成1280字节RAM;

6.通用I/O口(36/40/44个),复位后为:准双向口/弱上拉(普通8051传统I/O口),可设置成四种模式:准双向口/弱上拉,推挽/强上拉,仅为输入/高阻,开漏,每个I/O口驱动能力均可达到20mA,但整个芯片最大不要超过55Ma;

7. ISP(在系统可编程)/IAP(在应用可编程),无需专用编程器,无需专用仿真器,可通过串口(P3.0/P3.1)直接下载用户程序,数秒即可完成一片;

8.有EEPROM功能(STC12C5A62S2/AD/PWM无内部EEPROM);

9.看门狗;

10.内部集成MAX810专用复位电路(外部晶体12M以下时,复位脚可直接1K电阻到地);

11.外部掉电检测电路:在P4.6口有一个低压门槛比较器,5V单片机为1.32V,误差为+/-5%,3.3V单片机为1.30V,误差为+/-3%;

12.时钟源:外部高精度晶体/时钟,内部R/C振荡器(温漂为+/-5%到+/-10%以内) 1用户在下载用户程序时,可选择是使用内部R/C振荡器还是外部晶体/时钟,常温下内部R/C振荡器频率为:5.0V单片机为:11MHz~15.5MHz,3.3V单片机为:8MHz~12MHz,精度要求不高时,可选择使用内部时钟,但因为有制造误差和温漂,以实际测试为准;

13.共4个16位定时器   两个与传统8051兼容的定时器/计数器,16位定时器T0和T1,没有定时器2,但有波特率发生器   做串行通讯的波特率发生器   再加上2路PCA模块可再实现2个16位定时器;

14. 2个时钟输出口,可由T0的溢出在P3.4/T0输出时钟,可由T1的溢出在P3.5/T1输出时钟;

15.外部中断I/O口7路,传统的下降沿中断或低电平触发中断,并新增支持上升沿中断的PCA模块, Power Down模式可由外部中断唤醒,INT0/P3.2,INT1/P3.3,T0/P3.4, T1/P3.5, RxD/P3.0,CCP0/P1.3(也可通过寄存器设置到P4.2 ), CCP1/P1.4 (也可通过寄存器设置到P4.3);

16. PWM(2路)/PCA(可编程计数器阵列,2路):

——也可用来当2路D/A使用

——也可用来再实现2个定时器

——也可用来再实现2个外部中断(上升沿中断/下降沿中断均可分别或同时支持);

17.A/D转换, 10位精度ADC,共8路,转换速度可达250K/S(每秒钟25万次)18.通用全双工异步串行口(UART),由于STC12系列是高速的8051,可再用定时器或PCA软件实现多串口;

19. STC12C5A60S2系列有双串口,后缀有S2标志的才有双串口,RxD2/P1.2(可通过寄存器设置到P4.2),TxD2/P1.3(可通过寄存器设置到P4.3);

20.工作温度范围:-40 - +85℃(工业级) / 0 - 75℃(商业级)21.封装:PDIP-40,LQFP-44,LQFP-48  I/O口不够时,可用2到3根普通I/O口线外接  74HC1/165/595(均可级联)来扩展I/O口,还可用A/D做按键扫描来节省I/O口,或用双CPU,三线通信,还多了串口。

2.3 总体方案设计思想及框图

下图是地球某一点的地球磁场向量He的三维图,其中x轴和y轴与地球表面平行,x为前进方向,y为水平面上垂直x的方向,He为地磁场强度,Hex、Hey分别为He在x、y方向的水平分量,α为前进方向与磁场北极的夹角,称做方位角;λ为磁偏角,可以通过查表得知。x轴与南极的实际夹角大小为(α+λ)。从而只要得到方位角α的大小即可得知该水平面方位。由图可知tanα=Hey/Hex,所以只要求出y、x轴上的磁场强度之比Hey/Hex,即可得到方位角α的正切值。δ为磁倾角,He与水下面的夹角,可以用来校正水平面。磁场传感器可以分别测量Hex、Hey、Hez,并将其大小转化为相应强弱的电信号。但本系统并只做了X和Y方向的测量。由于考虑到时间安排有限,Z方向暂时不做,但本系统设计只要平拿平放并不影响测量结果的准确性。

图2.4 测量原理分析图

通过以上测量分析思路所得传感器信号,经过单片机数据预处理和算法补偿后在上传到LCD1602A液晶屏上显示。结合以上各方案选择及设计思路可得出以下总体方案框图。

图2.5 总体方案设计框图

3.硬件电路设计

对于一个完整的电子设计来讲,首要问题就是为整个系统提供电源供电模块,电源电路的稳定可靠是系统平稳运行的前提和基础。电子设备除用电池供电外,还采用市电(交流电网)供电。通过变压、整流、滤波和稳压后,得到稳定的直流电。本次系统采用干电池供电,在此不在赘述此稳压电源电路原理。

3.1 单片机最小系统

要使单片机工作起来,最基本的电路的构成由单片机、时钟电路、复位电路等组成。单片机最小系统如下图3.1所示。

时钟电路:本系统采用单片机内部方式产生时钟信号,用于外接一个12MHz石英晶体振荡器和2个30pF微调电容,构成稳定的的自激振荡器,其发出的脉冲直接送入内部的时钟电路。

复位电路:确定单片机工作的起始状态,完成单片机的启动过程。单片机系统的复位方式有上电自动复位和手动按键复位。本设计采用手动按键复位,该复位方式同样具有上电自动复位功能。电路如下图所示。

图3.1 单片机最小系统

3.2 串口电路

串口电路为单片提供与PC机连接端口,为单片机提供下载程序到单片机程序存储器中。串口原理图如图3-2所示。

串口也称串行通信接口,RS-232是目前最常用的一种串行通讯接口,由于其形状和针脚数量的原因,其接头又被称为DB9接头。RS-232针脚定义: 2 RXD ← Receive Data 接收数据 、3 TXD → Transmit Data 发送数据 、5 GND — System Ground 系统接地,一般就用到这几个引脚

MAX232芯片是专门为电脑的RS-232标准串口设计的单电源电平转换芯片,使用+5v单电源供电。

MAX23内部结构基本可分三个部分:

第一部分是电荷泵电路:由1、2、3、4、5、6脚和4只电容构成,功能是产生+12v和-12v两个电源,提供给RS-232串口电平的需要。

第二部分是数据转换通道:由7、8、9、10、11、12、13、14脚构成两个数据通道,

其中13脚(R1IN)、12脚(R1OUT)、11脚(T1IN)、14脚(T1OUT)为第一数据通

图3.2 串口原理图

道,其中13脚(R1IN)、12脚(R1OUT)、11脚(T1IN)、14脚(T1OUT)为第一数据通道,8脚(R2IN)、9脚(R2OUT)、10脚(T2IN)、7脚(T2OUT)为第二数据通道。TTL/CMOS数据从T1IN、T2IN输入转换成RS-232数据从T1OUT、T2OUT送到电脑DP9插头;DP9插头的RS-232数据从R1IN、R2IN输入转换成TTL/CMOS数据后从R1OUT、R2OUT输出

第三部分是供电:15脚DNG、16脚VCC(+5v)。

3.3 HMC5883L传感器模块

1.工作原理

霍尼韦尔HMC5883L磁阻传感器电路是三轴传感器并应用特殊辅助电路来测量磁场。通过施加供电电源,传感器可以将量测轴方向上的任何入射磁场转变成一种差分电压输出。磁阻传感器是由一个镍铁(坡莫合金)薄膜放置在硅片上,并构成一个带式电阻元件。在磁场存在的情况下,桥式电阻元件的变化将引起跨电桥输出电压的相应变化。这些磁阻元件两两对齐,形成一个共同的感应轴(如引脚图上的箭头所示),随着磁场在感应方向上不断增强,电压也会正向增长。因为输出只与沿轴方向上的磁阻元件成比例,其他磁阻电桥也放置在正交方向上,就能精密测量其他方向的磁场强度。

2.电源管理

该器件可有两种不同的供电模式。第一个是内部运作的VDD供电电源,第二个是为IO接口供电的VDDIO电源,当然VDDIO的电压可以与VDD电源相近;单电源模式,或在VDDIO 电压低于VDD 的情况下,HMC5883L都能正常运作并能与其他装置兼容。

图3.3 HMC5883L内部示意图

3.I²C接口

控制该装置可以通过I²C总线来实现。该装置将作为从机在一个主机(例如:处理器)的控制下连接总线。该装置必须符合I2C-Bus Specification(I2C-总线技术规格标准),作为一个I2C 兼容装置,该装置包含一个7-bit串行地址,并支持I2C 协议。这一装置可以支持标准和快速模式,分别为100kHz和400kHz,但不支持高速模式(Hs)。还需要外接电阻才能支持这些标准和快速模式。要求主机的活动(寄存器的读取和写入)优先于内部活动,例如:测量。这一优先次序的安排是为了不让主机等待,同时I²C总线占用的时间比必需的时间长。

4.置位/复位带驱动的H-桥式电路

ASIC包含大型开关FETs,可以传输大而短的脉冲到传感器的置位/复位带。这一置位/复位带在很大程度上是一种电阻性负载。并不需要外部去增加外部置位/复位回路。每次测量时,ASIC会自动完成置位/复位。首先一次置位脉冲产生后进行测量,然后,一次复位脉冲产生后进行测量,两次测量的差值的一半将会被放置在三轴上每根轴的数据输出寄存器上。这样,在所有测量中传感器的内部偏差和温度漂移差值就可以被移除/抵消了。

5.寄存器访问

下面表格列出了寄存器及其访问。所有地址为8 bits。

表3.1 寄存器列表

地址名称访问
00配置寄存器 A

读/写

01配置寄存器 B

读/写

02模式寄存器读/写

03数据输出 X MSB 寄存器

04数据输出 X LSB 寄存器

05数据输出 Z MSB寄存器

06数据输出 Z LSB 寄存器

07数据输出 Y MSB 寄存器

08数据输出 Y LSB 寄存器

09状态寄存器
10识别寄存器 A

11识别寄存器 B

12识别寄存器 C

这里介绍读取和写入此装置的过程。该装置使用地址指针来显示该寄存器地点是被读取或写入。这些指针位置从主机发出到从机并成功获得的7位地址加1 位读/写标识符。为了尽量减少主机和装置之间的通信,无主机干预下地址指针自动更新。寄存器指示器被读取后将自动的在目前被成功读取的寄存器的地址上加1。地址指针本身不能通过I2C总线被读取。任何试图去读取不存在的地址返回为0s,任何去写不存在的地址或者是未定义的bit写入定义的地址都将会被该装置予以忽略。为将地址指针移到随机存储器位置,首先发出一个“写”到寄存器地址,在指令后不带数据位。例如,要让地址指针指向寄存器10,发出的指令为0x3C 0x0A。其与单片机的连线图如下图所示。

图3.3 传感器模块连线图

3.4 LCD1602液晶屏模块

1602液晶也叫1602字符型液晶它是一种专门用来显示字母、数字、符号等的点阵型液晶模块它有若干个5×7或者5×11等点阵字符位组成,每个点阵字符位都可以显示一个字符。每位之间有一个点距的间隔每行之间也有间隔起到了字符间距和行间距的作用,正因为如此所以他不能显示图形。1602LCD是指显示的内容为16×2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。其引脚图和引脚说明如下:

图3.4 LCD1602引脚图

第1脚:VSS为电源地。

第2脚:VDD接5V电源正极。

第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高(对比度过高时会 产生“鬼影”,使用时可以通过一个10K的电位器调整对比度)。

第4脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。

第5脚:RW为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。 

第6脚:E(或EN)端为使能(enable)端。

第7~14脚:D0~D7为8位双向数据端。

第15~16脚:空脚或背灯电源。15脚背光正极,16脚背光负极。

LCD1602内置了DDRAM(显示数据存储RAM)、CGROM(字符存储ROM)和CGRAM(用户自定义RAM)。DDRAM就是显示数据RAM,用来寄存待显示的字符代码。共80个字节,其地址和屏幕的对应关系如下表: 

图3.5 RAM地址映射图

1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如附录C所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,也就是说想要在LCD1602屏幕的第一行第一列显示一个“A”字,就要向DDRAM的00H地址写入“A”的代码就行了,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。

其基本操作时序: 

读状态输入:RS=L,RW=H,E=H                        输出:DB0~DB7=状态字

写指令输入:RS=L,RW=L,E=下降沿脉冲,DB0~DB7=指令码        输出:无

读数据输入:RS=H,RW=H,E=H                        输出:DB0~DB7=数据

写数据输入:RS=H,RW=L,E=下降沿脉冲,DB0~DB7=数据            输出:无

图3.6 读操作时序

图3.7 写操作时序

数据指针设置:

表3.2 数据指针设置表

指令码功能
80H+地址码(0-27H,40H-67H)

设置数据地址指针
在1602中我们就用前16个就行了,第二行也一样用前16个地址。我们往DDRAM里的00H地址处送一个数据,譬如0x31(数字1的代码)并不能显示1出来。这是令初学者很容易出错的地方,原因就是如果你要想在DDRAM的00H地址处显示数据,则必须将00H加上80H,即0x80+0x00,若要在DDRAM的01H处显示数据,则必须将01H加上80H即0x80+0x01,依次类推。

在此,LCD1602用法及注意事项就简单的介绍到这里,1062从CGROM表上可以看到,表里面实际还有8个字节可用。如果我们要想显示这8个用户自定义的字符,操作方法和显示CGROM的一样,先设置DDRAM位置,再向DDRAM写入字符码,显示是直接取CGRAM的数据。这里没用用到在此不在赘述起原理方法。下面是1602与单片机的连线图。

图3-8 LCD1602模块连线图

4.软件设计

4.1 HMC5883L与单片机通信软件设计

    HMC5883L是一款集成IIC总线借口的数字传感器,而STC12单片机没有IIC接口,所以采用在单片机上模拟IIC通讯时序与HMC5883L进行通信,而HMC5883L可以采用单字节读取和多字节读取方式,在本设计中采用的是多字节读取方式,一次将XYZ的值读到单片机内,具体通信软件设计思路如下:

图4.1 HMC5883L模块与单片机通信软件流程图

4.2 LCD1602人机界面软件设计

    本设计采用LCD1602作为显示设备,显示的信息包括当前方位信息与与地理南极的夹角信息(角度制)。我们从HMC5883L得出地磁方向在X与Y轴上的磁场强度分量,采用atan2( )这个函数得出其与地理北极之间的夹角(弧度),再通过弧度到角度的转换,得到角度值,最后加上180°,使其变为与南极之间的夹角,而且所有值变为正数,方便处理。得到度数后,根据我们预先设定好的角度范围,判断当前所在哪个方位,并在LCD1602上显示,然后将其乘以10倍,变为整数,通过转换,在LCD1602上显示与南极夹角的值,具体设计思路如下:

图4.2 LCD1602人机界面软件流程图

4.3 系统总统软件设计

    本设计的软件设计总体思路是将HMC5883L得到的信息送至单片机内进行处理,再转换为液晶显示数据在LCD1602上进行显示,得到当前的方位信息与角度信息,由于硬件模块较少,所以很大部分工作放在了软件上,STC12单片机是一款1T单片机,晶振为22.1184MHZ,处理速度较快,在延时上不好把握,用定时器又太浪费资源,而本设计在一些模块时序上对延时有一定要求,所以本设计借用了别人验证好的一套运用在STC12单片机上的延时函数集,确保系统的正常运行。思路上采用每读完一次数据,就立即送至液晶显示的实时方式。具体流程图如下:

图4.3 系统总体软件流程图

5.系统调试

    STC12LE系列低功耗单片机的正常电压为3.3V,但LCD1602液晶的对比度电压要高于5V才能看出显示效果,最初采用3.3V供给整个系统的时候,发现液晶上无显示,后来将系统电源调至5V,LCD1602就可以正常显示了,而经测试,STC12LE单片机是可以在5V条件下进行工作的。在方向的确定上,我们结合手机上自带的电子罗盘对设计进行调试,校准HMC5883L模块的方向,最后用胶固定到PCB板上。

图5.1 液晶显示图

图5.2 整体硬件调试图

6.结论

该电子指南针设计模块简单,可集成性好,测量偏差0.1°,可以用于航海、山地探索的方向判定,而采用低功耗单片机增强了该设备的续航能力。但LCD1602液晶为单色字符液晶,显示能力有限,如果采用更高级的嵌入式处理器,拥有足够的速度和存储器,可以采用TFT液晶等较好的显示设备,将人机界面做得更加完善。本设计中HMC5883L传感器只用到了X与Y的值,即只能在系统水被平放置时才能较为精确地测量,非常不方便,如果能结合加速度传感器与HMC5883L中Z轴的值做三维方向的判定,就可以让系统在任意姿态下判断当前的位置信息。

在设计中,模拟IIC通讯是非常重要的软件设计环节,软件的优化可以为通信节省更多的资源和时间,我们采用了51单片机状态寄存器的CY位作为通信数据位进行数据交换,免去重新在RAM里定义数据变量,做到了一个资源优化。在液晶显示中,上一次显示的数据如果不能被下次显示的数据覆盖掉,就要及时清除,而如果采用命令清屏,就会使屏幕闪烁很厉害,所以我们才用用空格字符覆盖的方式,及时清除上一次显示的内容,方便下次数据的显示。在以后的实践中,应当注意这些软件设计上的问题,让系统运行更加稳定流畅。

7.总结与体会

在经过几周的不懈努力中,终于完成了本次智能化电子系统设计的任务。通过本设计锻炼了我们的实践能力,也是对以后我们实际工作能力的训练和考察过程。现在是一个高科技的时代,单片机的应用无处不在,这更坚定了我要学好单片机的决心。

本设计本身就比较简单,整个设计的过程中每一步都是大家亲自做过的,在经过遇到问题,思索问题到解决问题的过程中,收获是最多的。本设计重点在程序代码上,通过上网查资料对每一个模块元器件的用法一一了解清楚,最后通过对个元器件工作原理以及指令控制命令最整个设计程序进行编写。在设计程序时,不能妄想一次就将整个程序设计好,反复修改、不断改进是程序设计的必经之路,要养成注释程序的好习惯,一个程序的完美与否不仅仅是实现功能,而应该让人一看就能明白你的思路,这样也为交流提供了方便,为以后编程打下基础。

由本次课程设计从挑选课设题目,查阅资料,到研究出总体设计,详细设计,再到最后的编程上机调试,修改程序,完善程序,收获颇多。锻炼了发现问题、分析问题和通过查看相关资料来解决问题的能力以及团队合作能力。使自己扩大了知识面,提高了知识水平,借助仿真软件,不仅可以把课堂中所学到的知识,直接加以运用,而且还可以把各个分离的知识组合为一个整体,真正做到理论联系实际的重要性。使自己在专业知识和动手能力上有了很大的提高。另外通过本次设计,使我认识到自己对单片机C语言应用编程能力有很大的欠缺,需要在以后的学习中进一步提高。

此次智能化电子系统设计是学生大学学习阶段的一个重要的学习实践环节,它既能增强学生对所学课程内容的理解和综合,也能培养学生的综合应用及设计能力,同时,还可以拓宽课程内容和培养创新意识。感谢学校给我们安排课程设计,大大地加深了我们对理论知识的理解,同时有意识的培养了我们的创新思想。

致谢

本小组的智能化电子系统设计是在我们的导师王老师的亲切关怀和悉心指导下完成的。他严肃的科研态度,严谨的治学精神,精益求精的工作作风,深深地感染和激励着我们。从课题的选择到项目的最终完成,王老师都始终给予我们细心的指导和不懈的支持。在此谨向王老师致以诚挚的谢意和崇高的敬意。在此,我们还要感谢帮助我们答疑解惑的同学们,正是由于你们的帮助和支持,我们才能克服一个一个的困难和疑惑,直至设计的顺利完成。

另外,我们还要感谢学校能安排这次课程设计,为我们学习相关专业提供了良好的实践平台。

参考文献

[1] 邵婷婷,马建仓.电子罗盘的倾斜及罗差补偿算法研究 [J].传感技术学报,2007

[2] Honeywell.HMC5883三轴磁阻传感器中文规格说明书.

[3] Sunman.LCD1602液晶屏中文规格说明书.

[4] 华成英.电子技术[M].北京.广播电视大学出版社,2006

[5] 周国运.单片机原理及应用(C语言版).北京:中国水利水电出版社,2009

[6] 谭浩强.c程序设计.北京:清华大学出版社,2004

附录A: 电子指南针整机电路图和实物图

图A-1 系统整机电路原理图

图A-2 实物图

附录B: 1602液晶模块字符存储器

附录C: 电子指南针程序源代码

主程序HMC5883L_Test.c:

//***************************************

// HMC5883 

//****************************************

#include  "stc.h"

#include  "delay.h"    

#include

#include        

#include

#define   uchar unsigned char

#define   uint unsigned int    

#define   DataPort P0    //LCD1602数据端口

sbit    SCL=P1^0;      //IIC时钟

sbit    SDA=P1^1;      //IIC数据

sbit    LCM_RS=P2^0;   //LCD1602读写RAM        

sbit    LCM_RW=P2^1;   //LCD1602读写        

sbit    LCM_EN=P2^2;   //LCD1602使能 

#define    SlaveAddress   0x3C      //定义器件在IIC总线中的从地址

typedef unsigned char BYTE;

typedef unsigned short WORD;

BYTE BUF[8];                         //接收数据缓存区          

uchar ge,shi,bai,qian;           //显示变量

int  dis_data;                       //变量

void delay(unsigned int k);

void InitLcd();

void Init_HMC5883(void);            //初始化5883

void WriteDataLCM(uchar dataW);

void WriteCommandLCM(uchar CMD,uchar Attribc);

void DisplayOneChar(uchar X,uchar Y,uchar DData);

void conversion(uint temp_data);

void  Single_Write_HMC5883(uchar REG_Address,uchar REG_data);   //单个写入数据

uchar Single_Read_HMC5883(uchar REG_Address);                   //单个读取内部寄存器数据

void  Multiple_Read_HMC5883();                                //连续的读取内部寄存器数据

//模拟iic使用函数

void HMC5883_Start();

void HMC5883_Stop();

void HMC5883_SendACK(bit ack);

bit  HMC5883_RecvACK();

void HMC5883_SendByte(BYTE dat);

BYTE HMC5883_RecvByte();

void HMC5883_ReadPage();

void HMC5883_WritePage();

//-----------------------------------

void Clear_char();

//*********************************************************

void conversion(uint temp_data)  

{  

    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 WaitForEnable(void)    //忙检查         

{                    

DataPort=0xff;        

LCM_RS=0;LCM_RW=1;

delay1us();

LCM_EN=1;

delay1us();

delay1us();

while(DataPort&0x80);    

LCM_EN=0;                

}                    

void WriteCommandLCM(uchar CMD,uchar Attribc)    //写命令

{                    

if(Attribc)WaitForEnable();    

LCM_RS=0;LCM_RW=0;

delay1us();

DataPort=CMD;

delay1us();    

LCM_EN=1;

delay1us();

delay1us();

LCM_EN=0;

}                    

void WriteDataLCM(uchar dataW)    //写数据

{                    

WaitForEnable();        

LCM_RS=1;LCM_RW=0;

delay1us();

DataPort=dataW;

delay1us();    

LCM_EN=1;

delay1us();

delay1us();

LCM_EN=0;

}        

void InitLcd()    //液晶初始化            

{            

WriteCommandLCM(0x38,1);    

WriteCommandLCM(0x08,1);    

WriteCommandLCM(0x01,1);    //清零    

WriteCommandLCM(0x06,1);    

WriteCommandLCM(0x0c,1);

}            

/***********************************/

void DisplayOneChar(uchar X,uchar Y,uchar DData)    //显示字符

{                        

Y&=1;                        

X&=15;                        

if(Y)X|=0x40;                    

X|=0x80;            

WriteCommandLCM(X,0);        

WriteDataLCM(DData);        

}                        

/**************************************

起始信号

**************************************/

void HMC5883_Start()

{

    SDA = 1;                    //拉高数据线

    SCL = 1;                    //拉高时钟线

    Delay5us();                 //延时

    SDA = 0;                    //产生下降沿

    Delay5us();                 //延时

    SCL = 0;                    //拉低时钟线

}

/**************************************

停止信号

**************************************/

void HMC5883_Stop()

{

    SDA = 0;                    //拉低数据线

    SCL = 1;                    //拉高时钟线

    Delay5us();                 //延时

    SDA = 1;                    //产生上升沿

    Delay5us();                 //延时

}

/**************************************

发送应答信号

入口参数:ack (0:ACK 1:NAK)

**************************************/

void HMC5883_SendACK(bit ack)

{

    SDA = ack;                  //写应答信号

    SCL = 1;                    //拉高时钟线

    Delay5us();                 //延时

    SCL = 0;                    //拉低时钟线

    Delay5us();                 //延时

}

/**************************************

接收应答信号

**************************************/

bit HMC5883_RecvACK()

{

    SCL = 1;                    //拉高时钟线

    Delay5us();                 //延时

    CY = SDA;                   //读应答信号

    SCL = 0;                    //拉低时钟线

    Delay5us();                 //延时

    return CY;

}

/**************************************

向IIC总线发送一个字节数据

**************************************/

void HMC5883_SendByte(BYTE dat)

{

    BYTE i;

    for (i=0; i<8; i++)         //8位计数器

    {

        dat <<= 1;              //移出数据的最高位

        SDA = CY;               //送数据口

        SCL = 1;                //拉高时钟线

        Delay5us();             //延时

        SCL = 0;                //拉低时钟线

        Delay5us();             //延时

    }

    HMC5883_RecvACK();

}

/**************************************

从IIC总线接收一个字节数据

**************************************/

BYTE HMC5883_RecvByte()

{

    BYTE i;

    BYTE dat = 0;

    SDA = 1;                    //使能内部上拉,准备读取数据,

    for (i=0; i<8; i++)         //8位计数器

    {

dat <<= 1;

        SCL = 1;                //拉高时钟线

        Delay5us();             //延时

        dat |= SDA;             //读数据               

        SCL = 0;                //拉低时钟线

        Delay5us();             //延时

    }

    return dat;

}

//***************************************************

void Single_Write_HMC5883(uchar REG_Address,uchar REG_data)

{

    HMC5883_Start();                  //起始信号

    HMC5883_SendByte(SlaveAddress);   //发送设备地址+写信号

    HMC5883_SendByte(REG_Address);    //内部寄存器地址,请参考中文pdf 

    HMC5883_SendByte(REG_data);       //内部寄存器数据,请参考中文pdf

    HMC5883_Stop();                   //发送停止信号

}

//********单字节读取内部寄存器*************************

uchar Single_Read_HMC5883(uchar REG_Address)

{  uchar REG_data;

    HMC5883_Start();                          //起始信号

    HMC5883_SendByte(SlaveAddress);           //发送设备地址+写信号

    HMC5883_SendByte(REG_Address);                   //发送存储单元地址,从0开始    

    HMC5883_Start();                          //起始信号

    HMC5883_SendByte(SlaveAddress+1);         //发送设备地址+读信号

    REG_data=HMC5883_RecvByte();              //读出寄存器数据

    HMC5883_SendACK(1);   

    HMC5883_Stop();                           //停止信号

    return REG_data; 

}

//******************************************************

//

//连续读出HMC5883内部角度数据,地址范围0x3~0x8

//

//******************************************************

void Multiple_read_HMC5883(void)

{   uchar i;

    HMC5883_Start();                          //起始信号

    HMC5883_SendByte(SlaveAddress);           //发送设备地址+写信号

    HMC5883_SendByte(0x03);                   //发送存储单元地址,从0x3开始    

    HMC5883_Start();                          //起始信号

    HMC5883_SendByte(SlaveAddress+1);         //发送设备地址+读信号

     for (i=0; i<6; i++)                      //连续读取6个地址数据,存储中BUF

    {

        BUF[i] = HMC5883_RecvByte();          //BUF[0]存储数据

        if (i == 5)

        {

           HMC5883_SendACK(1);                //最后一个数据需要回NOACK

        }

        else

        {

          HMC5883_SendACK(0);                //回应ACK

       }

   }

    HMC5883_Stop();                          //停止信号

    Delay5ms();

}

//初始化HMC5883

void Init_HMC5883()

{

     Single_Write_HMC5883(0x02,0x00);  

}

void Clear_char()                      //清除方向字符

{

    DisplayOneChar(2,0,' ');

    DisplayOneChar(3,0,' ');

    DisplayOneChar(4,0,' ');

    DisplayOneChar(5,0,' ');

    DisplayOneChar(6,0,' ');

    DisplayOneChar(7,0,' ');

    DisplayOneChar(8,0,' ');

    DisplayOneChar(9,0,' ');

    DisplayOneChar(10,0,' ');

    DisplayOneChar(11,0,' ');

}

//*********************************************************

//主程序********

//*********************************************************

void main()

   unsigned int i,j;

   int x,y,z;

   double angle;

  InitLcd();

   Init_HMC5883();

  while(1)            

  { 

    Multiple_Read_HMC5883();      //连续读出数据,存储在BUF中

x=BUF[0] << 8 | BUF[1]; //Combine MSB and LSB of X Data output register

z=BUF[2] << 8 | BUF[3]; //Combine MSB and LSB of Z Data output register

y=BUF[4] << 8 | BUF[5]; //Combine MSB and LSB of Y Data output register

    angle= atan2((double)y,(double)x) * (180 / 3.14159265) + 180; // angle in degrees

// 显示方位

    if((angle < 22.5) || (angle > 337.5 ))    //South

    {

        DisplayOneChar(2,0,'S');

        DisplayOneChar(3,0,'o');

        DisplayOneChar(4,0,'u');

        DisplayOneChar(5,0,'t');

        DisplayOneChar(6,0,'h');

        Clear_char();

    }

    if((angle > 22.5) && (angle < 67.5 ))    //South-west

    {

        DisplayOneChar(2,0,'S');

        DisplayOneChar(3,0,'o');

        DisplayOneChar(4,0,'u');

        DisplayOneChar(5,0,'t');

        DisplayOneChar(6,0,'h');

        DisplayOneChar(7,0,'-');

        DisplayOneChar(8,0,'W');

        DisplayOneChar(9,0,'e');

        DisplayOneChar(10,0,'s');

        DisplayOneChar(11,0,'t');

        Clear_char();

    }

    if((angle > 67.5) && (angle < 112.5 ))    //West

    {

        DisplayOneChar(2,0,'W');

        DisplayOneChar(3,0,'e');

        DisplayOneChar(4,0,'s');

        DisplayOneChar(5,0,'t');

        Clear_char();

    }

    if((angle > 112.5) && (angle < 157.5 ))    //North-West    

    {

        DisplayOneChar(2,0,'N');

        DisplayOneChar(3,0,'o');

        DisplayOneChar(4,0,'r');

        DisplayOneChar(5,0,'t');

        DisplayOneChar(6,0,'h');

        DisplayOneChar(7,0,'-');

        DisplayOneChar(8,0,'W');

        DisplayOneChar(9,0,'e');

        DisplayOneChar(10,0,'s');

        DisplayOneChar(11,0,'t');

        Clear_char();

    }

    if((angle > 157.5) && (angle < 202.5 ))    //North

    {

        DisplayOneChar(2,0,'N');

        DisplayOneChar(3,0,'o');

        DisplayOneChar(4,0,'r');

        DisplayOneChar(5,0,'t');

        DisplayOneChar(6,0,'h'); 

        Clear_char();

    }

    if((angle > 202.5) && (angle < 247.5 ))    //North-East

    {

        DisplayOneChar(2,0,'N');

        DisplayOneChar(3,0,'o');

        DisplayOneChar(4,0,'r');

        DisplayOneChar(5,0,'t');

        DisplayOneChar(6,0,'h');

        DisplayOneChar(7,0,'-');

        DisplayOneChar(8,0,'E');

        DisplayOneChar(9,0,'a');

        DisplayOneChar(10,0,'s');

        DisplayOneChar(11,0,'t');

        Clear_char();

    }

    if((angle > 247.5) && (angle < 292.5 ))    //East

    {

        DisplayOneChar(2,0,'E');

        DisplayOneChar(3,0,'a');

        DisplayOneChar(4,0,'s');

        DisplayOneChar(5,0,'t');

        Clear_char();

    }

    if((angle > 292.5) && (angle < 337.5 ))    //South-East

    {

        DisplayOneChar(2,0,'S');

        DisplayOneChar(3,0,'o');

        DisplayOneChar(4,0,'u');

        DisplayOneChar(5,0,'t');

        DisplayOneChar(6,0,'h');

        DisplayOneChar(7,0,'-');

        DisplayOneChar(8,0,'E');

        DisplayOneChar(9,0,'a');

        DisplayOneChar(10,0,'s');

        DisplayOneChar(11,0,'t');

        Clear_char();

    }

    angle*=10;

 //计算数据和显示   

    conversion(angle);       

    DisplayOneChar(2,1,'A'); 

    DisplayOneChar(3,1,'n');

    DisplayOneChar(4,1,'g');

    DisplayOneChar(5,1,'l');

    DisplayOneChar(6,1,'e');

    DisplayOneChar(7,1,':'); 

    DisplayOneChar(8,1,qian); 

    DisplayOneChar(9,1,bai); 

    DisplayOneChar(10,1,shi); 

    DisplayOneChar(11,1,'.'); 

    DisplayOneChar(12,1,ge); 

//延时

for (i=0;i<50000;i++)

for (j=0;j<10;j++);

  }

}

延时函数集delay.h,引用其delay1us( ) 与delay5us( ): 

#define FOSC  22118400

void delay1us( )

{

_nop_();_nop_();_nop_();_nop_();_nop_();

    _nop_();_nop_();_nop_();_nop_();_nop_();

    _nop_();_nop_();

}

void delay5us( )

{

    delay8((FOSC/1000000*5-18)/10);

}

/*例如要延时的时间为100us,调用方式:delay8((FOSC/1000000*100-18)/10)*/

void delay8(unsigned char t)

{

    unsigned char i;    

    for(i=t;i;i--);

}下载本文

显示全文
专题