通过IIC访问模块寄存器[ESP--1]
上一节中,我们简单使用ESP函数来从主机视角扫描所有的IIC设备|上一篇文章的链接|,但是并不存在主从机之间的交流。这显然是不合理的,这个小节我们来学习如何实现主从机之间的通信
模块的寄存器
不说最简单的电阻电容电感,稍微复杂一些的功能模块,显示屏,摄像头…他们是如何被主机控制的呢?他们内部其实存在着一系列寄存器,主机就是通过IIC来操作这些寄存器来控制模块的工作,下面我们还是以测距模块VL53L0X(淘宝大概8块到20块一个)做例子来看看如何使用IIC操作寄存器
coding
从官方文档可以知道VL53L0X下总共有这些常用的寄存器
#define VL53L0X_REG_IDENTIFICATION_MODEL_ID 0xc0
#define VL53L0X_REG_IDENTIFICATION_REVISION_ID 0xc2
#define VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD 0x50
#define VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD 0x70
#define VL53L0X_REG_SYSRANGE_START 0x00
#define VL53L0X_REG_RESULT_INTERRUPT_STATUS 0x13
#define VL53L0X_REG_RESULT_RANGE_STATUS 0x14
//设备IIC地址
#define address 0x29
我们这里先尝试读取一下前两个寄存器的内容
主从机通信示例
-
要在通讯前正确的启动IIC设备
-
使用
Wire.write(reg)
,从主机向从机写入要读取的模块寄存器的地址Wire.beginTransmission(address); Wire.write(reg); Wire.endTransmission();
-
然后下一步向从机请求若干个字节的值
Wire.requestFrom(address, int(1));
-
下面一步就是读取,这一步也有一点要注意的东西,就是轮询可用的方案是比较有效的
while (!Wire.available() ); // 等待数据可用 return Wire.read();
#include <Wire.h>
#include <Arduino.h>
// VL53L0X 的 I2C 地址
#define VL53L0X_ADDRESS 0x29
#include <Adafruit_VL53L0X.h>
Adafruit_VL53L0X lox = Adafruit_VL53L0X();
byte readRegister(uint8_t address, uint8_t reg);
#define XSHUT_PIN 2
void setup() {
Serial.begin(9600);
Wire.begin();
//别忘了设备的初始化
// 初始化 XSHUT 引脚为输出
pinMode(XSHUT_PIN, OUTPUT);
// 启用传感器
digitalWrite(XSHUT_PIN, HIGH);
if (!lox.begin()) {
Serial.println(F("Failed to boot VL53L0X"));
while(1);
}
}
void loop() {
// 读取 VL53L0X_REG_IDENTIFICATION_MODEL_ID (寄存器地址 0xC0)
byte model_id = readRegister(VL53L0X_ADDRESS, 0xC0);
Serial.print("Model ID: 0x");
Serial.println(model_id, HEX);
// 读取 VL53L0X_REG_IDENTIFICATION_REVISION_ID (寄存器地址 0xC2)
byte revision_id = readRegister(VL53L0X_ADDRESS, 0xC2);
Serial.print("Revision ID: 0x");
Serial.println(revision_id, HEX);
delay(1000);
}
// 读取指定寄存器的函数
byte readRegister(uint8_t address, uint8_t reg) {
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom(address, int(1));
while (!Wire.available() ); // 等待数据可用
return Wire.read();
/*
最好轮询到值可用,这个方案不太行,万一不可用就不好了
if (Wire.available()) {
return Wire.read();
} else {
return 0xFF; // 错误值
}
*/
}
下面是运行效果