加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入

嵌入式外设-HMC5883L电子指南针(电磁场)驱动代码

05/23 16:59
4870
服务支持:
技术交流群

完成交易后在“购买成功”页面扫码入群,即可与技术大咖们分享疑惑和经验、收获成长和认同、领取优惠和红包等。

虚拟商品不可退

当前内容为数字版权作品,购买后不支持退换且无法转移使用。

加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论
放大
实物图
相关方案
  • 方案介绍
    • 前言
    • 一、模块介绍
    • 二、资料获取
    • 实验效果
    • 三、代码编写
    • 四、参考资料
  • 相关文件
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

前言

做一个项目需要用到,但是网上好多资料都没有标准库的,故移植写一个方便以后开发使用

一、模块介绍

霍尼韦尔 HMC5883L 是一种表面贴装的高集成模块,并带有数字接口的弱磁传感器芯片,应用于低成本罗盘和磁场检测领域。HMC5883L 包括最先进的高分辨率HMC118X 系列磁阻传感器,并附带霍尼韦尔专利的集成电路包括放大器、自动消磁驱动器、偏差校准、能使罗盘精度控制在1°~2°的12 位模数转换器.简易的I2C 系列总线接口。HMC5883L 是采用无铅表面封装技术,带有16 引脚,尺寸为3.0X3.0X0.9mm。HMC5883L 的所应用领域有手机、笔记本电脑、消费类电子、汽车导航系统和个人导航系统。

HMC5883L 采用霍尼韦尔各向异性磁阻(AMR)技术,该技术的优点是其他磁传感器技术所无法企及。这些各向异性传感器具有在轴向高灵敏度和线性高精度的特点.传感器带有的对于正交轴低敏感行的固相结构能用于测量地球磁场的方向和大小,其测量范围从毫高斯到 8 高斯(gauss)。 霍尼韦尔的磁传感器在低磁场传感器行业中是灵敏度最高和可靠性最好的传感器。

二、资料获取

