news 2026/6/27 4:14:09

CW32L012的TOF200C激光测距案例分享

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CW32L012的TOF200C激光测距案例分享

前言:本实验用CW32L012作为主控,TOF200C为激光测距模块,最终测得距离在串口助手中显示。

一、TOF200C传感器模块介绍:

TOF200C VL53L0X是ST公司推出的新一代 ToF 激光测距传感器,采用了第二代 FlightSenseTM技术,利用飞行时间(ToF)原理,通过光子的飞行来回时间与光速的计算,实现测距应用。较比上一代 VL6180X,新的器件将飞行时间测距长度扩展至 2 米,测量速度更快,能效更高。除此之外,为使集成度过程更加快捷方便, ST 公司为此也提供了 VL53L0X 软件 API(应用编程接口)以及完整的技术文档,通过主 IIC 接口,向应用端输出测距的数据,大大降低了开发难度。VL53L0X的感测能力可以支持各种功能,包括各种创新用户界面的手势感测或接近检测,扫地机器人、服务型机器人的障碍物探测与防撞系统,家电感应面板、笔记本电脑的用户存在检测或电源开关监控器,以及无人机和物联网(IoT)产品等。下附传感器实物图,CW32L012主板。

TOF200C激光测距模块

CW32L012主板

二、TOF200C工作原理

1.发射端:内置940nm 近红外 VCSEL(垂直腔面发射激光器),发射人眼安全(Class 1)的短激光脉冲。

2.接收端:反射光子经透镜与窄带滤光片(滤环境光),打到SPAD(单光子雪崩二极管)阵列。SPAD 单光子灵敏、雪崩放大,把弱光转为电脉冲。

3.计时与计算:内置TDC(时间数字转换器),皮秒级精度记录光子往返时间t。用TCSPC(时间相关单光子计数):发数百次脉冲,统计 “时间-光子数直方图”,取主峰得精准t。距离公式:d=ct/2(光速c≈3×10的八次方米每秒,÷2 因往返)

TOF200C优点:

1.窄带滤光 +阳光抑制算法,80klux 强光稳定。

2.内置玻璃盖板校准,不用用户写校准流程。

3.使用I2C+UART 双接口,用户可以自行选择。

三、软件讲解:

本TOF200C模块使用I2C进行通讯,下附Keil工程中代码例程:

vl53l0x_i2c.c以及vl53l0x_i2c.h ;bsp_VL53L0X.c以及bsp_VL53L0X.h;bsp_uart.c以及bsp_uart.h;main等核心文件

