2024艾迈斯欧司朗竞赛 - 基于dTOF8821和Arduino Cloud实现云平台实时距离检测
0.任务目标
任务四:1.使用Arduino UNO R4开发板结合dTOF8821模块获取当前距离信息。将获得的多路距离信息通过Arduino Cloud云平台的控件分别显示出来,同时在UNO R4的Matrix LED矩阵上以柱状形式显示距离的远近。
1. 硬件
1.1硬件连接演示图
硬件上根据dTOF8821模块的原理图和驱动手册,将模块的VCC与Arduino UNO R4的板载5V相连接,其中EN使能引脚与5V旁边的3.3V引脚相连接,即使模块处于上电即使能的状态。INT引脚与UNO R4的Pin6相连接。而用于dTOF8821模块IIC通讯的两个引脚直接与UNO R4的硬件IIC引脚相连接。
1.2硬件连接实物图
2.软件代码
2.1 dTOF8821模块驱动代码编写
TMF8821采用IIC进行通信,其I²C从机地址固定为0x41,基于第一节中介绍的硬件连接方式,所有的指令都应该通<Wire.h>库的硬件IIC进行下发和上传。在官方的《TMF8821 Host Driver Communication》文档提到了TMF的启动测量步骤:
总结下来可以分为7个步骤:1.设备准备检查。检查ENABLE寄存器(0xE0)确保设备就绪(bit6=1),若设备处于STANDBY状态(bit2=1),需先唤醒设备(写入0x21到ENABLE)2.应用模式验证。读取APPID寄存器(0x00)确认运行的是测量应用(值应为0x03),检查MODE寄存器(0x10)确认模式为TMF8821(值0x00)。3.配置加载。发送LOAD_CONFIG_PAGE_COMMON命令(0x16)加载通用配置页。4.工厂校准加载。此步骤可省略。5.中断设置配置INT_ENAB寄存器(0xE2)启用结果中断。6.启动测量。发送MEASURE命令(0x10)到CMD_STAT寄存器(0x08)轮询CMD_STAT直到返回STAT_ACCEPTED(0x01)7.结果读取。读取0x20-0xA3寄存器获取132字节结果数据。
// 步骤1: 检查设备是否准备好
if (!checkDeviceReady()) {
Serial.println("DeviceNotReady");
while(1);
}
// 步骤2: 确认应用模式 (APPID=0x03)
uint8_t appId = readRegister(REG_APPID);
if (appId != 0x03) {
Serial.print("EXITAPPID: 0x");
Serial.println(appId, HEX);
while(1);
}
// 步骤3: 配置设备(示例:设置测量周期100ms)
configureDevice();
// 步骤4: 加载工厂校准(需根据实际校准数据实现)
loadFactoryCalibration();
// 步骤5: 启动测量
sendCommand(CMD_MEASURE);
Serial.println("MEASURESTART...");
pinMode(INT_PIN, INPUT); // 设置INT引脚为输入
attachInterrupt(digitalPinToInterrupt(INT_PIN), intHandler, FALLING); // 下降沿触发中断
// 中断服务程序
void intHandler() {
newDataAvailable = true; // 设置标志位
}
// 检查设备是否就绪(ENABLE寄存器bit6=1)
bool checkDeviceReady() {
uint8_t retry = 10;
while (retry--) {
uint8_t val = readRegister(REG_ENABLE);
if ((val & 0x40) == 0x40) return true; // bit6=1表示就绪
delay(10);
}
return false;
}
void configureDevice() {
// 加载通用配置页
sendCommand(0x16); // LOAD_CONFIG_PAGE_COMMON
waitCommandDone();
// 设置为3x3 zones模式(根据具体的寄存器定义修改)
writeRegister(0x33, 0x03); // 假设寄存器0x33控制zone配置,值0x03选择3x3模式
// 修改测量周期为100ms(寄存器0x24-0x25)
writeRegister(0x24, 0x64); // LSB: 100 = 0x64
writeRegister(0x25, 0x00); // MSB: 0
// 提交配置
sendCommand(0x15); // WRITE_CONFIG_PAGE
waitCommandDone();
}
// 读取测量结果并打印
void readAndPrintResults() {
Wire.beginTransmission(TMF8821_ADDR);
Wire.write(REG_RESULT_START);
Wire.endTransmission(false);
uint8_t data[132];
Wire.requestFrom(TMF8821_ADDR, 132);
for (int i = 0; i < 132; i++) {
data[i] = Wire.read();
}
// 提取前4个距离值
for (int zone = 0; zone < 4; zone++) {
uint16_t distance = data[0x24 + zone * 3] | (data[0x25 + zone * 3] << 8);
uint8_t confidence = data[0x26 + zone * 3];
Serial.print("zone ");
Serial.print(zone);
Serial.print(": distance=");
Serial.print(distance);
Serial.println("\n");
//Serial.print(" mm, confidence=");
//Serial.println(confidence);
switch (zone) {
case 0:
zone0 = distance;
break;
case 1:
zone1 = distance;
break;
case 2:
zone2 = distance;
break;
case 3:
zone3 = distance;
break;
default:
break;
}
}
}
// 发送命令并等待接受
void sendCommand(uint8_t cmd) {
writeRegister(REG_CMD_STAT, cmd);
}
// 等待命令执行完成(STAT_OK=0x00)
void waitCommandDone() {
while (true) {
uint8_t stat = readRegister(REG_CMD_STAT);
if (stat == 0x00) break; // STAT_OK
else if (stat >= 0x10) continue; // 命令未处理完成
else {
Serial.print("errorcode: 0x");
Serial.println(stat, HEX);
break;
}
delay(1);
}
}
// 清除中断标志
void clearInterrupt(uint8_t reg, uint8_t mask) {
writeRegister(reg, mask);
}
// 读寄存器
uint8_t readRegister(uint8_t reg) {
Wire.beginTransmission(TMF8821_ADDR);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(TMF8821_ADDR, 1);
return Wire.read();
}
// 写寄存器
void writeRegister(uint8_t reg, uint8_t val) {
Wire.beginTransmission(TMF8821_ADDR);
Wire.write(reg);
Wire.write(val);
Wire.endTransmission();
}
上述代码主要将dTOF8821配置为3x3区域的读取模式,但是在读取寄存器的距离数值中,仅提取了前4个值,其中第一个值用于下一节的Matrix LED模块做矩阵显示使用,后面3个值用于第三节Arduino Cloud平台的Advanced Chart插件显示使用(一个Advanced Chart插件最多支持3个通道的显示)
2.2 Matrix LED矩阵显示模块代码编写
Arduino官方为UNO R4的Matrix LED矩阵提供了网站(Led Matrix Editor)用于一键生成图案数组,结合《Arduino_LED_Matrix.h》库即可在UNO R4板卡上展示对应的图案。以本次项目中的矩阵图案为例,先在Led Matrix Editor上绘制对应图案:
根据这些图案点击右上角的下载按钮,即可生成对应的数组:
const uint32_t fullOn[] = {
0xffffffff,
0xffffffff,
0xffffffff
};
const uint32_t two[] = {
0x0,
0xc000000,
0x0,
};
const uint32_t four[] = {
0x0,
0xf000000,
0x0,
};
const uint32_t six[] = {
0x0,
0xfc00000,
0x0,
};
const uint32_t eight[] = {
0x0,
0xff00000,
0x0,
};
const uint32_t ten[] = {
0x0,
0xffc0000,
0x0,
};
const uint32_t eleven[] = {
0x0,
0xffe0000,
0x0,
};
const uint32_t twelve[] = {
0x0,
0xffc0000,
0x0,
};
结合距离解析判断函数和matrixled.loadFrame();即可显示对应的图案:
void distancetodisplay(int distance){
if(distance<3000){
matrix.clear();
}else if((distance>=3000)&&(distance<5000)){
matrix.loadFrame(two);
}else if((distance>=5000)&&(distance<10000)){
matrix.loadFrame(four);
}else if((distance>=10000)&&(distance<15000)){
matrix.loadFrame(six);
}else if((distance>=15000)&&(distance<17500)){
matrix.loadFrame(eight);
}else if((distance>=17500)&&(distance<20000)){
matrix.loadFrame(ten);
}else if((distance>=20000)&&(distance<22500)){
matrix.loadFrame(eleven);
}else{
matrix.loadFrame(twelve);
}
}
2.3 Arduino Cloud 云平台编辑与使用
1. 首先在首页的Things选项卡中创建一个工程,依次在右侧Associated Device中选择UNO R4板卡,在NetWork中配置自己的无线路由名称与密码,配置界面如下图所示:
2. 在Things选项卡中切换到Sketch页面,在该页面编写工程相关代码,编写好代码后依次点击编译、下载按钮。首次使用应该下载Arduino Agnet插件方便Arduino Cloud访问本地硬件设备。
在Things选项卡中点击Setup,进入Cloud Variables页面,创建云平台与硬件开发板的交互变量,这里根据项目目标依次创建int型的Zone1、Zone2、Zone3的值。
最后在DashBoard选项卡中调用Advanced Chat插件并关联Zone1、Zone2、Zone3的值即可显示相关距离值
3.项目总结
本次项目通过Arduino的wire.h库的硬件IIC驱动了dTOF8821传感器获得了4路距离值,一路通过UNO R4的Matrix LED矩阵进行了矩阵显示,另外3路通过Arduino Cloud平台的Advanced Chat插件进行了实时显示。