目录
概述
1 STM32Cube控制配置I2C
1.1 I2C参数配置
1.2 使用STM32Cube产生工程
2 HAL库函数介绍
2.1 初始化函数
2.2 写数据函数
2.3 读数据函数
3 认识HMC5883L
3.1 HMC5883L功能介绍
3.2 HMC5883L的寄存器
4 HMC5883L驱动程序实现
4.1 驱动函数实现
4.2 完整驱动代码
5 测试
6 逻辑分析仪捕捉波形
概述
本文主要介绍STM32F4的内部I2C接口的使用方法,包括使用STM32Cube配置i2c接口函数,还介绍了STM32 HAL库中的接口函数,为了验证接口函数的是否能够正常工作,还使用HMC5883L
作为device,以I2C接口作为通信接口,以实现该芯片数据的读写操作。
1 STM32Cube控制配置I2C
STM32CubeMX 版本: 6.11
HAL库版本: STM32Cube_FW_F4_V1.27.1
1.1 I2C参数配置
STM32F407 的标准I2C接口最大支持100K工作频率,笔者选择最大工作频100k,以配置I2C的参数。
I2C使用的GPIO接口如下:
使用MCU类型和HAL库的版本
1.2 使用STM32Cube产生工程
在配置完成项目后,点击GENERATE生成项目,打开项目后项目目录如下,和I2C相关的代码如下:
代码第40行:选择I2C2作为硬件接口
代码第41行:I2C通信速率为100K
代码第44行:定义地址位7bit
2 HAL库函数介绍
STM32 HAL库函数数量很多,本文仅介绍笔者使用的一些函数接口。其他函数在使用的时候在具体研究,而不许把每个函数搞清楚才去应用。
2.1 初始化函数
函数原型:
HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c);
参数介绍
hi2c: 指向I2C_HandleTypeDef结构体的指针,该结构体包含指定I2C的配置信息。
一个使用案例: 如果已经初始化完成hi2c结构,初始化时,直接调用该结构体即可。
2.2 写数据函数
函数原型:
HAL_StatusTypeDef HAL_I2C_Mem_Write( I2C_HandleTypeDef *hi2c,
uint16_t DevAddress,
uint16_t MemAddress,
uint16_t MemAddSize,
uint8_t *pData,
uint16_t Size, uint32_t Timeout)
参数介绍:
hi2c: 指向I2C_HandleTypeDef结构体的指针,该结构体包含指定I2C的配置信息。
DevAddress: 目标设备地址:设备的7位地址值在调用接口之前,必须将数据表向左移动
MemAddress:内存地址
MemAddSize:内存地址大小
pData: 写数据指针
Size: 写数据大小
Timeout: 写数据超时时间
2.3 读数据函数
函数原型:
HAL_StatusTypeDef HAL_I2C_Mem_Read( I2C_HandleTypeDef *hi2c,
uint16_t DevAddress,
uint16_t MemAddress,
uint16_t MemAddSize,
uint8_t *pData,
uint16_t Size,
uint32_t Timeout)
参数介绍:
hi2c: 指向I2C_HandleTypeDef结构体的指针,该结构体包含指定I2C的配置信息。
DevAddress: 目标设备地址:设备的7位地址值在调用接口之前,必须将数据表向左移动
MemAddress:内存地址
MemAddSize:内存地址大小
pData: 读数据指针
Size: 读数据大小
Timeout: 读数据超时时间
3 认识HMC5883L
3.1 HMC5883L功能介绍
霍尼韦尔HMC5883L是一款表面贴装的多芯片模块,专为低场磁传感设计,具有数字接口,适用于低成本罗盘和磁强计等应用。HMC5883L包括我们最先进的高分辨率HMC118X系列磁阻传感器,以及包含放大、自动消磁带驱动器、偏移抵消和12位ADC的ASIC,可实现1°至2°罗盘航向精度。I2C串行总线允许简单的接口。HMC5883L是3.0 × 3.0 × 0.9mm表面贴装16引脚无引线芯片载体(LCC)。
HMC5883L采用霍尼韦尔的各向异性磁阻(AMR)技术,与其他磁传感器技术相比具有优势。这些各向异性定向传感器具有高精度的轴内灵敏度和线性度。这些传感器的固态结构具有非常低的交叉轴灵敏度,旨在测量地球磁场的方向和大小,从毫高斯到8高斯。霍尼韦尔的磁传感器是业内最灵敏、最可靠的低场传感器之一。
3.2 HMC5883L的寄存器
该设备通过许多片上寄存器进行控制和配置,这些寄存器将在本节中描述。在以下描述中,除另有说明外,set表示逻辑1,reset或clear表示逻辑0。
4 HMC5883L驱动程序实现
4.1 驱动函数实现
1)写寄存器函数
代码第25行: 调用HAL_I2C_Mem_Write实现写寄存器功能
2)读寄存器函数
代码第37行: 调用HAL_I2C_Mem_Read实现读寄存器功能
4.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)创建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
5 测试
1)编写测试代码
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);
}
}
2)编写代码,并下载到板卡中,运行代码
6 逻辑分析仪捕捉波形
读取数据的波形