#include "vl53l0x_i2c.h" #include "cw32l012_gpio.h" #include "cw32l012_sysctrl.h" /* 端口定义 */ #define PORT_VL53L0x CW_GPIOB #define GPIO_SCL GPIO_PIN_6 #define GPIO_SDA GPIO_PIN_7 #define PORT_XSHUT CW_GPIOA #define GPIO_XSHUT GPIO_PIN_8 /* 简单循环延时 */ void Simple_Delay(uint32_t count) { while(count--) { __NOP(); } } /* 终极兼容延时:将频率降到 50kHz 左右,确保电平上升沿完整 */ #define IIC_DELAY() Simple_Delay(1000) /* 核心策略:不再切换输入/输出方向。 将 SDA 始终保持为开漏输出模式(Output_OD)。 - 当我们要发送 1 或读取时,向 ODR 写入 1(释放总线,靠上拉电阻拉高)。 - 当我们要发送 0 时,向 ODR 写入 0(强行拉低)。 */ #define SCL_LOW() PORT_VL53L0x->BRR = GPIO_SCL #define SCL_HIGH() PORT_VL53L0x->BSRR = GPIO_SCL #define SDA_LOW() PORT_VL53L0x->BRR = GPIO_SDA #define SDA_HIGH() PORT_VL53L0x->BSRR = GPIO_SDA #define SDA_GET() ((PORT_VL53L0x->IDR & GPIO_SDA) != 0) void VL53L0X_i2c_init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __SYSCTRL_GPIOA_CLK_ENABLE(); __SYSCTRL_GPIOB_CLK_ENABLE(); // SCL 和 SDA 全部配置为开漏输出 + 开启内部上拉 GPIO_InitStruct.Pins = GPIO_SCL | GPIO_SDA; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.IT = GPIO_IT_NONE; GPIO_Init(PORT_VL53L0x, &GPIO_InitStruct); // 强制开启内部上拉(防止外部电阻虚接) PORT_VL53L0x->PUR |= (GPIO_SCL | GPIO_SDA); // XSHUT 配置为推挽输出 GPIO_InitStruct.Pins = GPIO_XSHUT; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_Init(PORT_XSHUT, &GPIO_InitStruct); // 硬件复位流程 GPIO_WritePin(PORT_XSHUT, GPIO_XSHUT, GPIO_Pin_RESET); Simple_Delay(2000000); GPIO_WritePin(PORT_XSHUT, GPIO_XSHUT, GPIO_Pin_SET); Simple_Delay(2000000); SCL_HIGH(); SDA_HIGH(); } void IIC_Start(void) { SDA_HIGH(); SCL_HIGH(); IIC_DELAY(); SDA_LOW(); IIC_DELAY(); SCL_LOW(); IIC_DELAY(); } void IIC_Stop(void) { SCL_LOW(); SDA_LOW(); IIC_DELAY(); SCL_HIGH(); IIC_DELAY(); SDA_HIGH(); IIC_DELAY(); } uint8_t I2C_WaitAck(void) { uint16_t retry = 0; SDA_HIGH(); // 释放 SDA,让传感器有机会拉低它 IIC_DELAY(); SCL_HIGH(); IIC_DELAY(); // 给传感器留出应答时间 while(SDA_GET()) { retry++; if(retry > 5000) { IIC_Stop(); printf("WaitAck Timeout!\r\n"); // 增加调试打印 return 1; } } SCL_LOW(); IIC_DELAY(); return 0; } void Send_Byte(uint8_t dat) { uint8_t i; for(i = 0; i < 8; i++) { if(dat & 0x80) SDA_HIGH(); else SDA_LOW(); dat <<= 1; IIC_DELAY(); SCL_HIGH(); IIC_DELAY(); SCL_LOW(); IIC_DELAY(); } } uint8_t Read_Byte(uint8_t ack) { uint8_t i, receive = 0; SDA_HIGH(); // 释放总线 IIC_DELAY(); for(i = 0; i < 8; i++) { SCL_LOW(); IIC_DELAY(); SCL_HIGH(); IIC_DELAY(); receive <<= 1; if(SDA_GET()) receive++; IIC_DELAY(); } SCL_LOW(); IIC_DELAY(); if (ack) SDA_LOW(); else SDA_HIGH(); IIC_DELAY(); SCL_HIGH(); IIC_DELAY(); SCL_LOW(); IIC_DELAY(); return receive; } // ---------------- 以下为接口封装(保持不变) ---------------- uint8_t VL_IIC_Write_nByte(uint8_t SlaveAddress, uint8_t REG_Address, uint16_t len, uint8_t *buf) { IIC_Start(); Send_Byte(SlaveAddress); if(I2C_WaitAck()) { IIC_Stop(); return 1; } Send_Byte(REG_Address); if(I2C_WaitAck()) { IIC_Stop(); return 1; } while(len--) { Send_Byte(*buf++); if(I2C_WaitAck()) { IIC_Stop(); return 1; } } IIC_Stop(); return 0; } uint8_t VL_IIC_Read_nByte(uint8_t SlaveAddress, uint8_t REG_Address, uint16_t len, uint8_t *buf) { IIC_Start(); Send_Byte(SlaveAddress); if(I2C_WaitAck()) { IIC_Stop(); return 1; } Send_Byte(REG_Address); if(I2C_WaitAck()) { IIC_Stop(); return 1; } IIC_Start(); Send_Byte(SlaveAddress | 0x01); if(I2C_WaitAck()) { IIC_Stop(); return 1; } while(len) { *buf = Read_Byte(len > 1); buf++; len--; } IIC_Stop(); return 0; } uint8_t VL53L0X_write_multi(uint8_t address, uint8_t index, uint8_t *pdata, uint16_t count) { return VL_IIC_Write_nByte(address, index, count, pdata); } uint8_t VL53L0X_read_multi(uint8_t address, uint8_t index, uint8_t *pdata, uint16_t count) { return VL_IIC_Read_nByte(address, index, count, pdata); } uint8_t VL53L0X_write_byte(uint8_t address, uint8_t index, uint8_t data) { return VL_IIC_Write_nByte(address, index, 1, &data); } uint8_t VL53L0X_write_word(uint8_t address, uint8_t index, uint16_t data) { uint8_t b[2]; b[0]=(uint8_t)(data>>8); b[1]=(uint8_t)data; return VL_IIC_Write_nByte(address, index, 2, b); } uint8_t VL53L0X_write_dword(uint8_t address, uint8_t index, uint32_t data) { uint8_t b[4]; b[0]=(uint8_t)(data>>24); b[1]=(uint8_t)(data>>16); b[2]=(uint8_t)(data>>8); b[3]=(uint8_t)data; return VL_IIC_Write_nByte(address, index, 4, b); } uint8_t VL53L0X_read_byte(uint8_t address, uint8_t index, uint8_t *pdata) { return VL_IIC_Read_nByte(address, index, 1, pdata); } uint8_t VL53L0X_read_word(uint8_t address, uint8_t index, uint16_t *pdata) { uint8_t b[2]; uint8_t s=VL_IIC_Read_nByte(address, index, 2, b); *pdata=((uint16_t)b[0]<<8)|b[1]; return s; } uint8_t VL53L0X_read_dword(uint8_t address, uint8_t index, uint32_t *pdata) { uint8_t b[4]; uint8_t s=VL_IIC_Read_nByte(address, index, 4, b); *pdata=((uint32_t)b[0]<<24)|((uint32_t)b[1]<<16)|((uint32_t)b[2]<<8)|b[3]; return s; } #ifndef __VL53L0_I2C_H #define __VL53L0_I2C_H #include <stdint.h> // 1. 统一使用标准库定义的类型(兼容旧代码) typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; // 2. 状态定义 #define STATUS_OK 0x00 #define STATUS_FAIL 0x01 // 3. I2C 底层操作函数声明 void VL53L0X_i2c_init(void); // 初始化引脚和复位传感器 void IIC_Start(void); // 起始信号 void IIC_Stop(void); // 停止信号 uint8_t I2C_WaitAck(void); // 等待应答 void Send_Byte(uint8_t dat); // 发送字节 uint8_t Read_Byte(uint8_t ack); // 读取字节 // 4. VL53L0X 官方 API 所需的底层读写接口声明 // 这些声明必须存在,否则 vl53l0x_platform.c 编译会报错 uint8_t VL53L0X_write_multi(uint8_t address, uint8_t index, uint8_t *pdata, uint16_t count); uint8_t VL53L0X_read_multi(uint8_t address, uint8_t index, uint8_t *pdata, uint16_t count); uint8_t VL53L0X_write_byte(uint8_t address, uint8_t index, uint8_t data); uint8_t VL53L0X_write_word(uint8_t address, uint8_t index, uint16_t data); uint8_t VL53L0X_write_dword(uint8_t address, uint8_t index, uint32_t data); uint8_t VL53L0X_read_byte(uint8_t address, uint8_t index, uint8_t *pdata); uint8_t VL53L0X_read_word(uint8_t address, uint8_t index, uint16_t *pdata); uint8_t VL53L0X_read_dword(uint8_t address, uint8_t index, uint32_t *pdata); #endif
#include "bsp_vl53l0x.h" #include "cw32l012_gpio.h" #include "cw32l012_sysctrl.h" #include "stdio.h" /* 外部延时函数声明 (需在main或sysctrl.c中实现) */ extern void delay_ms(uint32_t ms); /* 全局变量定义 */ VL53L0X_RangingMeasurementData_t vl53l0x_data; VL53L0X_Dev_t vl53l0x_dev; // 设备数据参数 VL53L0X_DeviceInfo_t vl53l0x_dev_info; // 设备信息 uint8_t AjustOK = 0; // 校准标志位 /* 测量模式参数(严格对照你提供的官方建议配置) */ mode_data Mode_data[] = { {(FixPoint1616_t)(0.25*65536), (FixPoint1616_t)(18*65536), 33000, 14, 10}, // 默认 {(FixPoint1616_t)(0.25*65536), (FixPoint1616_t)(18*65536), 200000, 14, 10},// 高精度 {(FixPoint1616_t)(0.1*65536) , (FixPoint1616_t)(60*65536), 33000, 18, 14}, // 长距离 {(FixPoint1616_t)(0.25*65536), (FixPoint1616_t)(32*65536), 20000, 14, 10} // 高速 }; /** * @brief 打印 PAL 层错误信息 * @note 依赖你提供的串口重定向 printf */ void print_pal_error(VL53L0X_Error Status) { char buf[VL53L0X_MAX_STRING_LENGTH]; VL53L0X_GetPalErrorString(Status, buf); printf("VL53L0X Error: %i : %s\r\n", Status, buf); } /** * @brief VL53L0X 综合初始化 * @note 适配 CW32L012 寄存器与引脚控制 */ VL53L0X_Error vl53l0x_init(VL53L0X_Dev_t *dev) { VL53L0X_Error Status = VL53L0X_ERROR_NONE; uint32_t refSpadCount; uint8_t isApertureSpads; uint8_t VhvSettings; uint8_t PhaseCal; // 1. 初始化 XSHUT 引脚 (PA8) - CW32风格 __SYSCTRL_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pins = GPIO_PIN_8; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_Init(CW_GPIOA, &GPIO_InitStruct); // 2. 初始化底层 I2C 接口 (调用适配过的模拟I2C) VL53L0X_i2c_init(); // 3. 硬件唤醒流程 (CW32引脚操作) GPIO_WritePin(CW_GPIOA, GPIO_PIN_8, GPIO_Pin_RESET); // XSHUT LOW delay_ms(20); GPIO_WritePin(CW_GPIOA, GPIO_PIN_8, GPIO_Pin_SET); // XSHUT HIGH delay_ms(20); // 4. 设备基础设置 dev->I2cDevAddr = 0x52; // 默认地址 dev->comms_type = 1; // I2C 模式 dev->comms_speed_khz = 400; // 5. 数据初始化 Status = VL53L0X_DataInit(dev); if(Status != VL53L0X_ERROR_NONE) goto error; // 6. 获取设备信息 Status = VL53L0X_GetDeviceInfo(dev, &vl53l0x_dev_info); if(Status != VL53L0X_ERROR_NONE) goto error; // 7. 静态初始化 Status = VL53L0X_StaticInit(dev); if(Status != VL53L0X_ERROR_NONE) goto error; // 8. 参考 Spad 管理与校准 Status = VL53L0X_PerformRefSpadManagement(dev, &refSpadCount, &isApertureSpads); if(Status != VL53L0X_ERROR_NONE) goto error; Status = VL53L0X_PerformRefCalibration(dev, &VhvSettings, &PhaseCal); if(Status != VL53L0X_ERROR_NONE) goto error; // 9. 设置为连续测量模式 Status = VL53L0X_SetDeviceMode(dev, VL53L0X_DEVICEMODE_CONTINUOUS_RANGING); if(Status != VL53L0X_ERROR_NONE) goto error; printf("VL53L0X HW Init Success!\r\n"); return VL53L0X_ERROR_NONE; error: print_pal_error(Status); return Status; } /** * @brief 设置测量模式 */ VL53L0X_Error vl53l0x_set_mode(VL53L0X_Dev_t *dev, uint8_t mode) { VL53L0X_Error Status = VL53L0X_ERROR_NONE; if(mode > 3) return VL53L0X_ERROR_INVALID_PARAMS; Status = VL53L0X_SetLimitCheckValue(dev, VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, Mode_data[mode].signalLimit); if(Status != VL53L0X_ERROR_NONE) return Status; Status = VL53L0X_SetLimitCheckValue(dev, VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, Mode_data[mode].sigmaLimit); if(Status != VL53L0X_ERROR_NONE) return Status; Status = VL53L0X_SetMeasurementTimingBudgetMicroSeconds(dev, Mode_data[mode].timingBudget); if(Status != VL53L0X_ERROR_NONE) return Status; Status = VL53L0X_SetVcselPulsePeriod(dev, VL53L0X_VCSEL_PERIOD_PRE_RANGE, Mode_data[mode].preRangeVcselPeriod); if(Status != VL53L0X_ERROR_NONE) return Status; Status = VL53L0X_SetVcselPulsePeriod(dev, VL53L0X_VCSEL_PERIOD_FINAL_RANGE, Mode_data[mode].finalRangeVcselPeriod); return Status; } #ifndef __BSP_VL53L0X_H #define __BSP_VL53L0X_H #include "vl53l0x_api.h" #include "vl53l0x_platform.h" #include "cw32l012.h" #include "cw32l012_gpio.h" #include <stdint.h> /* XSHUT 引脚控制宏 (PA8) - 适配 CW32 库函数 */ #define VL53L0X_XSHUT_LOW() GPIO_WritePin(CW_GPIOA, GPIO_PIN_8, GPIO_Pin_RESET) #define VL53L0X_XSHUT_HIGH() GPIO_WritePin(CW_GPIOA, GPIO_PIN_8, GPIO_Pin_SET) /* 测量模式宏定义 */ #define Default_Mode 0 #define HIGH_ACCURACY 1 #define LONG_RANGE 2 #define HIGH_SPEED 3 /* 模式参数结构体定义 */ typedef struct { FixPoint1616_t signalLimit; FixPoint1616_t sigmaLimit; uint32_t timingBudget; uint8_t preRangeVcselPeriod; uint8_t finalRangeVcselPeriod; } mode_data; /* 全局变量外部声明 (必须与 .c 文件中的定义严格对应) */ extern VL53L0X_Dev_t vl53l0x_dev; extern VL53L0X_RangingMeasurementData_t vl53l0x_data; extern mode_data Mode_data[]; extern uint8_t AjustOK; /* 函数声明 */ /** * @brief VL53L0X 综合初始化 * @param dev 设备结构体指针 * @return VL53L0X_Error 错误码 */ VL53L0X_Error vl53l0x_init(VL53L0X_Dev_t *dev); /** * @brief 设置测量模式(默认/高精度/长距离/高速) * @param dev 设备结构体指针 * @param mode 模式编号 (0-3) * @return VL53L0X_Error 错误码 */ VL53L0X_Error vl53l0x_set_mode(VL53L0X_Dev_t *dev, uint8_t mode); /** * @brief 打印 PAL 层错误信息到串口 * @param Status 错误状态码 */ void print_pal_error(VL53L0X_Error Status); /** * @brief 底层模拟 I2C 初始化 * @note 内部配置 PB6, PB7 为开漏输出 */ void VL53L0X_i2c_init(void); #endif
#include "bsp_uart.h" #include "stdio.h" #include "cw32l012_sysctrl.h" #include "cw32l012_gpio.h" #include "cw32l012_uart.h" uint8_t u1_recv_buff[USART1_RECEIVE_LENGTH]; // 接收缓冲区 uint16_t u1_recv_length = 0; // 接收数据长度 uint8_t u1_recv_flag = 0; // 接收完成标志位 /** * @brief 串口1初始化 * @param __Baud 波特率 */ void uart1_init(uint32_t __Baud) { // 1. 开启 GPIOA 和 UART1 时钟 __SYSCTRL_GPIOA_CLK_ENABLE(); __SYSCTRL_UART1_CLK_ENABLE(); // 2. 引脚配置 (TX: PA09, RX: PA10) GPIO_InitTypeDef GPIO_InitStruct = {0}; // TX 引脚: PA09 GPIO_InitStruct.Pins = GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_Init(CW_GPIOA, &GPIO_InitStruct); PA09_AFx_UART1TXD(); // 修正:使用对应的 PA09 复用函数 // RX 引脚: PA10 GPIO_InitStruct.Pins = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP; // 建议开启上拉,防止浮空噪声 GPIO_Init(CW_GPIOA, &GPIO_InitStruct); PA10_AFx_UART1RXD(); // 修正:使用对应的 PA10 复用函数 // 3. UART 参数配置 UART_InitTypeDef UART_InitStruct = {0}; UART_InitStruct.UART_BaudRate = __Baud; UART_InitStruct.UART_Source = UART_Source_PCLK; UART_InitStruct.UART_UclkFreq = SystemCoreClock; // 自动获取系统主频 UART_InitStruct.UART_Mode = UART_Mode_Rx | UART_Mode_Tx; // 开启全双工 UART_Init(CW_UART1, &UART_InitStruct); // 4. 中断配置 // 使使能接收完成中断 (RC) 和 接收空闲中断 (RXIDLE) UART_ITConfig(CW_UART1, UART_IT_RC | UART_IT_RXIDLE, ENABLE); UART_ClearITPendingBit(CW_UART1, UART_IT_RC); UART_ClearITPendingBit(CW_UART1, UART_IT_RXIDLE); NVIC_SetPriority(UART1_IRQn, 0); NVIC_EnableIRQ(UART1_IRQn); } /** * @brief printf 重定向 */ int fputc(int ch, FILE *f) { UART_SendData(CW_UART1, (uint8_t)ch); // 等待发送缓冲区空 while( UART_GetFlagStatus(CW_UART1, UART_FLAG_TXE) == RESET ); return ch; } /** * @brief 清除接收缓冲区 */ void uart1_receive_clear(void) { u1_recv_length = 0; u1_recv_flag = 0; } /** * @brief 获取接收到的数据 */ uint8_t *uart1_get_data(void) { if( u1_recv_flag == 1 ) { return u1_recv_buff; } return NULL; } /** * @brief 串口1中断服务函数 */ void UART1_IRQHandler(void) { // 1. 处理接收完成中断 (RC) if (UART_GetITStatus(CW_UART1, UART_IT_RC) != RESET) { if (u1_recv_length < USART1_RECEIVE_LENGTH - 1) // 预留一个位置给 '\0' { u1_recv_buff[u1_recv_length++] = UART_ReceiveData(CW_UART1); } UART_ClearITPendingBit(CW_UART1, UART_IT_RC); } // 2. 处理接收空闲中断 (RXIDLE) if (UART_GetITStatus(CW_UART1, UART_IT_RXIDLE) != RESET) { UART_ClearITPendingBit(CW_UART1, UART_IT_RXIDLE); // 必须先清除标志位 if (u1_recv_length > 0) { u1_recv_buff[u1_recv_length] = '\0'; // 结尾补零 u1_recv_flag = 1; // 标记一帧数据接收完成 } } } #ifndef __BSP_UART_H #define __BSP_UART_H #include "cw32l012.h" #include <stdint.h> #include <stdio.h> // 串口缓冲区的数据长度 #define USART1_RECEIVE_LENGTH 128 // 修正:extern 数组时最好带上长度,或者统一格式 extern uint8_t u1_recv_buff[USART1_RECEIVE_LENGTH]; extern uint16_t u1_recv_length; extern uint8_t u1_recv_flag; // 外部可调用函数声明 void uart1_init(uint32_t Baud); void uart1_receive_clear(void); uint8_t *uart1_get_data(void); #endif
#include "cw32l012.h" #include "cw32l012_sysctrl.h" #include "cw32l012_gpio.h" #include "bsp_uart.h" #include "bsp_VL53L0X.h" #include "vl53l0x_gen.h" #include "vl53l0x_api.h" // 确保包含 API 头文件 #include <stdio.h> // 统一使用简单延时 extern void Simple_Delay(uint32_t count); void RCC_Configuration(void) { SystemCoreClockUpdate(); } int main(void) { VL53L0X_Error Status = VL53L0X_ERROR_NONE; RCC_Configuration(); uart1_init(115200); Simple_Delay(5000000); printf("\r\n--- CW32 VL53L0X START ---\r\n"); // 第一步:硬件引脚初始化 printf("Step 1: Init I2C Pins...\r\n"); VL53L0X_i2c_init(); // 快速扫描验证 (只需确认 0x29 是否存在) IIC_Start(); Send_Byte(0x52); // VL53L0X 默认写地址 (0x29 << 1) if (I2C_WaitAck() == 0) { printf("I2C Check: Device Found at 0x29!\r\n"); } else { printf("I2C Check: Device NOT Found! Check wiring/XSHUT.\r\n"); } IIC_Stop(); printf("Step 1: Done.\r\n"); // 第二步:传感器软件初始化 (逐步执行) printf("Step 2-1: VL53L0X_DataInit...\r\n"); vl53l0x_dev.I2cDevAddr = 0x52; // 显式指定地址 Status = VL53L0X_DataInit(&vl53l0x_dev); if(Status != VL53L0X_ERROR_NONE) { printf("DataInit FAILED! Error: %d\r\n", Status); } else { printf("DataInit Success! Next: StaticInit...\r\n"); Status = VL53L0X_StaticInit(&vl53l0x_dev); if(Status != VL53L0X_ERROR_NONE) { printf("StaticInit FAILED! Error: %d\r\n", Status); } else { printf("StaticInit Success! Next: SpadManagement...\r\n"); // 这一步最耗时,如果卡住,请多等一会儿 uint32_t refSpadCount; uint8_t isApertureSpads; Status = VL53L0X_PerformRefSpadManagement(&vl53l0x_dev, &refSpadCount, &isApertureSpads); if(Status != VL53L0X_ERROR_NONE) { printf("SpadManagement FAILED! Error: %d\r\n", Status); } else { printf("Step 2: ALL SUCCESS!\r\n"); } } } // 第三步:配置测量模式 (默认使用单次测量) if(Status == VL53L0X_ERROR_NONE) { vl53l0x_set_mode(&vl53l0x_dev, 0); printf("Sensor Ready to Range...\r\n"); } while(1) { if(Status == VL53L0X_ERROR_NONE) { Status = VL53L0X_PerformSingleRangingMeasurement(&vl53l0x_dev, &vl53l0x_data); if(Status == VL53L0X_ERROR_NONE) { printf("Distance: %d mm\r\n", vl53l0x_data.RangeMilliMeter); } else { printf("Ranging Error: %d\r\n", Status); } } else { printf("Sensor Error State, check hardware.\r\n"); Simple_Delay(10000000); } Simple_Delay(5000000); } } void assert_failed(uint8_t *file, uint32_t line) { while (1); }

