esp32驱动max30102的iic初始化篇一

前言

主要介绍的是arduino中SparkFun_MAX3010x_Sensor_Library这个库。

SparkFun_MAX3010x_Sensor_Library链接地址

这个库可以在arduino中直接搜索下载。

主要分析的是SpO2这个部分。examples中是示例,src中是源码。

如果对max30102的初始化过程不清楚,可以看下面这篇文章。

MAX02分析

实例代码分析

引用部分

头文件的引用

#include <Wire.h>
#include "MAX30105.h"
#include "spo2_algorithm.h"

虽然这里标注的是#include "MAX30105.h",但是MAX30102也可以使用。

#include <Wire.h>其实是不用引用的,因为在#include "MAX30105.h"中已经引用过了,这里引用可能是为了可读性。

创建类

MAX30105 particleSensor;

这里没什么好说的,就是创建了一个MAX30105的对象。

iic初始化部分

if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
{
    Serial.println(F("MAX30105 was not found. Please check wiring/power."));
    while (1);
}

代码的核心部分是particleSensor.begin(Wire, I2C_SPEED_FAST)

I2C_SPEED_FAST

代表的是iic的速度,下面是它的定义。

#define I2C_SPEED_STANDARD        100000
#define I2C_SPEED_FAST            400000

因为现在购买的一般是黑色的MAX30102的模块,这种模块是MAX30102和电容电阻都在一个面,而且面积小,手指在按上去的时候很容易接触到信号线的触点,所以会干扰到iic信号。一般的解决方法是做绝缘,或者把信号线速率降低。

所以这里更建议设置为I2C_SPEED_STANDARD

Wire

这里其实就是传递一个TowWire的引用。

MAX30105::begin

再看一下这个函数的原型。

在H文件中的引用是这样的

boolean begin(TwoWire &wirePort = Wire, uint32_t i2cSpeed = I2C_SPEED_STANDARD, uint8_t i2caddr = MAX30105_ADDRESS);

这样写是代表这三个选项都是可选的,也就是说,你不传递任何值,也是可以正确初始化的。

看一下三个参数

  • wirePort就是接受了一个Wire类
  • i2cSpeed默认是100kHz的速率
  • i2caddr是MAX30102的地址,默认是0x57

也就是说如果什么都不传递,i2cSpeed的速率默认是低速的,所以在初始化时,传递了Wire和I2C_SPEED_FAST,把速度设置为高速。
为啥不直接传I2C_SPEED_FAST,还要传个Wire呢?因为i2cSpeed是第二的参数,所以想要赋值第二个参数,你先得赋值第一个参数。

所以如果想让iic运行在低速时,begin是不用传递参数的。

这里的TwoWire只是Wire类的别名,功能上是完全等价的,为什么要用TwoWire呢,其实就是告诉你,如果你的开发板上有两个iic,而你恰好想用第二条,你就可以传递一个Wire1。

begin在C文件中的实现如下

boolean MAX30105::begin(TwoWire &wirePort, uint32_t i2cSpeed, uint8_t i2caddr) {

  _i2cPort = &wirePort; //Grab which port the user wants us to use

  _i2cPort->begin();
  _i2cPort->setClock(i2cSpeed);

  _i2caddr = i2caddr;

  // Step 1: Initial Communication and Verification
  // Check that a MAX30105 is connected
  if (readPartID() != MAX_30105_EXPECTEDPARTID) {
    // Error -- Part ID read from MAX30105 does not match expected part ID.
    // This may mean there is a physical connectivity problem (broken wire, unpowered, etc).
    return false;
  }

  // Populate revision ID
  readRevisionID();
  
  return true;
}

前四行代码功能就是开启iic总线

  • _i2cPort = &wirePort;在赋值TowWire类
  • _i2cPort->begin();在初始化iic总线
  • _i2cPort->setClock(i2cSpeed);在设置iic速率
  • _i2caddr = i2caddr;在设置iic地址。

进一步深入发现readPartID()readRevisionID其核心是调用了readRegister8,而读取和写入一般都是成对出现的,写入的函数是writeRegister8

uint8_t MAX30105::readPartID() {
  return readRegister8(_i2caddr, MAX30105_PARTID);
}

MAX30105_PARTID:值为0xFF。作用是读取部件id。部件id固定是0x15,所以可以推出来MAX_30105_EXPECTEDPARTID的值是0x15。

void MAX30105::readRevisionID() {
  revisionID = readRegister8(_i2caddr, MAX30105_REVISIONID);
}

