由于ESP32-C3只有一条硬件I2C总线,然而我的程序中需要同时要两条I2C总线,所以不得不考虑同时使用硬件I2C和软件I2C。硬件I2C作为Slave用于与上位机通信,效率比较高,代码也简单,本篇不做详细介绍。本篇重点介绍软件I2C方式驱动VL53L0X,其他I2C设备可参考。
前面有篇文章写到了I2C总线驱动VL53L0X,这篇我们再深入点。
本文的I2C均是Wire模式使用。软件I2C只能作为master使用。
本人水平有限,以下骚操作仅做参考。
一、软件I2C总线库
arduino下搜索SoftI2CMaster能搜索到一个库:
其在github的链接地址如下:
GitHub - felias-fogg/SoftI2CMaster: Software I2C Arduino librarySoftware I2C Arduino library. Contribute to felias-fogg/SoftI2CMaster development by creating an account on GitHub.https://github.com/felias-fogg/SoftI2CMaster为啥贴出来呢?因为这个库是为AVR写的,不是为ESP32写的,要使用的话必须要去github找找详细点的信息以便改造。
二、Wire这个名称
我的程序需要同时使用硬件I2C和软件I2C,所以我的头文件里有:
#include "Wire.h"
#include <SoftWire.h>
这肯定是有问题的。
打开SoftWire.h文件,第83行:
extern SoftWire Wire;
第248行:
SoftWire Wire = SoftWire();
这两行把Wire这个名称直接与SoftWire进行了绑定,甚至帮你定义好了一个叫做Wire的SoftWire对象。
写这个代码的人的本意,是你用软件I2C了,那你肯定不会用硬件I2C,所以不会在头文件中include "Wire.h"。但是他怎么没想到我会硬件和软件总线一起用呢。。。
这个Wire名称在"Wire.h"中被写成了第一条(0号)硬件I2C的对象,所以在SoftI2C中,我们不能再使用这个名称了。
处理方法很简单,直接把第83行和第248行注释掉。后面我们可以在自己的代码中去定义SoftI2C的名称。
三、增加适配文件
做完上面的工作,就可以编译了。但是肯定不会成功的,不然就没有后文了。
Arduino编译提示:
#error "Not an AVR MCU! Use 'SlowSoftI2CMaster' library instead of 'SoftI2CMaster'!"
意思然你不是AVR CPU,得用另外一个库SlowSoftI2CMaster!
好吧。打开前面安装的SoftI2CMaster库目录,找遍了也没有这个库的cpp和h文件。
既然作者这么提示了,还是看看这个库的README.md文件,在文件最后发现线索:
去这两个链接地址,把SlowSoftI2CMaster.cpp、SlowSoftI2CMaster.h、SlowSoftWire.cpp和SlowSoftWire.h下载下来,放入SoftI2CMaster库目录的src文件夹中。
打开这几个源文件仔细看,并没有发现引用Wire.h,也没有直接使用Wire这个对象,那么就可以尝试测试了。
四、编码测试总线部分
头文件部分,同时包含硬件I2C的头文件"Wire.h"和软件I2C的头文件"SlowSoftWire.h"。
#include "Wire.h"
#include <VL53L0X.h>
//#include <SoftWire.h>
#include <SlowSoftWire.h>
SlowSoftWire Wire2 = SlowSoftWire(6, 7);
Wire2.begin();
基本就可以了。
注意软件I2C的引脚只能在SlowSoftWire(6, 7)指定,不能在begin()函数中指定了。
这时才发现,修改SoftWire.h文件是做了个无用功,这个文件并没有被用到。不过通过这个过程我们也知道了该怎么做。
五、适配VL53L0X
1.头文件VL53L0X.h中
第5行:
#include <Wire.h>
修改为:
#include <SlowSoftWire.h>
第103和104行,把TwoWire类型修改为SlowSoftWire:
void setBus(TwoWire * bus) { this->bus = bus; }
TwoWire * getBus() { return bus; }
修改为:
void setBus(SlowSoftWire * bus) { this->bus = bus; }
SlowSoftWire * getBus() { return bus; }
第159行,把TwoWire类型修改为SlowSoftWire:
TwoWire * bus;
修改为:
SlowSoftWire * bus;
2.源代码VL53L0X.cpp中
第7行:
#include <Wire.h>
修改为:
#include <SlowSoftWire.h>
第38行,构造函数中,把写死的Wire(硬件0号总线)干掉,赋值NULL:
VL53L0X::VL53L0X()
: bus(&Wire)
, address(ADDRESS_DEFAULT)
, io_timeout(0) // no timeout
, did_timeout(false)
{
}
修改为:
VL53L0X::VL53L0X()
: bus(NULL)
, address(ADDRESS_DEFAULT)
, io_timeout(0) // no timeout
, did_timeout(false)
{
}
六、编码测试VL53L0X部分
代码:
#include "Wire.h"
#include <VL53L0X.h>
//#include <SoftWire.h>
#include <SlowSoftWire.h>
VL53L0X sensor;
SlowSoftWire Wire2 = SlowSoftWire(6, 7);
void setup() {
Serial.begin(115200);
Wire2.begin();
sensor.setBus(&Wire2);
#if defined LONG_RANGE
// lower the return signal rate limit (default is 0.25 MCPS)
sensor.setSignalRateLimit(0.1);
// increase laser pulse periods (defaults are 14 and 10 PCLKs)
sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
#endif
#if defined HIGH_SPEED
// reduce timing budget to 20 ms (default is about 33 ms)
sensor.setMeasurementTimingBudget(20000);
#elif defined HIGH_ACCURACY
// increase timing budget to 200 ms
sensor.setMeasurementTimingBudget(200000);
#endif
sensor.setTimeout(500);
while (!sensor.init())
{
Serial.println("Failed to detect and initialize sensor!");
delay(2000);
}
}
void loop() {
Serial.println("start measure...");
Serial.print(sensor.readRangeSingleMillimeters());
if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
delay(1000);
Serial.println();
}
注意我们前面把VL53L0X源码中的bus(&Wire)给改成了bus(NULL),sensor对象初始化时bus对象是空的,所以我们这里要用sensor.setBus(&Wire2);将传感器的总线绑定到Wire2,也就是软件I2C总线上。
硬件I2C的使用代码部分我就没贴了,正常使用Wire.h中定义Wire就行了。
软件I2C驱动其他I2C设备可参考移植。
OK,到此为止,看到串口在不断输出VL53L0X的测量结果时,这个移植工作就算完成了。