【模块学习】关于磁力计HMC5883L型号探索

关于磁力计HMC5883L型号探索

一.序言

         在众多磁力计中,HMC5883L因为其廉价实用而受到大多数嵌入式开发小白的追捧。然而某宝上不仅仅有HMC5883L这一款,还有QMC5883HMC5983,常有商家搞不清芯片就出售,导致提供的数据手册不对应。同时,不同单片机对IIC的操作也略有差异,对小白而言也是件头疼的事情。

HMC5883LQMC5883L区别对比

【模块学习】关于磁力计HMC5883L型号探索_第1张图片

         可以看到,QMC5883L的各寄存器地址与HMC5883L区别还是不小。这样,移植时候程序整体结构不用大改,把寄存器改掉即可。

(1)      修改I2C address

0x3C -> 0x1A

0x3D -> 0x1B

(2)      X/Y/Z Register

起始:0x03 -> 0x00

顺序:X-Z-Y -> X-Y-Z

(3)      Mode Register

0x02 -> 0x09

0x00 -> 0x01

二.HMC5983

         HMC5983HMC5883L的“加强版”,寄存器与5883基本一致,但同时支持I2CSPI两种通信模式,更加快捷。因此,使用方法与5883几乎没有差别。这里,本人将官方提供的测试程序修改为STC15系列单片机,主要移植I2C通信中时序函数。

         本人增加了一个定任意方向为0度的功能,主要为了解决各类机器人竞赛中场地不一定何种角度朝向的问题。不过由于时间仓促没有来的及写滤波。思路就是将坐标系进行转换。贴出程序,仅供参考。

 

1.电路图

【模块学习】关于磁力计HMC5883L型号探索_第2张图片

2.所需元件

STC15W408AS    x1

HMC5983        x1

1k电阻          x1

独立按键        x1

排针           若干

洞洞板          x1

3.程序结构

【模块学习】关于磁力计HMC5883L型号探索_第3张图片

4.源码

(1)user_config.h

/*-----------------------------------------

	用户配置文件
	
	
-------------------------------------------*/
#ifndef _CONFIG_H_
#define _CONFIG_H_

/*  宏定义  */
#define   uchar unsigned char
#define   uint  unsigned int	
	
typedef unsigned char BYTE;
typedef unsigned short WORD;
	

/*  包含头文件  */
#include 
#include      //Keil library  
#include     //Keil library	
#include  
//USER Library
#include "HMC5983_Driver.h"
#include "HMC5983_Software.h"
#include "uart.h"
#include "delay.h"
#include "interrupt.h"

//#include "LQ12864.h"

//使用的端口,请按照以下接线
sbit	SCL=P3^2;      //IIC时钟引脚定义
sbit	SDA=P3^3;      //IIC数据引脚定义
sbit  KEY=P3^6;      //按键
//sfr INT_CLKO = 0x8f;	//外部中断与时钟输出控制寄存器

//全局变量引入
extern BYTE BUF[8];
extern uchar ge,shi,bai,qian,wan;           //显示变量
extern int  dis_data;                       //变量
extern double angle_ch;
#endif


(2)HMC5983_Driver.h

/*------------------------------------

	HMC5983驱动文件
	
-------------------------------------*/
#ifndef _HMC5983_DRIVER_H_
#define _HMC5983_DRIVER_H_

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

//************
//函数
//************

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


void  Single_Write_HMC5883(uchar REG_Address,uchar REG_data);   //单个写入数据
//uchar Single_Read_HMC5883(uchar REG_Address);                   //单个读取内部寄存器数据
void  Multiple_Read_HMC5883(void);                                  //连续的读取内部寄存器数据
//以下是模拟iic使用函数-------------
void HMC5883_Start(void);
void HMC5883_Stop(void);
void HMC5883_SendACK(bit ack);
bit  HMC5883_RecvACK(void);
void HMC5883_SendByte(BYTE dat);
BYTE HMC5883_RecvByte(void);
void HMC5883_ReadPage(void);
void HMC5883_WritePage(void);

#endif

(3)interrupt.h

/*--------------------------

中断服务头文件

---------------------------*/
#ifndef _IT_H_
#define _IT_H_

#define Init_INT2() INT_CLKO |= 0x10


#endif


(4)uart.c

/*-----------------------------------

	串口配置
	STC15F408AS
	内置晶振
	波特率 9600 bps
	
------------------------------------*/

#include "user_config.h"

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

//*********************************************
//串口初始化
//9600 bps @ 11.059 MHz 
void init_uart(void)
{
	SCON  = 0x50;
	AUXR |= 0x04;
	T2L   = 0xa0;
	T2H   = 0xfc;
	AUXR |= 0x10;
	
	TI    = 1;
	EA    = 1;	
}

//*********串口数据发送******************
void SeriPushSend(uchar send_data)
{
  SBUF = send_data;  
	while(!TI);TI=0;	  
}


(5)interrupt.c

/*-----------------------------

					中断服务

-----------------------------*/
#include "user_config.h"

double angle_ch = 0;

void KEY_DOWN(void) interrupt 10
{
	Delay5ms();
	
	if(KEY == 0)
	{
		while(!KEY);
		angle_ch = Angle_Update();
	}
}


