• 正文
  • 相关推荐
申请入驻 产业图谱

CW32L012的TOF200C激光测距案例分享

05/27 11:39
Image675
加入交流群
Image 扫码加入
获取工程师必备礼包
参与热点资讯讨论

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

一、TOF200C传感器模块介绍:

TOF200C VL53L0X是ST公司推出的新一代 ToF 激光测距传感器,采用了第二代 FlightSenseTM技术,利用飞行时间(ToF)原理,通过光子的飞行来回时间与光速的计算,实现测距应用。较比上一代 VL6180X,新的器件将飞行时间测距长度扩展至 2 米,测量速度更快,能效更高。

除此之外,为使集成度过程更加快捷方便, ST 公司为此也提供了 VL53L0X 软件 API(应用编程接口)以及完整的技术文档,通过主 IIC 接口,向应用端输出测距的数据,大大降低了开发难度。VL53L0X的感测能力可以支持各种功能,包括各种创新用户界面的手势感测或接近检测,扫地机器人、服务型机器人的障碍物探测与防撞系统,家电感应面板、笔记本电脑的用户存在检测或电源开关监控器,以及无人机物联网(IoT)产品等。下附传感器实物图,CW32L012主板。

Image

TOF200C激光测距模块

Image

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!rn"); // 增加调试打印            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 : %srn", 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!rn");    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) // 预留一个位置给 ''        {            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] = ''; // 结尾补零            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("rn--- CW32 VL53L0X START ---rn");    // 第一步:硬件引脚初始化    printf("Step 1: Init I2C Pins...rn");    VL53L0X_i2c_init(); 
    // 快速扫描验证 (只需确认 0x29 是否存在)    IIC_Start();    Send_Byte(0x52); // VL53L0X 默认写地址 (0x29 << 1)    if (I2C_WaitAck() == 0) {        printf("I2C Check: Device Found at 0x29!rn");    } else {        printf("I2C Check: Device NOT Found! Check wiring/XSHUT.rn");    }    IIC_Stop();    printf("Step 1: Done.rn");    // 第二步:传感器软件初始化 (逐步执行)    printf("Step 2-1: VL53L0X_DataInit...rn");    vl53l0x_dev.I2cDevAddr = 0x52; // 显式指定地址    Status = VL53L0X_DataInit(&vl53l0x_dev);     if(Status != VL53L0X_ERROR_NONE) {        printf("DataInit FAILED! Error: %drn", Status);    } else {        printf("DataInit Success! Next: StaticInit...rn");
        Status = VL53L0X_StaticInit(&vl53l0x_dev);        if(Status != VL53L0X_ERROR_NONE) {            printf("StaticInit FAILED! Error: %drn", Status);        } else {            printf("StaticInit Success! Next: SpadManagement...rn");
            // 这一步最耗时,如果卡住,请多等一会儿            uint32_t refSpadCount;            uint8_t isApertureSpads;            Status = VL53L0X_PerformRefSpadManagement(&vl53l0x_dev, &refSpadCount, &isApertureSpads);            if(Status != VL53L0X_ERROR_NONE) {                printf("SpadManagement FAILED! Error: %drn", Status);            } else {                printf("Step 2: ALL SUCCESS!rn");            }        }    }    // 第三步:配置测量模式 (默认使用单次测量)    if(Status == VL53L0X_ERROR_NONE) {        vl53l0x_set_mode(&vl53l0x_dev, 0);         printf("Sensor Ready to Range...rn");    }    while(1) {        if(Status == VL53L0X_ERROR_NONE) {            Status = VL53L0X_PerformSingleRangingMeasurement(&vl53l0x_dev, &vl53l0x_data);            if(Status == VL53L0X_ERROR_NONE) {                printf("Distance: %d mmrn", vl53l0x_data.RangeMilliMeter);            } else {                printf("Ranging Error: %drn", Status);            }        } else {            printf("Sensor Error State, check hardware.rn");            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.程序加多次取平均滤波,数值更稳。

Image
扫码加入QQ群 3群| 610403240

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录

以开放、共享、互助为理念,致力于构建武汉芯源半导体CW32系列MCU生态社区。无论是嵌入式MCU小自还是想要攻破技术难题的工程师,亦或是需求解决方案的产品经理都可在CW32生态社区汲取营养、共同成长。