HMC5883L--STM32+CUBEMX(HAL库)基于硬件I2C使用HMC5883L

一、基础知识

1、HMC5883L磁力计的基础知识

磁力计是用来测量磁场强弱(也就是磁感应强度)的,磁感应强度是一个矢量,我们本篇使用的HMC5883L可以用来测量三个轴向的磁感应强度。

磁感应强度的标准单位是特斯拉(Tesla),也有用高斯(Gauss)来表示的,换算关系是1Tesla=10000Gauss。

当垂直于磁场方向长度为1m的导体,通过1A电流时,所受磁场的作用力的大小为1N,则该磁场的磁感应强度为1T。

磁力计可以用来检测地球磁场方向,也就是作为指南针使用,在航模或者四轴飞行器中,可以用来修正偏航角。

2、HMC5883L的寄存器对应表

后续代码的编写就是写入读取寄存器来进行编写

该图为寄存器对应图(引用于@向全栈冲锋)

3、硬件连接方面

硬件方面,磁力计模块上只连VCC、GND、SCL、SDA四根线,SCL连接到stm32的PB6,SDA连接到stm32的PB7,由于该模块的电路板上已经设计了上拉电阻,所以I2C接口的两根线不用再外接上拉了。

以下是电路连接图:

二、软件编写方面

1、STM32CUBEMX配置

1.0、软件版本

STM32CUBEMX 版本:V6.2.0

HAL库 版本:STM32Cube FW_F4 V1.28.0

1.1、新建工程

选择相应的芯片型号(本文使用的是STM32F407VET6)

1.2、初始化配置

1.2.1、配置RCC
1.2.2、配置debug
1.2.3、配置时钟频率

        频率设置为168Mhz

1.3、外设配置

1.3.1、I2C参数配置

STM32F407 的标准I2C接口最大支持100K工作频率,本文选择最大工作频100k,以配置I2C的参数。

GPIO接口配置

1.3.2、串口配置

选择USART1进行串口的发送,在后续实验中用来发送实验数据,后续将进行串口重定向

RX:PA10

TX:PA9

波特率:115200

1.4、生产代码

2、KEIL5代码编写

2.1、I2C初始化

生产的代码已经自动配置了I2C

2.2、HMC5883L代码编写

2.2.1、创建hmc5883l.c,编写如下代码
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name            : hmc5883l.c
* Description          : I2C drive based on STM32F4
* STM32 HAL library ver: STM32Cube_FW_F4_V1.27.1
* 
******************************************************************************
* @attention
*
* Copyright (c) 2024~2029 mingfei.tang
* All rights reserved.
*
*************************************************************************
*/
/* USER CODE END Header */
#include "hmc5883l.h"
 
HMC5883L_T g_tMag;
 
static uint8_t hmc5883L_WeReg( uint16_t regAdd, uint8_t *pData, uint16_t Size )
{
    HAL_StatusTypeDef status;
    
    status = HAL_I2C_Mem_Write( &hi2c2, HMC5883L_SLAVE_ADDRESS, regAdd, 
                                I2C_MEMADD_SIZE_8BIT, pData, Size, 1000);
    if( status == HAL_OK)
        return HMC5883L_OK;
    else
        return HMC5883L_ERROR; 
}
 
static uint8_t hmc5883L_RdReg( uint16_t regAdd, uint8_t *pData, uint16_t Size )
{
    HAL_StatusTypeDef status;
    
    status = HAL_I2C_Mem_Read( &hi2c2, HMC5883L_SLAVE_ADDRESS, regAdd, 
                               I2C_MEMADD_SIZE_8BIT, pData, Size, 1000);
    if( status == HAL_OK)
        return HMC5883L_OK;
    else
        return HMC5883L_ERROR; 
}
 
void hmc5883L_WriteByte(uint8_t _ucRegAddr, uint8_t _ucRegData)
{
    hmc5883L_WeReg( _ucRegAddr, &_ucRegData, 1);
}
 
uint8_t hmc5883L_ReadByte(uint8_t _ucRegAddr)
{
    uint8_t _ucRegData;
 
    hmc5883L_RdReg( _ucRegAddr, &_ucRegData, 1);
 
    return  _ucRegData;
}
 
void hmc5883l_Init(void)
{
    /* 设置Mode寄存器 */
    #if 1
        hmc5883L_WriteByte(0x00, 0x70);
        hmc5883L_WriteByte(0x01, 0x20);
        hmc5883L_WriteByte(0x02, 0x00);
    #else    /* 自校准模式 */
        hmc5883L_WriteByte(0x00, 0x70 + 2);
        hmc5883L_WriteByte(0x01, 0x20);
        hmc5883L_WriteByte(0x02, 0x00);
    #endif
    
    
    g_tMag.CfgRegA = hmc5883L_ReadByte(0);
    g_tMag.CfgRegB = hmc5883L_ReadByte(1);
    g_tMag.ModeReg = hmc5883L_ReadByte(2);
    
    g_tMag.IDReg[0] = hmc5883L_ReadByte(10);
    g_tMag.IDReg[1] = hmc5883L_ReadByte(11);
    g_tMag.IDReg[2] = hmc5883L_ReadByte(12);
    g_tMag.IDReg[3] = 0;
    
    /* 设置最小最大值初值 */
    g_tMag.X_Min = 4096;
    g_tMag.X_Max = -4096;
    
    g_tMag.Y_Min = 4096;
    g_tMag.Y_Max = -4096;
 
    g_tMag.Z_Min = 4096;
    g_tMag.Z_Max = -4096;
}
 
