1、设计需求及目标
通过对电子指南针硬件电路和软件程序的分析,阐述了电子指南针基本的工作原理及实现。实现模块精度达到1°,能够在LCD上显示当前方位并能通过键盘控制上传指南针处理得到的数据到上位机。
2、设计思路及方案
电子指南针的系统主要由前端磁阻传感器、磁场测量专用转换芯片、单片控制器、辅助扩展电路、人机界面以及系统电源几个部分组成,系统结构如图:
整个系统中前端的磁阻传感器负责测量地磁场的大小并将磁场的变化转化为微弱的电流的变化,专用的磁场测量芯片负责把磁阻传感器变化的电流(模拟量)转换成微控制器可以识别的数字量,然后通过芯片内部的SPI总线上传给微控制器。微控制器将表征当前磁场大小的数字量按照方位进行归一化等处理后通过直观的LCD进行方位显示,同时可以通过键盘控制微控制器进行相应的操作,如将转换后的数据通过串口的形式发送到上位机。整个系统中还包含了实时时钟等一些辅助电路,使整个系统功能得到进一步的扩展。仿真电路图:
3、 部分代码
/******************************************************************************************************************************
***模块名称: 测试主程序 ***
***模块功能: ***
***作 者: METAL MAX,CUIT([email protected]) ***
***调用方式: ***
***日 志: 日期 版本 修改人 记录 ***
*** 06/10/2008 V1.01 METALMAX 总体组合测试通过 ***
***备 注: ***
*****************************************************************************************************************************/
#include <reg52.h>
#include <stdio.h>
#include <math.h> /* T6963驱动库 */
#include "DriverT6963.h"
#include "DataBase.h"
#include "PCF8583.h"
#include "UART.h"
unsigned char GblCnt = 0;
unsigned char T0IRQCNT = 0;
unsigned char oldtempx, oldtempy;
unsigned int Angle;
unsigned char keyflag = 0;
extern unsigned char COMBUF[10];
/******************************************************************************************************************************
**函数名称:delay() **
**函数功能:软件延迟 **
**入口参数:延迟时间倍数 **
**出口参数:无 **
**具体资源:无 **
**调用程序:无 **
**备 注:延时不精确 **
******************************************************************************************************************************/
void delay(unsigned int time)
{
unsigned int i,j;
for (i=0; i<time; i++) {
for (j=0; j<1700; j++){;}
}
}
/******************************************************************************************************************************
**函数名称:DisCurTime() **
**函数功能:在指定位置显示实时芯片内的时间 **
**入口参数:显示位置x, y坐标 **
**出口参数:无 **
**具体资源:无 **
**调用程序:ReadPCF8583(), DisStr() **
**备 注: **
******************************************************************************************************************************/
void DisCurTime(unsigned char x, unsigned char y)
{
unsigned char time[3];
unsigned char dispBuff[9];
ReadPCF8583(0x02, 3, time);
dispBuff[8] = '\0'; /* 在数组最后单元放入标识符以便判断内容结束 */
dispBuff[7] = (time[0] & 0x0f) + '0'; /* 提取秒个位 */
dispBuff[6] = (time[0] >> 4) + '0'; /* 提取秒十位 */
dispBuff[5] = ':';
dispBuff[4] = (time[1] & 0x0f) + '0'; /* 提取分个位 */
dispBuff[3] = (time[1] >> 4) + '0'; /* 提取分十位 */
dispBuff[2] = ':';
dispBuff[1] = (time[2] & 0x0f) + '0'; /* 提取时个位 */
dispBuff[0] = ((time[2] >> 4) & 0x03) + '0'; /* 提取时十位 */
DispStr(y*20+x, dispBuff);
}
/******************************************************************************************************************************
**函数名称:显示日期 **
**函数功能:在指定位置显示实时芯片内的日期 **
**入口参数:显示位置x, y坐标 **
**出口参数:无 **
**具体资源:无 **
**调用程序:ReadPCF8583(), DisStr() **
**备 注: **
******************************************************************************************************************************/
void DisCurDate(unsigned char x, unsigned char y)
{
unsigned char Date[2];
unsigned char DisBuf[11];
ReadPCF8583(0x05, 2, Date); /* 获取PCF8583的日期 */
DisBuf[4] = (Date[0] & 0x0f) + '0'; /* 提取日个位 */
DisBuf[3] = ((Date[0] >> 4) & 0x03) + '0'; /* 提取日十位 */
DisBuf[2] = '/';
DisBuf[1] = (Date[1] & 0x0f) + '0'; /* 提取月个位 */
DisBuf[0] = ((Date[1] >> 4) & 0x01) + '0'; /* 提取月十位 */
DisBuf[5] = '/';
DisBuf[6] = '2';
DisBuf[7] = '0';
DisBuf[8] = '0';
DisBuf[9] = '8';
DisBuf[10]= '\0'; /* 在数组最后单元放入标识符以便判断内容结束 */
DispStr(y*20+x, DisBuf);
}
/******************************************************************************************************************************
**函数名称:DisClock() **
**函数功能:绘制钟面 **
**入口参数:显示位置 **
**出口参数:无 **
**具体资源:无 **
**调用程序:Circle(), Line(), WriteEN(), EasyCH() **
**备 注: **
******************************************************************************************************************************/
void DrawClock(unsigned char x, unsigned char y, unsigned char r)
{
Circle(x, y, r);
Line(x, y-r, x, y-r+5, 0); /* 绘制0点处竖线 */
Line(x, y+r, x, y+r-5, 0); /* 绘制6点处竖线 */
Line(x-r, y, x-r+5, y, 0); /* 绘制9点处竖线 */
Line(x+r, y, x+r-5, y, 0); /* 绘制3点处竖线 */
WriteEN(198,'E');
WriteEN(273,'S');
WriteEN(189,'W');
WriteEN(93,'N');
EasyCH(3, 1, fang);
EasyCH(3, 2, wei);
}
/******************************************************************************************************************************
**函数名称:GraphicTest() **
**函数功能:显示子函数测试程序 **
**入口参数:无 **
**出口参数:无 **
**具体资源:无 **
**调用程序:显示子函数 **
**备 注: **
******************************************************************************************************************************/
void GraphicTest(void)
{
Circle(80, 63, 60);
Rectangle(0, 0, 159, 127, 0);
Triangle(0, 0, 20, 30, 120, 50);
Line(0, 0, 159, 127, 0);
Line(0, 127, 159, 0, 1);
}
/******************************************************************************************************************************
**函数名称:DisMain() **
**函数功能:主显示界面 **
**入口参数:显示位置 **
**出口参数:无 **
**具体资源:无 **
**调用程序:无 **
**备 注:仅用作测试使用 **
******************************************************************************************************************************/
void DisMain(void)
{
Rectangle(0, 22, 159, 127, 0);
DrawClock(113, 70, 45);
Line(0, 115, 159, 115, 0);
Line(64, 22, 64, 115, 0);
}
/******************************************************************************************************************************
**函数名称:DisCurDirc() **
**函数功能:显示当前方位指针 **
**入口参数:显示角度 **
**出口参数:无 **
**具体资源:无 **
**调用程序:WriteEN(), Line() **
**备 注: **
******************************************************************************************************************************/
void DisCurDirc(unsigned int Dir)
{
unsigned char tempx, tempy;
unsigned char Dir1, Dir2, Dir3;
Dir1 = Dir/100 +'0'; /* 提取其各位 */
Dir2 = (Dir%100)/10 + '0';
Dir3 = (Dir%100)%10 + '0';
WriteEN(122, Dir1);
WriteEN(123, Dir2);
WriteEN(124, Dir3);
Dir = Dir/3; /* 不满3的倍数的按3的倍数算 */
tempx = DirTbl[(Dir<<1)];
tempy = DirTbl[((Dir<<1)+1)];
LineClr(113, 70, oldtempx, oldtempy);
Line(113, 70, tempx, tempy, 0);
oldtempx = tempx;
oldtempy = tempy;
}
/******************************************************************************************************************************
**函数名称:SendAngle() **
**函数功能:向串口送当前角度值 **
**入口参数:当前角度 **
**出口参数:无 **
**具体资源:无 **
**调用程序:UartSendStr(), UartSendByte() **
**备 注: **
******************************************************************************************************************************/
void SendAngle(unsigned int Dir)
{
unsigned char Dir1, Dir2, Dir3;
unsigned char Str[] = "Current angle = 360 degree !";
Dir1 = Dir/100 +'0'; /* 提取其各位 */
Dir2 = (Dir%100)/10 + '0';
Dir3 = (Dir%100)%10 + '0';
sprintf(Str, "Current angle = %c%c%c degree !", Dir1,Dir2,Dir3);
UartSendStr(Str);
UartSendByte(0x0d);
UartSendByte(0x0a);
}
/******************************************************************************************************************************
**函数名称:外部中断0 ISR **
**函数功能:获取键值 **
**入口参数:无 **
**出口参数:无 **
**具体资源:无 **
**调用程序:无 **
**备 注: **
******************************************************************************************************************************/
INT0IRQ (void) interrupt 0
{
unsigned char keytmp;
EA = 0;
delay(10);
keytmp = (P1 & 0xf8); /* 保留高5位 */
if (keytmp == 0xf8) { /* 抖动 */
EA = 1;
}else {
switch (keytmp) { /* Key1 */
case 0x78 :
keyflag = 1;
break; /* Key2 */
case 0xb8 : break; /* Key3 */
case 0xd8 : break; /* Key4 */
case 0xe8 : break; /* Key5 */
case 0xf0 : break;
default : break;
}
EA = 1;
}
}
/******************************************************************************************************************************
**函数名称:定时器0 ISR **
**函数功能:定时器0中断服务程序 **
**入口参数:无 **
**出口参数:无 **
**具体资源:无 **
**调用程序:无 **
**备 注: **
******************************************************************************************************************************/
T0IRQ (void) interrupt 1
{
EA = 0;
TR0 = 0;
T0IRQCNT++;
TR0 = 1;
EA = 1;
}
/******************************************************************************************************************************
**函数名称:GetAngle() **
**函数功能:获取方向角度 **
**入口参数:无 **
**出口参数:无 **
**具体资源:无 **
**调用程序:无 **
**备 注: **
******************************************************************************************************************************/
void GetAngle(void)
{
unsigned char Dir1, Dir2, Dir3;
Dir1 = COMBUF[0] - '0';
if (Dir1 > 3) {
}else {
Dir2 = COMBUF[1] - '0';
Dir3 = COMBUF[2] - '0';
Angle = Dir1 * 100 + Dir2 * 10 + Dir3;
}
}
/******************************************************************************************************************************
**函数名称:主测试函数 **
**函数功能: **
**入口参数:无 **
**出口参数:无 **
**具体资源:无 **
**调用程序:无 **
**备 注: **
******************************************************************************************************************************/
void main(void)
{
InitScreen();
InitCOM();
DisMain();
EX0 = 1; /* 外部中断0开 */
IT0 = 1; /* 外部中断0为边沿触发 */
DisCurDate(0, 15); /* 显示系统日期 */
Angle = 1;
while(1)
{
GetAngle();
if (T0IRQCNT == 5) {
DisCurDirc(Angle);
}
DisCurTime(11, 15); /* 显示系统时间 */
switch (keyflag) {
case 1 :
SendAngle(Angle);
keyflag = 0;
break;
default : break;
}
}
}
完整资料:
https://market.m.taobao.com/app/idleFish-F2e/widle-taobao-rax/page-detail?wh_weex=true&wx_navbar_transparent=true&id=614513242483&ut_sk=1.WUpxx7gpwUoDAMmnnrBIzAno_12431167_1585228024499.Copy.detail.614513242483.1828622527&forceFlush=1