基于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!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.程序加多次取平均滤波,数值更稳。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分