关注微信公众号--星之援工作室 发送关键字(HMC5883L

➡️➡️

实验效果

我主要实验一下对金属的反馈效果,达到检测车辆的作用,测试使用的是X轴,得到的结果还是符合预期,可以针对进出不同方向达到测试车辆行驶的方向进行记录

接线方式如下

 首先确认一个位置,并且查看X轴数据(可以自信更新方位和检测轴,道理一样)

测试所得

当金属在左侧时,X轴反馈数据会大于无物体数据
反之,当金属在左侧时,X轴反馈数据会小于于无物体数据

这样就可以判断我们车辆的行驶方向

 连接串口可以输出我们获取到的消息

三、代码编写

 首先,模块用到了IIC通信,我们需要进行模拟IIC通信,全部代码如下,完整工程可以在vx公众号获取

main.c

/*--------------------------------------------------------*
 *                                       								  *
 *   星之援网络科技工作室学习资料v1.0    									*
 *		 时间:2022.7.14                    								*
 *		 程序介绍:HMC5883L 使用               							*
 *		 实现效果:串口输出 XYZ轴 以及偏转角度  						*
 *                                      							    *
 *--------------------------------------------------------*
*/

#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "usart.h"
#include "hmc5883l.h"

extern HMC_XYZ hmc_xyz_init; // 初始化结构体

int main(void)
{
	delay_init();
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	LED_GPIO_Config();	// LED 端口初始化 
	uart_init(115200);// 串口初始化

  GY_IIC_Init() ;
	HMC5883_Init(); // HMC5883L初始
	printf("init okn");
  while(1)
	{

		HMC5883_Get_Angle();// 读数据
		printf("X:%d Y:%d Z:%d Angle:%.1fn",hmc_xyz_init.HMC_X,hmc_xyz_init.HMC_Y,
																		 hmc_xyz_init.HMC_Z,hmc_xyz_init.Angle );
		delay_ms(250);
		LED1_TOGGLE;
  }   
}

hmc5883l.h

#ifndef __HMC_H
#define __HMC_H
 
#include "stm32f10x_conf.h"
#include "sys.h"
 
// 结构体
typedef struct
{
	short HMC_X;
	short	HMC_Y;
	short HMC_Z; // HMC5883三轴数据输出
	float Angle; // 偏转角度
	
} HMC_XYZ;
 
#define SlaveAddress 0X3C     //HMC5883L从机地址
#define SelfTest_EN 1

#define CRA 0x00
#define CRB 0x01
#define MR 0x02
#define DOXMR 0x03
#define DOXLR 0x04
#define DOZMR 0x05
#define DOZLR 0x06
#define DOYMR 0x07
#define DOYLR 0x08
#define SR 0x09
#define IRA 0x0A
#define IRB 0x0B
#define IRC 0x0C

#define GY_IN_GPIO_PORT GPIOB               /* GPIO端口 */
#define GY_IN_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口时钟 */
#define GY_IN_GPIO_PIN GPIO_Pin_7           /* 连接到SCL时钟线的GPIO */

#define GY_SCLK__GPIO_PORT GPIOB              /* GPIO端口 */
#define GY_SCLK_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口时钟 */
#define GY_SCLK__GPIO_PIN GPIO_Pin_9          /* 连接到SCL时钟线的GPIO */

#define GY_DATA__GPIO_PORT GPIOB              /* GPIO端口 */
#define GY_DATA_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口时钟 */
#define GY_DATA__GPIO_PIN GPIO_Pin_8          /* 连接到SCL时钟线的GPIO */

// IO操作函数
#define GY_IIC_SCL PBout(9) // SCL
#define GY_IIC_SDA PBout(8) // SDA
#define GY_READ_SDA PBin(8) // 输入SDA
 
//IIC所有操作函数
void GY_IIC_Delay(void);				//MPU IIC延时函数
void GY_IIC_Init(void);                 //初始化IIC的IO口				 
void GY_IIC_Start(void);				//发送IIC开始信号
void GY_IIC_Stop(void);	  			    //发送IIC停止信号
void GY_IIC_Send_Byte(u8 txd);			//IIC发送一个字节
u8   GY_IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8   GY_IIC_Wait_Ack(void); 				//IIC等待ACK信号
void GY_IIC_Ack(void);					//IIC发送ACK信号
void GY_IIC_NAck(void);				     //IIC不发送ACK信号
 
 
// HMC5883L
u8 HMC5883_SB_Read(u8 Slave_Address, u8 Register_Address) ;
u8 HMC5883_SB_Write(u8 Slave_Address, u8 Register_Address, u8 Register_Data) ;
void HMC5883_Init(void) ;
void HMC5883_Get_Angle(void);
void HMC5883_Get_XYZ(short* x, short* y, short* z);
 
#endif

hmc5883l.C

#include "hmc5883l.h"
#include "math.h"
#include "delay.h"
#include "usart.h"
HMC_XYZ hmc_xyz_init; // 初始化结构体
 
//==============================模拟IIC函数区===================================== 
void GY_IIC_Delay(void)
{
	delay_us(2);
}
// 配置双向I/O端口为输出态
static void GY_SDA_OUT()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(GY_DATA_GPIO_CLK, ENABLE);

	GPIO_InitStructure.GPIO_Pin = GY_DATA__GPIO_PIN; // PC.10  DATA
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GY_DATA__GPIO_PORT, &GPIO_InitStructure); // 初始化GPIOC.10
}
// 配置双向I/O端口为输入态
static void GY_SDA_IN()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(GY_DATA_GPIO_CLK, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GY_DATA__GPIO_PIN; // PC.10 DATA
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GY_DATA__GPIO_PORT, &GPIO_InitStructure); // 初始化GPIOC.10
}
//初始化IIC
void GY_IIC_Init(void)
{					     
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(GY_DATA_GPIO_CLK, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GY_DATA__GPIO_PIN; // PC.11  CE
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
	GPIO_Init(GY_DATA__GPIO_PORT, &GPIO_InitStructure); // 初始化GPIOC.11

	GPIO_InitStructure.GPIO_Pin = GY_SCLK__GPIO_PIN; // PC.12  SCLK
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
	GPIO_Init(GY_SCLK__GPIO_PORT, &GPIO_InitStructure); // 初始化GPIOC.12

	GY_IIC_SCL = 1;
	GY_IIC_SDA = 1;
 
}
//产生IIC起始信号
void GY_IIC_Start(void)
{
	GY_SDA_OUT();     //sda线输出
	GY_IIC_SDA=1;	  	  
	GY_IIC_SCL=1;
	GY_IIC_Delay();
 	GY_IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
	GY_IIC_Delay();
	GY_IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void GY_IIC_Stop(void)
{
	GY_SDA_OUT();//sda线输出
	GY_IIC_SCL=0;
	GY_IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
 	GY_IIC_Delay();
	GY_IIC_SCL=1;  
	GY_IIC_SDA=1;//发送I2C总线结束信号
	GY_IIC_Delay();							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 GY_IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	GY_SDA_IN();      //SDA设置为输入  
	GY_IIC_SDA=1;GY_IIC_Delay();	   
	GY_IIC_SCL=1;GY_IIC_Delay();	 
	while(GY_READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			GY_IIC_Stop();
			return 1;
		}
	}
	GY_IIC_SCL=0;//时钟输出0 	   
	return 0;  
} 
//产生ACK应答
void GY_IIC_Ack(void)
{
	GY_IIC_SCL=0;
	GY_SDA_OUT();
	GY_IIC_SDA=0;
	GY_IIC_Delay();
	GY_IIC_SCL=1;
	GY_IIC_Delay();
	GY_IIC_SCL=0;
}
//不产生ACK应答		    
void GY_IIC_NAck(void)
{
	GY_IIC_SCL=0;
	GY_SDA_OUT();
	GY_IIC_SDA=1;
	GY_IIC_Delay();
	GY_IIC_SCL=1;
	GY_IIC_Delay();
	GY_IIC_SCL=0;
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void GY_IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
	GY_SDA_OUT(); 	    
    GY_IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        GY_IIC_SDA=(txd&0x80)>>7;
        txd<<=1; 	  
		GY_IIC_SCL=1;
		GY_IIC_Delay(); 
		GY_IIC_SCL=0;	
		GY_IIC_Delay();
    }	 
} 	    
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 GY_IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	GY_SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        GY_IIC_SCL=0; 
        GY_IIC_Delay();
		GY_IIC_SCL=1;
        receive<<=1;
        if(GY_READ_SDA)receive++;   
		GY_IIC_Delay(); 
    }					 
    if (!ack)
        GY_IIC_NAck();//发送nACK
    else
        GY_IIC_Ack(); //发送ACK   
    return receive;
}
//==================================模拟IIC-END==============================
 
 
 
 
//==========================HMC5883函数定义=============================
 