(6)HMC5983_Driver.c

//***************************************
// HMC5883 51串口测试程序
// 使用单片机STC89C51 
// 晶振:11.0592M
// 显示:PC串口
// 编译环境 Keil uVision2
// 参考宏晶网站24c04通信程序
// 时间:2011年3月1日
//****************************************

#include "user_config.h"
#include "HMC5983_Driver.h"


int  dis_data;                       //变量

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



/**************************************
起始信号
**************************************/
void HMC5883_Start(void)
{
    SDA = 1;                    //拉高数据线
    SCL = 1;                    //拉高时钟线
    Delay5us();                 //延时
    SDA = 0;                    //产生下降沿
    Delay5us();                 //延时
    SCL = 0;                    //拉低时钟线
}

/**************************************
停止信号
**************************************/
void HMC5883_Stop(void)
{
    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(void)
{
    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(void)
{
    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~0x5
//
//******************************************************
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<7; i++)                      //连续读取6个地址数据,存储中BUF
    {
        BUF[i] = HMC5883_RecvByte();          //BUF[0]存储0x32地址中的数据
        if (i == 6)
        {
           HMC5883_SendACK(1);                //最后一个数据需要回NOACK
        }
        else
        {
          HMC5883_SendACK(0);                //回应ACK
       }
   }
    HMC5883_Stop();                          //停止信号
    Delay5ms();
}

//初始化HMC5883,根据需要请参考pdf进行修改****
void Init_HMC5883(void)
{
   Single_Write_HMC5883(0x02,0x00);  //
	 Single_Write_HMC5883(0x01,0xE0);  //
}



(7)HMC5983_Software.c

/*---------------------------------

				HMC5983  角度变换

				将任意角度变为0度

-----------------------------------*/
#include "user_config.h"

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

double Angle_Update(void)
{
		int x,y,z,t;
	
			Multiple_Read_HMC5883();      //连续读出数据,存储在BUF中
			x = BUF[0] << 8 | BUF[1]; 
			z = BUF[2] << 8 | BUF[3]; 
			y = BUF[4] << 8 | BUF[5]; 
			t = atan2((double)y,(double)x) * (180 / 3.14159265) + 180; // angle in degrees
		
		while(abs(t-45) <= 0.001)
		{
			Multiple_Read_HMC5883();      //连续读出数据,存储在BUF中
			x = BUF[0] << 8 | BUF[1]; 
			z = BUF[2] << 8 | BUF[3]; 
			y = BUF[4] << 8 | BUF[5]; 
			t = atan2((double)y,(double)x) * (180 / 3.14159265) + 180; // angle in degrees
		}
		return t;
}

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; 	
}

double Change_Target(void)
{
	double angle_now = Angle_Update();
	if(angle_now >= angle_ch) return angle_now-angle_ch;
	else return 360-angle_ch+angle_now;
}


(8)main.c

/*----------------------------------------------------------

	基于HMC5983智能电子罗盘
	
	2017/10/24		Listen C
	
	
	@ 型号:STC15F408AS
	@ 晶振:内置33.1776MHz
	@ 通信:IIC
	@ 显示:0.96 OLED
	@ 串口:9600 bps
	
------------------------------------------------------------*/

#include 
#include "user_config.h"

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

void main(void)
{ // bit sign_bit;

   unsigned int i;
   double angle;


   delay(100);
	 Init_INT2();
   init_uart();
   Init_HMC5883();

  while(1)            //循环
  { 
    
    angle = Change_Target();
    conversion(angle);       //计算数据和显示
		Delay5ms(); 


			SeriPushSend(0x0d);
			SeriPushSend(0x0a);
		
			SeriPushSend(bai);
			SeriPushSend(shi);
			SeriPushSend(ge);
         
  }
} 


三.QMC5883LArduino上使用

         arduino中,I2C address用的是7位地址而不是8位,所以需要对应将address改掉。

比如QMC58830x1a,则二进制为0001_1010。而换算为7位,右移一位二进制为0000_1101

则十六进制为0x0d

源码如下:

#include 
 
#define address 0x0d 
 
void setup() {
  //put your setup code here, to run once:
 Serial.begin(9600);
 delay(500);
 Wire.begin();
 
 Wire.beginTransmission(address);
 Wire.write(0x09);
 Wire.write(0x01);
 Wire.endTransmission();
  
}
 
void loop() {
  //put your main code here, to run repeatedly:
  intx,y,z;
 Wire.beginTransmission(address);
 Wire.write(0x00);
 Wire.endTransmission();
 
 Wire.requestFrom(address,6);
 if(Wire.available() >= 6){
     x= Wire.read() << 8;
      x |= Wire.read();
     y = Wire.read() << 8;
     y |= Wire.read();
     z= Wire.read() << 8;
     z |= Wire.read();
    }
 
   Serial.print("x: ");
   Serial.print(x);
   Serial.print("   y: ");
   Serial.print(y);
   Serial.print("   z: ");
   Serial.println(z);
 
   delay(250);
    
    
}

网盘链接:http://pan.baidu.com/s/1gfEje8r 密码:dbvr

你可能感兴趣的:(模块)