目录
概述
1 STM32Cube控制配置I2C
1.1 I2C参数配置
1.2 使用STM32Cube产生工程
2 HAL库函数介绍
2.1 初始化函数
2.2 写数据函数
2.3 读数据函数
3 大气压力传感器BMP085
3.1 BMP085介绍
3.2 BMP085的应用电路
3.3 BMP085操作流程
3.4 BMP085寄存器
3.5 开始温度和压力测量
3.6 读取A/D转换结果或E2PROM数据
4 BMP085驱动的实现
4.1 驱动接口的实现
4.2 完整驱动函数
5 测试
概述
本文主要介绍STM32F4的内部I2C接口的使用方法,包括使用STM32Cube配置i2c接口函数,还介绍了STM32 HAL库中的接口函数,为了验证接口函数的是否能够正常工作,还使用BMP085作为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 大气压力传感器BMP085
3.1 BMP085介绍
BMP085是一种大气压力传感器,由德国博世公司(Bosch Sensortec)生产。它采用微电子机械系统(MEMS)技术,能够测量大气压力和温度。
BMP085传感器具有高精度和低功耗的特点,可广泛应用于气象观测、气压计、高度测量、无人机导航等领域。它使用I2C总线进行通信,与微控制器或其他设备连接方便。
BMP085传感器能够测量绝对压力范围为300到1100百帕(hPa),精度为0.03hPa。它还具有温度补偿功能,可以减少温度对压力测量的影响。
3.2 BMP085的应用电路
BMP085通过I2C接口与MCU相连,工作电压为1.8~3.6v
3.3 BMP085操作流程
微控制器发送启动序列以启动压力或温度测量。之后转换时间、结果值(UP或UT,分别)可以通过I2C接口读取。对于以°C为单位计算温度,以hPa为单位计算压力,必须使用校准数据。这些常数可以从BMP085中读出通过I2C接口的E2PROM软件初始化。采样率可以增加到128每秒采样数(标准模式)用于动态测量在这种情况下每秒只测量一次温度并将该值用于所有压力在同一时期的测量。通过使用不同的模式实现最佳折衷介于功耗、速度和可以选择分辨率,请参阅下表。
3.4 BMP085寄存器
BMP085内部有176位的E2PROM,其被划分为11个字,每个字16位。其中包含11个校准系数。每个传感器模块都有个自的系数。在第一次计算之前主机读取E2PROM数据。可以通过检查没有一个单词的值为0或0xFFFF。
3.5 开始温度和压力测量
开始测量温度值UT和压力值的时序图UP如下所示。在启动条件之后,主机发送设备地址写入
寄存器地址和控制寄存器数据。BMP085发送确认(ACKS)。主机在最后确认。
控制寄存器不同内部过采样设置(osr)的值:
3.6 读取A/D转换结果或E2PROM数据
为了读出温度数据字UT(16位)、压力数据字UP(16至19位)和E2PROM数据进行如下:
在启动条件之后,主机发送模块地址写入命令和寄存器住址寄存器地址选择读取寄存器:E2PROM数据寄存器0xAA至0xBF,温度或压力值UT或UP 0xF6(MSB),0xF7(LSB),可选0xF8(XLSB)然后,主机发送一个重新启动条件,然后是读取的模块地址由BMP085(ACKS)确认。BMP085首先发送8个MSB,由然后是8个LSB。主机发送“未确认”(NACKM),并且
最后是一个停止条件。可选地,对于超高分辨率,可以读取地址为0xF8的XLSB寄存器以扩展
将16位字转换为最多19位。
时序图读取16位A/D转换结果:
4 BMP085驱动的实现
4.1 驱动接口的实现
1)写寄存器函数
代码第26行: 调用HAL库中I2C接口写内存函数,实现写寄存器数据的功能
2)读寄存器函数
代码第38行: 调用HAL库中I2C接口读内存函数,实现读寄存器数据的功能
3)参数初始化函数
读取芯片内部的校准参数,用于计算温度和气压值
4.2 完整驱动函数
1)创建bmp085.c文件,编写如下代码
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : hal_i2c.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 "bmp085.h"BMP085_T g_tBMP085;static uint8_t bmp085_WeReg( uint16_t regAdd, uint8_t *pData, uint16_t Size )
{HAL_StatusTypeDef status;status = HAL_I2C_Mem_Write( &hi2c2, BMP085_SLAVE_ADDRESS, regAdd, I2C_MEMADD_SIZE_8BIT, pData, Size, 1000);if( status == HAL_OK)return BMP085_OK;elsereturn BMP085_ERROR;
}static uint8_t bmp085_RdReg( uint16_t regAdd, uint8_t *pData, uint16_t Size )
{HAL_StatusTypeDef status;status = HAL_I2C_Mem_Read( &hi2c2, BMP085_SLAVE_ADDRESS, regAdd, I2C_MEMADD_SIZE_8BIT, pData, Size, 1000);if( status == HAL_OK)return BMP085_OK;elsereturn BMP085_ERROR;
}uint16_t bmp085_readValue( uint16_t regAdd )
{uint8_t value[2];bmp085_RdReg(regAdd, value, 2);return (value[0]<<8|value[1]);
}static void BMP085_WaitConvert(void)
{if (g_tBMP085.OSS == 0){bsp_DelayMS(6); /* 4.5ms 7.5ms 13.5ms 25.5ms */}else if (g_tBMP085.OSS == 1){bsp_DelayMS(9); /* 4.5ms 7.5ms 13.5ms 25.5ms */}else if (g_tBMP085.OSS == 2){bsp_DelayMS(15); /* 4.5ms 7.5ms 13.5ms 25.5ms */}else if (g_tBMP085.OSS == 3){bsp_DelayMS(27); /* 4.5ms 7.5ms 13.5ms 25.5ms */}
}void bmp085_Init(void)
{/* 读出芯片内部的校准参数(每个芯片不同,这是BOSCH出厂前校准好的数据) */g_tBMP085.AC1 = (int16_t)bmp085_readValue(0xAA);g_tBMP085.AC2 = (int16_t)bmp085_readValue(0xAC);g_tBMP085.AC3 = (int16_t)bmp085_readValue(0xAE);g_tBMP085.AC4 = (uint16_t)bmp085_readValue(0xB0);g_tBMP085.AC5 = (uint16_t)bmp085_readValue(0xB2);g_tBMP085.AC6 = (uint16_t)bmp085_readValue(0xB4);g_tBMP085.B1 = (int16_t)bmp085_readValue(0xB6);g_tBMP085.B2 = (int16_t)bmp085_readValue(0xB8);g_tBMP085.MB = (int16_t)bmp085_readValue(0xBA);g_tBMP085.MC = (int16_t)bmp085_readValue(0xBC);g_tBMP085.MD = (int16_t)bmp085_readValue(0xBE);g_tBMP085.OSS = 0; /* 过采样参数,0-3 */
}void bmp085_ReadTempPress(void)
{long X3, B3, B6, B7, p;unsigned long B4;long X1, X2, B5, T;uint8_t status;uint8_t cmd;uint8_t tempBuff[3];long uiRegValue;long pressvalue;uint32_t pressRegValue;/* Read tempeture value */cmd = 0x2E;bmp085_WeReg(0xF4, &cmd, 1);BMP085_WaitConvert(); /* 等待转换结束 */status = bmp085_RdReg(0xF6, tempBuff, 2);if( status == BMP085_OK ){uiRegValue = (tempBuff[0] << 8) + tempBuff[1];/* 计算真实温度(单位 0.1摄氏度) */X1 = ((long)(uiRegValue - g_tBMP085.AC6) * g_tBMP085.AC5) >> 15;X2 = ((long)g_tBMP085.MC << 11) / (X1 + g_tBMP085.MD);B5 = X1 + X2; /* 该系数将用于压力的温度补偿计算 */T = (B5 + 8) >> 4;g_tBMP085.Temp = T; /* 将计算结果保存在全局变量 */printf(" bmp085 temp: %5d.%d ℃\r\n", g_tBMP085.Temp / 10, g_tBMP085.Temp % 10);/* 读压力原始值 */cmd = 0x34 + (g_tBMP085.OSS << 6);bmp085_WeReg(0xF4, &cmd, 1);BMP085_WaitConvert(); /* 等待转换结束 */status = bmp085_RdReg(0xF6, tempBuff, 3);if( status == BMP085_OK ){pressRegValue = (tempBuff[0] << 16) + (tempBuff[1] << 8) + tempBuff[2];pressvalue = pressRegValue >> (8 - g_tBMP085.OSS);/* 计算真实压力值(单位 Pa) */B6 = B5 - 4000;X1 = (g_tBMP085.B2 * (B6 * B6) >> 12) >> 11;X2 = (g_tBMP085.AC2 * B6) >> 11;X3 = X1 + X2;B3 = (((((long)g_tBMP085.AC1) * 4 + X3) << g_tBMP085.OSS) + 2) >> 2;X1 = (g_tBMP085.AC3 * B6) >> 13;X2 = (g_tBMP085.B1 * ((B6 * B6) >> 12)) >> 16;X3 = ((X1 + X2) + 2) >> 2;B4 = (g_tBMP085.AC4 * (unsigned long)(X3 + 32768)) >> 15;B7 = ((unsigned long)(pressvalue - B3) * (50000 >> g_tBMP085.OSS));if (B7 < 0x80000000){p = (B7 << 1) / B4;}else{p = (B7 / B4) << 1;}X1 = (p >> 8) * (p >> 8);X1 = (X1 * 3038) >> 16;X2 = (-7357 * p) >> 16;p = p + ((X1 + X2 + 3791) >> 4);g_tBMP085.Press = p; /* 将计算结果保存在全局变量 */printf("Press = %5d.%03d KPa \r", g_tBMP085.Press / 1000, g_tBMP085.Press % 1000);}}
}void bmp085_test( void )
{bmp085_Init();while(1){bmp085_ReadTempPress();HAL_Delay(100);}
}/* End of this file */
2)创建bmp085.h文件,编写如下代码
/* USER CODE BEGIN Header */
/********************************************************************************* File Name : bmp085.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 __BMP_085_H
#define __BMP_085_H#ifdef __cplusplusextern "C" {
#endif#include "stdio.h"
#include "main.h"#define BMP085_OK 1
#define BMP085_ERROR 0#define bsp_DelayMS HAL_Delay
#define BMP085_SLAVE_ADDRESS 0xEE /* I2C从机地址 */typedef struct
{/* 用于保存芯片内部EEPROM的校准参数 */int16_t AC1;int16_t AC2;int16_t AC3;uint16_t AC4;uint16_t AC5;uint16_t AC6;int16_t B1;int16_t B2;int16_t MB;int16_t MC;int16_t MD;uint8_t OSS; /* 过采样值,可有用户自己设定 *//* 下面2个单元用于存放计算的真实值 */int32_t Temp; /* 温度值, 单位 0.1摄氏度 */int32_t Press; /* 压力值, 单位 Pa */
}BMP085_T;extern BMP085_T g_tBMP085;void bmp085_Init(void);
void bmp085_ReadTempPress(void);
void bmp085_test( void );#ifdef __cplusplus
}
#endif#endif /*__BMP_085_H */
5 测试
1)编写测试代码
void bmp085_test( void )
{bmp085_Init();while(1){bmp085_ReadTempPress();HAL_Delay(100);}
}
2)编译代码,下载代码至板卡中,运行结构如下:
6 逻辑分析仪捕捉波形
1)读取气压值
2)读取温度值