u8 HMC5883_SB_Read(u8 Slave_Address, u8 Register_Address) 
{
    static u8 Res_Data = 0;
    GY_IIC_Start(); 
	GY_IIC_Send_Byte(Slave_Address);//0X3C	
	GY_IIC_Wait_Ack();		//等待应答 
    GY_IIC_Send_Byte(Register_Address);	//寄存器地址
    GY_IIC_Wait_Ack();		//等待应答
    GY_IIC_Start();
	GY_IIC_Send_Byte(Slave_Address + 1);//0X3D	
    GY_IIC_Wait_Ack();		//等待应答 
	Res_Data=GY_IIC_Read_Byte(0);//读取数据,发送nACK 
    GY_IIC_Stop();			//产生一个停止条件 
	return Res_Data;		
}
 
u8 HMC5883_SB_Write(u8 Slave_Address, u8 Register_Address, u8 Register_Data)
{
     GY_IIC_Start(); 
	 GY_IIC_Send_Byte(Slave_Address);//发送设备地址
	 if(GY_IIC_Wait_Ack())	//等待应答
	 {
	 	 GY_IIC_Stop();		 
 		 return 1;		
	 }
     GY_IIC_Send_Byte(Register_Address); //写寄存器地址
     GY_IIC_Wait_Ack();		          //等待应答 
	 GY_IIC_Send_Byte(Register_Data);    //发送数据
	 if(GY_IIC_Wait_Ack())	              //等待ACK
	 {
	 	 GY_IIC_Stop();	 
		 return 1;		 
	 }		 
     GY_IIC_Stop();	 
     return 0;
     
}

uint8_t SF=0;  //Self Test Flag
void HMC5883_Init(void)
{
	uint8_t Reg[13];
	GY_IIC_Init() ;
	
	Reg[0] = HMC5883_SB_Read(SlaveAddress,CRA);
	Reg[1] = HMC5883_SB_Read(SlaveAddress,CRB);
	Reg[2] = HMC5883_SB_Read(SlaveAddress,MR);
	Reg[3] = HMC5883_SB_Read(SlaveAddress,DOXMR);
	Reg[4] = HMC5883_SB_Read(SlaveAddress,DOXLR);
	Reg[5] = HMC5883_SB_Read(SlaveAddress,DOZMR);
	Reg[6] = HMC5883_SB_Read(SlaveAddress,DOZLR);
	Reg[7] = HMC5883_SB_Read(SlaveAddress,DOYMR);
	Reg[8] = HMC5883_SB_Read(SlaveAddress,DOYLR);
	Reg[9] = HMC5883_SB_Read(SlaveAddress,SR);
	Reg[10] = HMC5883_SB_Read(SlaveAddress,IRA); //data = 0x48
	Reg[11] = HMC5883_SB_Read(SlaveAddress,IRB); //data = 0x34
	Reg[12] = HMC5883_SB_Read(SlaveAddress,IRC); //data = 0x33

	if(!((Reg[10]==0x48)&&(Reg[11]==0x34)&&(Reg[12]==0x33)))
	{
		printf("HMC5883 I2C access failure!rn");
		printf("HMC5883 regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%xrn", Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], Reg[5], Reg[6], Reg[7], Reg[8], Reg[9], Reg[10], Reg[11], Reg[12]);
	}
	else
	{
		printf("HMC5883 I2C access OK!rn");
		printf("HMC5883 regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%xrn", Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], Reg[5], Reg[6], Reg[7], Reg[8], Reg[9], Reg[10], Reg[11], Reg[12]);


		HMC5883_SB_Write(SlaveAddress,CRA, 0X70);//samples average: 8; data output rate: 15Hz; measure mode: normal
		HMC5883_SB_Write(SlaveAddress,CRB, 0X20);//gain: ± 1.3 Ga
		HMC5883_SB_Write(SlaveAddress,MR, 0X00);//continuous-measurement mode

	}
}

