#include
#include
#include
#include
#define uchar unsigned char
#define uint unsigned int
//使用的端口,请按照以下接线
sbit SCL=P3^2; //IIC时钟引脚定义
sbit SDA=P3^7; //IIC数据引脚定义
sbit P33=P3^3;
sbit P34=P3^4;
sbit P35=P3^5;
#define SlaveAddress 0x3C //定义器件在IIC总线中的从地址
unsigned char BUF[8]; //接收数据缓存区
unsigned char w[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
void Init_HMC5883(void); //初始化5883
void Single_Write_HMC5883(uchar REG_Address,uchar REG_data); //单个写入数据
void Read_HMC5883(void); //连续的读取内部寄存器数据
//以下是模拟iic使用函数-------------
void Delay5us();
void Delay5ms();
void HMC5883_Start();
void HMC5883_Stop();
void HMC5883_SendACK(bit ack);
bit HMC5883_RecvACK();
void HMC5883_SendByte(unsigned char dat);
unsigned char HMC5883_RecvByte();
void HMC5883_ReadPage();
void HMC5883_WritePage();
/**************************************
延时5微秒(STC90C52RC@12M)
不同的工作环境,需要调整此函数,注意时钟过快时需要修改
当改用1T的MCU时,请调整此延时函数
**************************************/
void Delay5us()
{
_nop_();_nop_();_nop_();_nop_(); _nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_(); _nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
}
/**************************************
延时5毫秒(STC90C52RC@12M)
不同的工作环境,需要调整此函数
当改用1T的MCU时,请调整此延时函数
**************************************/
void Delay5ms()
{
unsigned int n ;
for(n=900;n--;n>0)
Delay5us();
}
/**************************************
起始信号
**************************************/
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(unsigned char dat)
{
unsigned char i;
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1; //移出数据的最高位
SDA = CY; //送数据口
SCL = 1; //拉高时钟线
Delay5us(); //延时
SCL = 0; //拉低时钟线
Delay5us(); //延时
}
HMC5883_RecvACK();
}
/**************************************
从IIC总线接收一个字节数据
**************************************/
unsigned char HMC5883_RecvByte()
{
unsigned char i;
unsigned char 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(); //发送停止信号
}
//******************************************************
//
//连续读出HMC5883内部角度数据,地址范围0x3~0x5
//
//******************************************************
void Read_HMC5883(void)
{ uchar i;
HMC5883_Start(); //起始信号
HMC5883_SendByte(SlaveAddress); //发送设备地址+写信号
HMC5883_SendByte(0x03); //发送存储单元地址,从0x32开始
HMC5883_Start(); //起始信号
HMC5883_SendByte(SlaveAddress+1); //发送设备地址+读信号
for (i=0; i<6; i++) //连续读取6个地址数据,存储中BUF
{
BUF[i] = HMC5883_RecvByte(); //BUF[0]存储0x32地址中的数据
if (i == 5)
{
HMC5883_SendACK(1); //最后一个数据需要回NOACK
}
else
{
HMC5883_SendACK(0); //回应ACK
}
}
HMC5883_Stop(); //停止信号
Delay5ms();
}
//初始化HMC5883,根据需要请参考pdf进行修改****
void Init_HMC5883()
{
Single_Write_HMC5883(0x02,0x00); //
}
void show(int angle_xy)
{
unsigned int a;
unsigned char b;
a=angle_xy/15; //360度等分为24份,每份15度 一个强制转换就会多出98个字节
b=a/8;
P1=0xff; //P1口全部关闭
P3=0xc7; //NPN低电平关闭 11000111
switch (b) //选择哪组灯亮 NPN高电平通
{
case 0:
P33=1; //P3.3高电平
P34=0;
P35=0;
break;
case 1:
P33=0; //P3.4高电平
P34=1;
P35=0;
break;
case 2:
P33=0; //P3.5高电平
P34=0;
P35=1;
break;
default:
break;
}
a%=8;
P1=w[a];
}
//*********************************************************
//主程序********
//*********************************************************
void main() //原来
{
int x,y,z,angle_xy,x_max=0,x_min=0,y_max=0,y_min=0,x_offset,y_offset;
float p;
Delay5ms();
Init_HMC5883();
while(1) //循环
{
Read_HMC5883(); //连续读出数据,存储在BUF中
x=BUF[0] << 8 | BUF[1]; //Combine MSB and LSB of X Data output register xyz有符号!!!!
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
if(z<0) //假如指南针反放,则取相反数
z=-z;
if(z>380) //保证在做xy方向旋转时,垂直方向不能摆动过大,不然就会影响x、y轴的最大小值
{
if(x>x_max)
x_max=x;
if(x
if(y>y_max)
y_max=y;
if(y
x_offset=(x_max + x_min) / 2;
y_offset=(y_max + y_min) / 2;
p=(float)(x_max - x_min) / (float)(y_max - y_min);
x=x-x_offset;
y=p*(y-y_offset);
}
angle_xy= atan2((float)y,(float)x) * (180.0 /3.14159265) + 180; // angle_xy为0~359
show(angle_xy);
Delay5ms();
}
}