前言
做一個項目需要用到,但是網(wǎng)上好多資料都沒有標準庫的,故移植寫一個方便以后開發(fā)使用
一、模塊介紹
霍尼韋爾 HMC5883L 是一種表面貼裝的高集成模塊,并帶有數(shù)字接口的弱磁傳感器芯片,應用于低成本羅盤和磁場檢測領域。HMC5883L 包括最先進的高分辨率HMC118X 系列磁阻傳感器,并附帶霍尼韋爾專利的集成電路包括放大器、自動消磁驅(qū)動器、偏差校準、能使羅盤精度控制在1°~2°的12 位模數(shù)轉換器.簡易的I2C 系列總線接口。HMC5883L 是采用無鉛表面封裝技術,帶有16 引腳,尺寸為3.0X3.0X0.9mm。HMC5883L 的所應用領域有手機、筆記本電腦、消費類電子、汽車導航系統(tǒng)和個人導航系統(tǒng)。
HMC5883L 采用霍尼韋爾各向異性磁阻(AMR)技術,該技術的優(yōu)點是其他磁傳感器技術所無法企及。這些各向異性傳感器具有在軸向高靈敏度和線性高精度的特點.傳感器帶有的對于正交軸低敏感行的固相結構能用于測量地球磁場的方向和大小,其測量范圍從毫高斯到 8 高斯(gauss)。 霍尼韋爾的磁傳感器在低磁場傳感器行業(yè)中是靈敏度最高和可靠性最好的傳感器。
二、資料獲取
關注微信公眾號--星之援工作室 發(fā)送關鍵字(HMC5883L)
????
實驗效果
我主要實驗一下對金屬的反饋效果,達到檢測車輛的作用,測試使用的是X軸,得到的結果還是符合預期,可以針對進出不同方向達到測試車輛行駛的方向進行記錄
接線方式如下
?首先確認一個位置,并且查看X軸數(shù)據(jù)(可以自信更新方位和檢測軸,道理一樣)
測試所得
當金屬在左側時,X軸反饋數(shù)據(jù)會大于無物體數(shù)據(jù)
反之,當金屬在左側時,X軸反饋數(shù)據(jù)會小于于無物體數(shù)據(jù)這樣就可以判斷我們車輛的行駛方向
?連接串口可以輸出我們獲取到的消息
三、代碼編寫
main.c
/*--------------------------------------------------------*
* *
* 星之援網(wǎng)絡科技工作室學習資料v1.0 *
* 時間:2022.7.14 *
* 程序介紹:HMC5883L 使用 *
* 實現(xiàn)效果:串口輸出 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位搶占優(yōu)先級,2位響應優(yōu)先級
LED_GPIO_Config(); // LED 端口初始化
uart_init(115200);// 串口初始化
GY_IIC_Init() ;
HMC5883_Init(); // HMC5883L初始
printf("init okn");
while(1)
{
HMC5883_Get_Angle();// 讀數(shù)據(jù)
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三軸數(shù)據(jù)輸出
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操作函數(shù)
#define GY_IIC_SCL PBout(9) // SCL
#define GY_IIC_SDA PBout(8) // SDA
#define GY_READ_SDA PBin(8) // 輸入SDA
//IIC所有操作函數(shù)
void GY_IIC_Delay(void); //MPU IIC延時函數(shù)
void GY_IIC_Init(void); //初始化IIC的IO口
void GY_IIC_Start(void); //發(fā)送IIC開始信號
void GY_IIC_Stop(void); //發(fā)送IIC停止信號
void GY_IIC_Send_Byte(u8 txd); //IIC發(fā)送一個字節(jié)
u8 GY_IIC_Read_Byte(unsigned char ack);//IIC讀取一個字節(jié)
u8 GY_IIC_Wait_Ack(void); //IIC等待ACK信號
void GY_IIC_Ack(void); //IIC發(fā)送ACK信號
void GY_IIC_NAck(void); //IIC不發(fā)送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函數(shù)區(qū)=====================================
void GY_IIC_Delay(void)
{
delay_us(2);
}
// 配置雙向I/O端口為輸出態(tài)
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端口為輸入態(tài)
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;
}
//產(chǎn)生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總線,準備發(fā)送或接收數(shù)據(jù)
}
//產(chǎn)生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;//發(fā)送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;
}
//產(chǎn)生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;
}
//不產(chǎn)生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發(fā)送一個字節(jié)
//返回從機有無應答
//1,有應答
//0,無應答
void GY_IIC_Send_Byte(u8 txd)
{
u8 t;
GY_SDA_OUT();
GY_IIC_SCL=0;//拉低時鐘開始數(shù)據(jù)傳輸
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個字節(jié),ack=1時,發(fā)送ACK,ack=0,發(fā)送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();//發(fā)送nACK
else
GY_IIC_Ack(); //發(fā)送ACK
return receive;
}
//==================================模擬IIC-END==============================
//==========================HMC5883函數(shù)定義=============================
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);//讀取數(shù)據(jù),發(fā)送nACK
GY_IIC_Stop(); //產(chǎn)生一個停止條件
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);//發(fā)送設備地址
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); //發(fā)送數(shù)據(jù)
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數(shù)據(jù)輸出、采樣平均數(shù)0
// HMC5883_SB_Write(SlaveAddress, 0X01, 0X40); //寫寄存器B,傳感器量程+-0.88Ga、增益1370高斯
// HMC5883_SB_Write(SlaveAddress, 0X02, 0X00); //寫寄存器C,連續(xù)數(shù)據(jù)輸出
//
//}
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協(xié)議獲取HMC5883L電子羅盤磁角度數(shù)據(jù) (HAL)https://blog.csdn.net/hwytree/article/details/126407447【STM32+cubemx】0029 HAL庫開發(fā):HMC5883L磁力計的應用(電子指南針)https://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
聯(lián)系方式 微信號:13648103287