四、总结与建议:

1.TOF200C为红外 dToF 激光测距,靠光飞行时间算距离,精度比超声波高、体积小。

2.量程20cm~2m,室内好用,斜测、黑面、镜面、强光下容易不准。

3.只做近距离室内测距 / 避障选TOF200C,远距离别用。

4.必须3.3V 供电,不能 5V;安装垂直正对障碍物。

5.程序加多次取平均滤波,数值更稳。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/27 4:11:31

移动物联网AI-IoT创新发展论坛在沪成功举办,利尔达蜂窝一体化方案引关注

2026年6月25日下午&#xff0c;移动物联网AI-IoT创新发展论坛在沪成功举办。本次论坛由中国信息通信研究院主办&#xff0c;中移物联网有限公司、联通数字科技有限公司、移动物联网发展方阵、华为技术有限公司共同承办。中国通信标准化协会理事长闻库、中国信息通信研究院首席专…

作者头像 李华
网站建设 2026/6/27 4:06:02

2026 年6月龙虾 AI 智能体工具盘点 AionClaw等五款自动化工具分行业测评

前置免责声明 本文仅围绕 OpenClaw 开源框架展开技术实测与架构分析&#xff0c;文中提及的各类衍生发行版无任何商业合作、付费推广导向&#xff0c;所有性能数据均基于固定测试环境复现&#xff0c;仅作开发者技术选型参考&#xff0c;不构成工具采购建议。金融相关工具仅用于…