MAX30105_REVISIONID:值为0xFE。作用是读取版本号。

MAX30105::readRegister8

来看看读写函数

这是一个用iic总线读取8位数据的函数。

看一下函数原型

uint8_t MAX30105::readRegister8(uint8_t address, uint8_t reg) {
  _i2cPort->beginTransmission(address);
  _i2cPort->write(reg);
  _i2cPort->endTransmission(false);

  _i2cPort->requestFrom((uint8_t)address, (uint8_t)1); // Request 1 byte
  if (_i2cPort->available())
  {
    return(_i2cPort->read());
  }

  return (0); //Fail

}

_i2cPort->beginTransmission(address);的作用是设置传输设备的地址

_i2cPort->write(reg);的作用是设置要传输的数据,这里代表的就是寄存器地址

_i2cPort->endTransmission(false);的作用是结束iic传输,并重新发送一个开始信号,释放资源,如果是传输true的话,会返回一个状态码,指示是否传输成功

状态码表示
0表示传输成功
1表示数据量超过了传送缓存的容纳限制
2表示在传送地址时收到了NACK(非确认信号)
3表示在传送数据时收到了NACK
4表示其他错误

_i2cPort->requestFrom((uint8_t)address, (uint8_t)1);的作用是读取一个字节

_i2cPort->available()的作用是判断是否有可用的数据供读取

_i2cPort->read()的作用是把这个数据读取出来

如果读取失败了,就返回0,这也是在使用这个库时最好iic用低速率的原因。当iic总线收到干扰时(没有做绝缘,手指触到到之后干扰到iic总线信号传输,因为人体相当于一个几十到几百uF的电容)就会直接返回0,这时并不能确定时总线受到干扰,信号没回来,还是传输回来的就是0。
这时候看到的数据就是不稳定的。

MAX30105::writeRegister8

介绍完了读函数,写函数就没什么好说的了。看一下源码。

void MAX30105::writeRegister8(uint8_t address, uint8_t reg, uint8_t value) {
  _i2cPort->beginTransmission(address);
  _i2cPort->write(reg);
  _i2cPort->write(value);
  _i2cPort->endTransmission();
}

加了一个value,就是需要在reg这个地址的寄存内写入的数据。

不同的是_i2cPort->endTransmission();里面没有传递参数,这代表着,发送停止信号,结束iic传输。在读函数中,有参数是因为还要执行一遍读取操作,而写函数不需要再读取了。

用户操作部分

Serial.println(F("Attach sensor to finger with rubber band. Press any key to start conversion"));
while (Serial.available() == 0) ; //wait until user presses a key
Serial.read();

这一段没什么好说的,就是初始化成功了,然后让你随便输入个东西,然后继续执行后面的内容

实际开发中用不到这一块代码

  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于ESP32Arduino环境下同时初始化两个软件IIC的问题,我可以为您提供一些帮助。 首先,ESP32Arduino库并没有直接支持同时初始化两个软件IIC的函数。但是,您可以使用Wire库中的软件IIC实现多个IIC总线。 以下是一个示例代码,展示了如何在ESP32上同时初始化两个软件IIC: ```cpp #include <Wire.h> // 定义两个IIC总线对象 TwoWire Wire1 = TwoWire(1); TwoWire Wire2 = TwoWire(2); void setup() { // 初始化第一个IIC总线 Wire1.begin(21, 22); // SDA1 -> GPIO21, SCL1 -> GPIO22 // 初始化第二个IIC总线 Wire2.begin(18, 19); // SDA2 -> GPIO18, SCL2 -> GPIO19 // 其他初始化代码... } void loop() { // 使用Wire1进行第一个IIC总线的操作 Wire1.beginTransmission(0x12); // ... Wire1.endTransmission(); // 使用Wire2进行第二个IIC总线的操作 Wire2.beginTransmission(0x34); // ... Wire2.endTransmission(); // 其他代码... } ``` 在上面的示例中,我们创建了两个TwoWire对象(Wire1和Wire2),分别代表了两个不同的软件IIC总线。然后,我们使用`begin`函数初始化这两个总线,并传入对应的SDA和SCL引脚。在`loop`函数中,您可以分别使用`Wire1`和`Wire2`进行对应IIC总线的操作。 需要注意的是,ESP32上的GPIO引脚分配可能因具体板型而有所不同,请根据您使用的ESP32开发板的引脚定义进行相应的修改。 希望这个示例能对您有所帮助!如果您有任何其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值