STC 51单片机53——电子指南针HMC5883l

STC 51单片机53——电子指南针HMC5883l_第1张图片

 STC 51单片机53——电子指南针HMC5883l_第2张图片

 

 
#include      
#include      //Keil library  
#include     //Keil library    
#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         x_min=x;
      if(y>y_max)
        y_max=y;
        if(y         y_min=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();                 
  }
}

你可能感兴趣的:(STC单片机,51单片机,嵌入式硬件,单片机,C51)