作者头像 李华
网站建设 2026/6/27 4:03:23

永恒岛 - 高清版手游官网下载:永恒岛高清版最新官方下载渠道

永恒岛 - 高清版手游官网下载&#xff1a;永恒岛高清版最新官方下载渠道 《永恒岛 - 高清版》又名《彩虹岛永恒岛高清复刻版》《彩虹岛怀旧高清服》《永恒岛三端互通版》《彩虹岛横版休闲冒险手游》&#xff0c;由安徽游昕联合忆往游戏运营的正版横版冒险 MMORPG 手游。1:1 高…

作者头像 李华
网站建设 2026/6/27 4:03:11

福州整木定制避坑指南:豪宅装修选木作,这三点比品牌更重要

在福州做过豪宅装修的人大多有个共识&#xff1a;整木定制是最容易超预算、也最容易出效果的环节。门墙柜一体化做得好&#xff0c;整个家的高级感会直接拉满&#xff1b;一旦工艺不过关、落地不到位&#xff0c;几十万砸下去也可能满是瑕疵。很多业主一开始只盯着大牌名号&…

作者头像 李华
网站建设 2026/6/27 4:02:24

AI财报复盘资料整理工具,标的信息归档辅助平台梳理

AI财报复盘资料整理工具&#xff0c;标的信息归档辅助平台梳理 开篇 长期自主梳理上市公司资料、定期完成盘面复盘的使用者&#xff0c;大多会遭遇信息碎片化的困扰&#xff1a;历年财报PDF、券商深度研报、行业政策资讯、每日盘面观察笔记分散存储在多款AI工具中&#xff0c…

作者头像 李华