void hmc5883l_ReadData(void)
{
    uint8_t ucReadBuf[7];
 
    hmc5883L_RdReg( DATA_OUT_X, ucReadBuf, 7);
 
    /* 将读出的数据保存到全局结构体变量 */
    g_tMag.X = (int16_t)((ucReadBuf[0] << 8) + ucReadBuf[1]);
    g_tMag.Z = (int16_t)((ucReadBuf[2] << 8) + ucReadBuf[3]);
    g_tMag.Y = (int16_t)((ucReadBuf[4] << 8) + ucReadBuf[5]);
    
    g_tMag.Status = ucReadBuf[6];
    
    /* 统计最大值和最小值 */
    if ((g_tMag.X > - 2048) && (g_tMag.X < 2048))
    {
        if (g_tMag.X > g_tMag.X_Max)
        {
            g_tMag.X_Max = g_tMag.X;
        }
        if (g_tMag.X < g_tMag.X_Min)
        {
            g_tMag.X_Min = g_tMag.X;
        }    
    }
 
    if ((g_tMag.Y > - 2048) && (g_tMag.Y < 2048))
    {
        if (g_tMag.Y > g_tMag.Y_Max)
        {
            g_tMag.Y_Max = g_tMag.Y;
        }
        if (g_tMag.Y < g_tMag.Y_Min)
        {
            g_tMag.Y_Min = g_tMag.Y;
        }    
    }
    
    if ((g_tMag.Z > - 2048) && (g_tMag.Z < 2048))
    {
        if (g_tMag.Z > g_tMag.Z_Max)
        {
            g_tMag.Z_Max = g_tMag.Z;
        }
        if (g_tMag.Z < g_tMag.Z_Min)
        {
            g_tMag.Z_Min = g_tMag.Z;
        }    
    }
}
 
void hmc5883l_test( void )
{
    hmc5883l_Init();
 
    while(1)
    {
        hmc5883l_ReadData();
        
        printf("X=%5d(%5d,%5d),Y=%6d(%5d,%5d),Z=%6d(%5d,%5d)\r",
                g_tMag.X, g_tMag.X_Min, g_tMag.X_Max,
                g_tMag.Y, g_tMag.Y_Min, g_tMag.Y_Max,
                g_tMag.Z, g_tMag.Z_Min, g_tMag.Z_Max);
        HAL_Delay(100);
    }
}
 
/* End of this file */
 
 
2.2.2、创建hmc5883l.h,编写如下代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : hmc5883l.h
  * Description        : I2C drive based on STM32F4
  * 
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024~2029 mingfei.tang
  * All rights reserved.
  *
  *************************************************************************
  */
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __HMC5883L_H
#define __HMC5883L_H
 
#ifdef __cplusplus
 extern "C" {
#endif
 
#include "stdio.h"
#include "main.h"
     
#define HMC5883L_OK               1
#define HMC5883L_ERROR            0
 
 
#define bsp_DelayMS               HAL_Delay
#define HMC5883L_SLAVE_ADDRESS    0x3C           /* I2C从机地址 */
 
#define DATA_OUT_X        0x03
 
typedef struct
{
    int16_t X;
    int16_t Y;
    int16_t Z;
 
    int16_t X_Min;
    int16_t Y_Min;
    int16_t Z_Min;
 
    int16_t X_Max;
    int16_t Y_Max;
    int16_t Z_Max;
 
    uint8_t Status;
    
    uint8_t CfgRegA;
    uint8_t CfgRegB;
    uint8_t CfgRegC;
    uint8_t ModeReg;
    
    uint8_t IDReg[3+1];
}HMC5883L_T;
 
extern HMC5883L_T g_tMag;
 
 
void hmc5883l_test( void );
 
#ifdef __cplusplus
}
#endif
 
#endif /*__BH1750_H */
__HMC5883L_H
2.2.3、主函数进行hmc5883l.h文件的引用
#include "hmc5883l.h"

hmc5883代码编写完成

2.3、USART1串口 printf()函数重载

2.3.1、编写uart.h
#ifndef _UART_H
#define _UART_H

#include "main.h"
#include "stdio.h"	 	  	


int fputc(int ch, FILE *f) ;

#endif

2.3.2、编写uart.c
#include "uart.h"   
#include "usart.h"

extern UART_HandleTypeDef huart1;   //????

/* USER CODE BEGIN 1 */
#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
  return ch;
}
/* USER CODE END 1 */

注意此处使用的是USART1,根据实际应用进行修改即可

extern UART_HandleTypeDef huart1;  
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);

2.3.3、在设置中勾选LIH

2.3.4、引用头文件

#include "hmc5883l.h"
#include "stdio.h"
#include "uart.h"

串口重定向完成

即可使用printf()函数进行串口发送

printf("Hellow World");

2.4 测试代码编写在hmc5883l.c中,

void hmc5883l_test( void )
{
    hmc5883l_Init();
 

    hmc5883l_ReadData();
        
    printf("X1=%5d(%5d,%5d),Y1=%6d(%5d,%5d),Z1=%6d(%5d,%5d)\r",
                g_tMag.X, g_tMag.X_Min, g_tMag.X_Max,
                g_tMag.Y, g_tMag.Y_Min, g_tMag.Y_Max,
                g_tMag.Z, g_tMag.Z_Min, g_tMag.Z_Max);
    HAL_Delay(100);
   
}

同时在hmc5883l.h中进行声明

void hmc5883l_test( void );

在2.2中已经对测试代码进行了编写,如果是直接复制则无需再次编写

2.5进行测试

主函数中调用hmc5883l_tset函数即可

进行编译后,开启串口,即可看到现象

串口正常发送,实验成功

  • 21
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值