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

来源:互联网 发布:三个字网络流行语 编辑:程序博客网 时间:2024/06/05 07:14

关于磁力计HMC5883L型号探索

一.序言

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

HMC5883LQMC5883L区别对比

         可以看到,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.电路图

2.所需元件

STC15W408AS   x1

HMC5983       x1

1k电阻         x1

独立按键       x1

排针          若干

洞洞板         x1

3.程序结构

4.源码

(1)user_config.h

/*-----------------------------------------用户配置文件-------------------------------------------*/#ifndef _CONFIG_H_#define _CONFIG_H_/*  宏定义  */#define   uchar unsigned char#define   uint  unsigned inttypedef unsigned char BYTE;typedef unsigned short WORD;/*  包含头文件  */#include <STC15F2K60S2.H>#include  <math.h>    //Keil library  #include  <stdio.h>   //Keil library#include  <INTRINS.H>//USER Library#include "HMC5983_Driver.h"#include "HMC5983_Software.h"#include "uart.h"#include "delay.h"#include "interrupt.h"//#include "LQ12864.h"//使用的端口,请按照以下接线sbitSCL=P3^2;      //IIC时钟引脚定义sbitSDA=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_#defineSlaveAddress   0x3C    //定义器件5883在IIC总线中的从地址//************//函数//************void Init_HMC5883(void);            //初始化5883void  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 degreeswhile(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/24Listen C@ 型号:STC15F408AS@ 晶振:内置33.1776MHz@ 通信:IIC@ 显示:0.96 OLED@ 串口:9600 bps------------------------------------------------------------*/#include <STC15F2K60S2.H>#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 <Wire.h> #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

原创粉丝点击