//void HMC5883_Init(void)
//{
//    GY_IIC_Init() ;
//    HMC5883_SB_Write(SlaveAddress, 0X00, 0X58); //写寄存器A,30Hz数据输出、采样平均数0
//    HMC5883_SB_Write(SlaveAddress, 0X01, 0X40); //写寄存器B,传感器量程+-0.88Ga、增益1370高斯
//    HMC5883_SB_Write(SlaveAddress, 0X02, 0X00); //写寄存器C,连续数据输出
//    
//}
 
 
void HMC5883_Get_Angle(void)
{
    u8 i ;

    short Recive_Data[6] ;   //store temperary data
    //HMC5883_Init() ;
    for(i=0; i<6; i++)
    {
        Recive_Data[i] = HMC5883_SB_Read(SlaveAddress, i+3) ;  //get data
    }
    
    hmc_xyz_init.HMC_X = Recive_Data[0]<<8 | Recive_Data[1];//Combine MSB and LSB of X Data output register
    hmc_xyz_init.HMC_Y = Recive_Data[2]<<8 | Recive_Data[3];//Combine MSB and LSB of Z Data output register
    hmc_xyz_init.HMC_Z = Recive_Data[4]<<8 | Recive_Data[5];//Combine MSB and LSB of Y Data output register
    
    hmc_xyz_init.Angle = atan2((double)hmc_xyz_init.HMC_Y,(double) hmc_xyz_init.HMC_X) * (180 / 3.14159265) + 180; // angle in degrees
}
 
void HMC5883_Get_XYZ(short* x, short* y, short* z)
{
	u8 i;
	short Recive_Data[6];
	//HMC5883_Init();
	for (i = 0; i < 6; i++) {
		Recive_Data[i] = HMC5883_SB_Read(SlaveAddress, i + 3);
	}
	*x = Recive_Data[0] << 8 | Recive_Data[1];
	*y = Recive_Data[2] << 8 | Recive_Data[3];
	*z = Recive_Data[4] << 8 | Recive_Data[5];
}

四、参考资料

STM32模拟I2C协议获取HMC5883L电子罗盘磁角度数据 (HAL)icon-default.png?t=N7T8https://blog.csdn.net/hwytree/article/details/126407447【STM32+cubemx】0029 HAL库开发:HMC5883L磁力计的应用(电子指南针)icon-default.png?t=N7T8https://blog.csdn.net/little_grapes/article/details/127895372?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171573961816800211552065%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=171573961816800211552065&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-127895372-null-null.142%5Ev100%5Epc_search_result_base7&utm_term=HMC5883L&spm=1018.2226.3001.4187

联系方式 微信号:13648103287

  • 联系方式.docx

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
LM35DZ/LFT1 1 Texas Instruments 1C high voltage analog temperature sensor, 10 mV/C 3-TO-92

ECAD模型

下载ECAD模型
$3.01 查看
TMP01FPZ 1 Rochester Electronics LLC ANALOG TEMP SENSOR-VOLTAGE, 5Cel, RECTANGULAR, THROUGH HOLE MOUNT, ROHS COMPLIANT, PLASTIC, DIP-8
$11.19 查看
ADT75ARZ 1 Rochester Electronics LLC DIGITAL TEMP SENSOR-SERIAL, 12BIT(s), 3Cel, RECTANGULAR, SURFACE MOUNT, LEAD FREE, MS-012AA, SOIC-8
$2.34 查看

相关推荐

电子产业图谱

方案定制,程序设计方案、单片机程序设计与讲解、APP定制开发。本公众号致力于向读者传递关于程序设计和开发的相关知识,并分享一些关于软件开发的最佳实践。如果您有什么问题或建议,请随时联系我们。我们将竭诚为您服务