使用硬 IIC 口,从 BMP180 中获取温度、气压以及海拔高度值。
Arduino nano 板、BMP180 模组、Arduino IDE。
Arduino 是我非常喜欢的一款 IDE,C++ 语法特性让我在设计以及使用的时候非常方便。同时在工作中,如果需要快速开发做演示,我也很喜欢使用 Arduino。走量产项目的话,还是不推荐它。
http://read.pudn.com/downloads707/sourcecode/others/2839579/GY68BMP180/相关数据手册/BST-BMP180-DS000-07.pdf
在上一篇我们讲解了 BMP180 的工作环境和电气性能。我们知晓 BMP180 是通过 IIC 进行操作的,那么这章我们就可以开始介绍 BMP180 的寄存器。
Arduino 开源代码——BMP180 程序(一)器件选型须知
Arduino 开源代码——BMP180 程序(二)寄存器介绍
其实根据上一章我们就能自己进行操作了。但是,本源码用浮点数而不是BMP发表的整数。
原手册都是建立在整数的基础上,在使用除法时候很容易被四舍五入导致结果偏差过大。
本源码采取的浮点数不受这个问题和修正的影响,会随输入值的变化而平稳地变化(同样也是不精准的,与整数不精准的原理不同)。也使得方程更简单,更容易实现,减少计算误差。
参考 http://wmrx00.sourceforge.net/Arduino/BMP085-Calcs.pdf (需要自备梯子)
本代码采取了更多的是C++思想,C程序员C++没学过就请多查询资料。
Object_IIC.h
/*!
* @file Object_IIC.h
* @n IIC族顶层父类
*
*
* @author [郑振静]([email protected])
* @version V1.0
* @date 2019-04-24
*/
#ifndef ZZJ_OBJECT_IIC_H
#define ZZJ_OBJECT_IIC_H
#include "Wire.h"
#include "Object.h"
namespace ZZJ_LIB
{
class Object_IIC:public Object
{
protected:
uint8_t m_address; //I2C地址
uint8_t m_chipid; //芯片id
bool m_begin_flag; //初始化成功标志
virtual bool config(uint8_t reg_chipid); //读取芯片ID和与预设芯片ID是否相同
virtual void write1(uint8_t reg, uint8_t bitNum,uint8_t value); //I2C写value到reg寄存器中第bitNum位中
virtual void writes(uint8_t reg, uint8_t bitStart, uint8_t length,uint8_t value); //I2C写value到reg寄存器中第bitStart位开始后length个位
virtual void write8(uint8_t reg, uint8_t value); //I2C写8个位的value到reg寄存器中
virtual uint8_t read1(uint8_t reg, uint8_t bitNum); //I2C读取reg寄存器的第bitNum位
virtual uint8_t reads(uint8_t reg, uint8_t bitStart, uint8_t length); //I2C读取reg寄存器的第bitStart位开始后length个位
virtual uint8_t read8(uint8_t reg); //I2C读取reg寄存器的8位
virtual uint16_t read16(uint8_t reg); //I2C读取reg寄存器的16位
virtual uint32_t read24(uint8_t reg); //I2C读取reg寄存器的24位
virtual int16_t readS16(uint8_t reg);
virtual uint16_t read16_LE(uint8_t reg); //I2C大段模式读取reg寄存器的16位数据返回
virtual int16_t readS16_LE(uint8_t reg);
};
}
#endif
Object_IIC.c
#include "Object_IIC.h"
namespace ZZJ_LIB
{
/***********************************************
检测是否连接和设置是否正确
读取芯片ID和与预设芯片ID是否相同
相同返回true否则false
***********************************************/
bool Object_IIC::config(uint8_t reg_chipid)
{
bool ret = false;
Serial.println(read8(reg_chipid));
if (read8(reg_chipid) == m_chipid) {
ret = true;
}
return ret;
}
/***********************************************
给寄存器写数据和读数据
***********************************************/
void Object_IIC::write1(uint8_t reg, uint8_t bitNum,uint8_t value)
{
uint8_t temp;
temp = read8(reg);
temp = (value != 0) ? (temp | (1 << bitNum)) : (temp & ~(1 << bitNum));
write8(reg,temp);
}
void Object_IIC::writes(uint8_t reg, uint8_t bitStart, uint8_t length,uint8_t value)
{
uint8_t temp;
uint8_t data;
data = read8(reg);
temp = ((1 << length) - 1) << (bitStart - length + 1);
temp = ~(temp);
data &= temp;
data += value << (bitStart - length + 1);
write8(reg,data);
}
void Object_IIC::write8(uint8_t reg, uint8_t value)
{
Wire.beginTransmission((uint8_t)m_address);
Wire.write((uint8_t)reg);
Wire.write((uint8_t)value);
Wire.endTransmission();
}
uint8_t Object_IIC::read1(uint8_t reg, uint8_t bitNum)
{
uint8_t value;
uint8_t ret;
value = read8(reg);
ret = value & (1 << bitNum);
return ret;
}
uint8_t Object_IIC::reads(uint8_t reg, uint8_t bitStart, uint8_t length)
{
uint8_t value;
uint8_t ret;
value = read8(reg);
ret = value & ((1 << length) - 1) << (bitStart - length + 1);
ret >>= (bitStart - length + 1);
return ret;
}
uint8_t Object_IIC::read8(uint8_t reg)
{
uint8_t value;
Wire.beginTransmission((uint8_t)m_address);
Wire.write((uint8_t)reg);
Wire.endTransmission();
Wire.requestFrom((uint8_t)m_address, (byte)1);
value = Wire.read();
return value;
}
uint16_t Object_IIC::read16(uint8_t reg)
{
uint16_t value;
Wire.beginTransmission((uint8_t)m_address);
Wire.write((uint8_t)reg);
Wire.endTransmission();
Wire.requestFrom((uint8_t)m_address, (byte)2);
value = (Wire.read() << 8) | Wire.read();
return value;
}
uint16_t Object_IIC::read16_LE(uint8_t reg) {
uint16_t temp = read16(reg);
return (temp >> 8) | (temp << 8);
}
int16_t Object_IIC::readS16(uint8_t reg)
{
return (int16_t)read16(reg);
}
int16_t Object_IIC::readS16_LE(uint8_t reg)
{
return (int16_t)read16_LE(reg);
}
uint32_t Object_IIC::read24(uint8_t reg)
{
uint32_t value;
Wire.beginTransmission((uint8_t)m_address);
Wire.write((uint8_t)reg);
Wire.endTransmission();
Wire.requestFrom((uint8_t)m_address, (byte)3);
value = Wire.read();
value <<= 8;
value |= Wire.read();
value <<= 8;
value |= Wire.read();
return value;
}
}
BMP180_IIC.h
/*!
@file BMP180_IIC.h
@n BMP180_IIC获取温度,气压
@author [郑振静]([email protected])
@version V1.0
@date 2019-04-24
*/
#ifndef ZZJ_BMP180_IIC_H
#define ZZJ_BMP180_IIC_H
#include "Object_IIC.h"
#define BMP180_ADDR 0X77
#define BMP180_CHIPID 0X55
/***********************************************
寄存器向量表
***********************************************/
#define BMP180_R_REG_XLSB 0XF8 //用于读写16位数据
#define BMP180_R_REG_LSB 0XF7
#define BMP180_R_REG_MSB 0XF6
#define BMP180_RW_REG_MEAS 0XF4 //用于设置模式,检测工作,测量控制
#define BMP180_RW_REG_RESULT 0XE0 //用于复位
#define BMP180_R_REG_CHIPID 0XD0 //读取芯片ID寄存器
#define BMP180_R_REG_AC1_S 0XAA //校准系数......
#define BMP180_R_REG_AC1_E 0XAB
#define BMP180_R_REG_AC2_S 0XAC
#define BMP180_R_REG_AC2_E 0XAD
#define BMP180_R_REG_AC3_S 0XAE
#define BMP180_R_REG_AC3_E 0XAF
#define BMP180_R_REG_AC4_S 0XB0
#define BMP180_R_REG_AC4_E 0XB1
#define BMP180_R_REG_AC5_S 0XB2
#define BMP180_R_REG_AC5_E 0XB3
#define BMP180_R_REG_AC6_S 0XB4
#define BMP180_R_REG_AC6_E 0XB5
#define BMP180_R_REG_B1_S 0XB6
#define BMP180_R_REG_B1_E 0XB7
#define BMP180_R_REG_B2_S 0XB8
#define BMP180_R_REG_B2_E 0XB9
#define BMP180_R_REG_MB_S 0XBA
#define BMP180_R_REG_MB_E 0XBB
#define BMP180_R_REG_MC_S 0XBC
#define BMP180_R_REG_MC_E 0XBD
#define BMP180_R_REG_MD_S 0XBE
#define BMP180_R_REG_MD_E 0XBF
/***********************************************
设置模式常量值
BMP180_RW_REG_MEAS
***********************************************/
#define BMP180_MODE_BIT 07
#define BMP180_MODE_LENGTH 02
#define BMP180_ULTRA_LOW_POWER 0 //超低功耗模式
#define BMP180_STANDARD 1 //标准模式
#define BMP180_HIGH_RESOLUTION 2 //高分辨率模式
#define BMP180_ULTRA_HIGH_RESOLUTION 3 //超高分辨率模式
#define BMP180_CONVERSION_TIME_BIT 04
#define BMP180_CONVERSION_TIME_LENGTH 05
#define BMP180_COMMAND_TEMPERATURE 46 //温度时等待时长
#define BMP180_COMMAND_PRESSURE0 52 //超低功耗模式,气压等待时长
#define BMP180_COMMAND_PRESSURE1 116 //标准模式,气压等待时长
#define BMP180_COMMAND_PRESSURE2 180 //高分辨率模式,气压等待时长
#define BMP180_COMMAND_PRESSURE3 244 //超高分辨率模式,气压等待时长
namespace ZZJ_LIB
{
struct bmp180_data_s
{
double bmp180_c5;
double bmp180_c6;
double bmp180_mc;
double bmp180_md;
double bmp180_x0;
double bmp180_x1;
double bmp180_x2;
double bmp180_y0;
double bmp180_y1;
double bmp180_y2;
double bmp180_p0;
double bmp180_p1;
double bmp180_p2;
double bmp180_UT;
double bmp180_UP;
};
struct bmp180_open_data_s
{
double bmp180_T;
double bmp180_P;
};
class BMP180_IIC : public Object_IIC
{
private:
bool m_getTemp_flag;
uint8_t m_mode;
double init_pressure;
bmp180_data_s m_bmp180_data;
bmp180_open_data_s m_bmp180_open_data; //暂时为共有成员方便调试。
bool initMode(uint8_t mode); //初始化模式 //尝试是否初始化成功
void getCalParam(); //获取校准系数
void getUT(); //获取温度系数
void getUP(); //获取气压系数
public:
BMP180_IIC();
bool begin(uint8_t addr = BMP180_ADDR, uint8_t chipid = BMP180_CHIPID, uint8_t mode = BMP180_STANDARD); //初始化BMP280,初始化成功返回true
float getTemperature(void); //获取温度值
float getPressure(void); //获取气压值
float getAltitude(float seaLevelhPa = 1013.25); //获取海拔值
float getHeight(); //获取高度
uint8_t getMode(); //获取当前模式
};
}
#endif
BMP180_IIC.c
#include "BMP180_IIC.h"
#include
namespace ZZJ_LIB
{
BMP180_IIC::BMP180_IIC()
{
m_begin_flag = false; //设置初始化标志信息,防止重复初始化
}
bool BMP180_IIC::begin(uint8_t addr, uint8_t chipid, uint8_t mode)
{
bool ret = false;
m_chipid = chipid;
m_address = addr;
m_mode = mode;
Wire.begin();
if (!m_begin_flag)
{
delay(1000);
ret = config(BMP180_R_REG_CHIPID);//获取初始化是否成功
m_begin_flag = true;
}
if (ret)
ret = (initMode(m_mode) ? 1 : 0);
if (ret)
getCalParam();
init_pressure = getPressure();
return ret;
}
bool BMP180_IIC::initMode(uint8_t mode)
{
bool ret = false;
uint8_t meas = read8(BMP180_RW_REG_MEAS);
meas &= ~(3 << 6);
write8(BMP180_RW_REG_MEAS, mode << 6 | (meas));
ret = true;
return ret;
}
uint8_t BMP180_IIC::getMode()
{
uint8_t ret;
uint8_t meas = read8(BMP180_RW_REG_MEAS);
ret = meas >> 6;
return ret;
}
void BMP180_IIC::getCalParam()
{
int16_t bmp180_AC1 = read16(BMP180_R_REG_AC1_S);
int16_t bmp180_AC2 = read16(BMP180_R_REG_AC2_S);
int16_t bmp180_AC3 = read16(BMP180_R_REG_AC3_S);
uint16_t bmp180_AC4 = read16(BMP180_R_REG_AC4_S);
uint16_t bmp180_AC5 = read16(BMP180_R_REG_AC5_S);
uint16_t bmp180_AC6 = read16(BMP180_R_REG_AC6_S);
int16_t bmp180_B1 = read16(BMP180_R_REG_B1_S);
int16_t bmp180_B2 = read16(BMP180_R_REG_B2_S);
int16_t bmp180_MB = read16(BMP180_R_REG_MB_S);
int16_t bmp180_MC = read16(BMP180_R_REG_MC_S);
int16_t bmp180_MD = read16(BMP180_R_REG_MD_S);
double c3 = 160.0 * pow(2, -15) * bmp180_AC3;
double c4 = pow(10, -3) * pow(2, -15) * bmp180_AC4;
double b1 = pow(160, 2) * pow(2, -30) * bmp180_B1;
m_bmp180_data.bmp180_c5 = (pow(2, -15) / 160) * bmp180_AC5;
m_bmp180_data.bmp180_c6 = bmp180_AC6;
m_bmp180_data.bmp180_mc = (pow(2, 11) / pow(160, 2)) * bmp180_MC;
m_bmp180_data.bmp180_md = bmp180_MD / 160.0;
m_bmp180_data.bmp180_x0 = bmp180_AC1;
m_bmp180_data.bmp180_x1 = 160.0 * pow(2, -13) * bmp180_AC2;
m_bmp180_data.bmp180_x2 = pow(160, 2) * pow(2, -25) * bmp180_B2;
m_bmp180_data.bmp180_y0 = c4 * pow(2, 15);
m_bmp180_data.bmp180_y1 = c4 * c3;
m_bmp180_data.bmp180_y2 = c4 * b1;
m_bmp180_data.bmp180_p0 = (3791.0 - 8.0) / 1600.0;
m_bmp180_data.bmp180_p1 = 1.0 - 7357.0 * pow(2, -20);
m_bmp180_data.bmp180_p2 = 3038.0 * 100.0 * pow(2, -36);
}
void BMP180_IIC::getUT()
{
uint8_t meas = BMP180_COMMAND_TEMPERATURE;
meas &= ~(3 << 6);
meas = m_mode << 6 | (meas);
write8(BMP180_RW_REG_MEAS, meas);
delay(5);
uint32_t T_MSB = read8(BMP180_R_REG_MSB);
uint32_t T_LSB = read8(BMP180_R_REG_LSB);
m_bmp180_data.bmp180_UT = (T_MSB << 8) + T_LSB;
}
void BMP180_IIC::getUP()
{
switch (m_mode)
{
case 0: write8(BMP180_RW_REG_MEAS, BMP180_COMMAND_PRESSURE0 ); delay(5); break;
case 1: write8(BMP180_RW_REG_MEAS, BMP180_COMMAND_PRESSURE1 ); delay(8); break;
case 2: write8(BMP180_RW_REG_MEAS, BMP180_COMMAND_PRESSURE2 ); delay(14); break;
case 3: write8(BMP180_RW_REG_MEAS, BMP180_COMMAND_PRESSURE3 ); delay(26); break;
}
uint32_t P_MSB = read8(BMP180_R_REG_MSB);
uint32_t P_LSB = read8(BMP180_R_REG_LSB);
uint32_t P_XLSB = read8(BMP180_R_REG_XLSB);
m_bmp180_data.bmp180_UP = ( (P_MSB << 8) + P_LSB + (P_XLSB >> 8));
}
float BMP180_IIC::getTemperature(void)
{
float ret = -404;
getUT();
double temp_a = m_bmp180_data.bmp180_c5 * (m_bmp180_data.bmp180_UT - m_bmp180_data.bmp180_c6);
ret = temp_a + (m_bmp180_data.bmp180_mc / (temp_a + m_bmp180_data.bmp180_md));
m_getTemp_flag = 1;
m_bmp180_open_data.bmp180_T = ret;
return ret;
}
float BMP180_IIC::getPressure(void)
{
float ret = -404;
if (!m_getTemp_flag)
getTemperature();
getUP();
double s = m_bmp180_open_data.bmp180_T - 25.0;
double x = (m_bmp180_data.bmp180_x2 * pow(s, 2)) + (m_bmp180_data.bmp180_x1 * s) + m_bmp180_data.bmp180_x0;
double y = (m_bmp180_data.bmp180_y2 * pow(s, 2)) + (m_bmp180_data.bmp180_y1 * s) + m_bmp180_data.bmp180_y0;
double z = (m_bmp180_data.bmp180_UP - x) / y;
ret = (m_bmp180_data.bmp180_p2 * pow(z, 2)) + (m_bmp180_data.bmp180_p1 * z) + m_bmp180_data.bmp180_p0;
m_getTemp_flag = 0;
m_bmp180_open_data.bmp180_P = ret;
return ret;
}
float BMP180_IIC::getAltitude(float seaLevelhPa)
{
float ret = -404;
ret = 44330 * (1 - pow(((m_bmp180_open_data.bmp180_P) / seaLevelhPa), (1.0 / 5.255)));
return ret;
}
float BMP180_IIC::getHeight()
{
return getAltitude(init_pressure);
}
}
代码我也提供一份到我的百度云盘,有需要者可以自行拿去。同时提供了一份例子。
链接:https://pan.baidu.com/s/16OWhSTGLE_EfkgQpCaIRiA
提取码:sc53