vl6180距离传感器的idf代码
·
vl6180是一款激光距离传感器,stm32、arduino版的代码资料在网上一直都很丰富,但是基于esp_idf的代码却几乎没有,为了将vl6180移植至idf,我只能自己修改源码,经过测试,已确定移植成功,用的是新版的i2c_master驱动,现将代码分享出来,有需要的自取。
下载链接:https://gitee.com/Lelin_star/vl6180_idf
源文件Adafruit_VL6180X.c
//Adafruit_VL6180X.c
#include "Adafruit_VL6180X.h"
#include "driver/i2c_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
//2025.1.16测试成功
// 内部函数声明
static void load_settings(vl6180x_dev_t* dev);
static uint16_t read16(vl6180x_dev_t* dev, uint16_t register_address);
static uint8_t read8(vl6180x_dev_t* dev, uint16_t register_address);
static void write16(vl6180x_dev_t* dev, uint16_t register_address, uint16_t data);
static void write8(vl6180x_dev_t* dev, uint16_t register_address, uint8_t data);
bool vl6180x_init(vl6180x_dev_t* dev, uint8_t i2c_addr) {
if (dev == NULL) {
ESP_LOGE("VL6180X", "Device handle is NULL");
return false;
}
// 初始化设备结构体
dev->i2c_addr = i2c_addr;
dev->bus_handle = NULL;
dev->dev_handle = NULL;
dev->initialized = false;
// 初始化I2C主总线
i2c_master_bus_config_t bus_config = {
.i2c_port = I2C_NUM_1,
.sda_io_num = CONFIG_SDA_GPIO,
.scl_io_num = CONFIG_SCL_GPIO,
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true,
};
esp_err_t ret = i2c_new_master_bus(&bus_config, &dev->bus_handle);
if (ret != ESP_OK) {
ESP_LOGE("VL6180X", "I2C Bus Init Failed: %s", esp_err_to_name(ret));
return false;
}
// 添加设备到总线
i2c_device_config_t dev_config = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = dev->i2c_addr, // 修正:使用正确的成员名
.scl_speed_hz = 100000,
};
ret = i2c_master_bus_add_device(dev->bus_handle, &dev_config, &dev->dev_handle);
if (ret != ESP_OK) {
ESP_LOGE("VL6180X", "I2C Device Add Failed: %s", esp_err_to_name(ret));
i2c_del_master_bus(dev->bus_handle);
dev->bus_handle = NULL;
return false;
}
// 检查设备标识符
if (read8(dev, VL6180X_REG_IDENTIFICATION_MODEL_ID) != 0xB4) {
ESP_LOGE("VL6180X", "Model ID Mismatch");
vl6180x_cleanup(dev);
return false;
}
// 如果是新设备,加载设置
if (read8(dev, VL6180X_REG_SYSTEM_FRESH_OUT_OF_RESET)&0x01) {
load_settings(dev);
ESP_LOGI("VL6180X", "加载设置");
write8(dev, VL6180X_REG_SYSTEM_FRESH_OUT_OF_RESET, 0x00);
}
dev->initialized = true;
ESP_LOGI("VL6180X", "VL6180X initialized successfully at address 0x%02X", dev->i2c_addr);
return true;
}
void vl6180x_cleanup(vl6180x_dev_t* dev) {
if (dev == NULL) return;
if (dev->dev_handle != NULL) {
i2c_master_bus_rm_device(dev->dev_handle);
dev->dev_handle = NULL;
}
if (dev->bus_handle != NULL) {
i2c_del_master_bus(dev->bus_handle);
dev->bus_handle = NULL;
}
dev->initialized = false;
dev->i2c_addr = 0;
}
// 加载设备设置(与原始C++版本完全一致)
static void load_settings(vl6180x_dev_t* dev) {
// 私有设置
write8(dev, 0x0207, 0x01);
write8(dev, 0x0208, 0x01);
write8(dev, 0x0096, 0x00);
write8(dev, 0x0097, 0xfd);
write8(dev, 0x00e3, 0x00);
write8(dev, 0x00e4, 0x04);
write8(dev, 0x00e5, 0x02);
write8(dev, 0x00e6, 0x01);
write8(dev, 0x00e7, 0x03);
write8(dev, 0x00f5, 0x02);
write8(dev, 0x00d9, 0x05);
write8(dev, 0x00db, 0xce);
write8(dev, 0x00dc, 0x03);
write8(dev, 0x00dd, 0xf8);
write8(dev, 0x009f, 0x00);
write8(dev, 0x00a3, 0x3c);
write8(dev, 0x00b7, 0x00);
write8(dev, 0x00bb, 0x3c);
write8(dev, 0x00b2, 0x09);
write8(dev, 0x00ca, 0x09);
write8(dev, 0x0198, 0x01);
write8(dev, 0x01b0, 0x17);
write8(dev, 0x01ad, 0x00);
write8(dev, 0x00ff, 0x05);
write8(dev, 0x0100, 0x05);
write8(dev, 0x0199, 0x05);
write8(dev, 0x01a6, 0x1b);
write8(dev, 0x01ac, 0x3e);
write8(dev, 0x01a7, 0x1f);
write8(dev, 0x0030, 0x00);
// 推荐公共寄存器
write8(dev, 0x0011, 0x10);
write8(dev, 0x010a, 0x30);
write8(dev, 0x003f, 0x46);
write8(dev, 0x0031, 0xFF);
write8(dev, 0x0041, 0x63);
write8(dev, 0x002e, 0x01);
// 可选公共寄存器
write8(dev, SYSRANGE__INTERMEASUREMENT_PERIOD, 0x09);
write8(dev, 0x003e, 0x31);
write8(dev, 0x0014, 0x24);
}
uint8_t vl6180x_read_range(vl6180x_dev_t* dev) {
if (dev == NULL || !dev->initialized) {
ESP_LOGE("VL6180X", "Device not initialized");
return 0;
}
// 等待设备就绪
// ESP_LOGE("VL6180X", "等待设备就绪");
while ((read8(dev, VL6180X_REG_RESULT_RANGE_STATUS) & 0x01) == 0) {
vTaskDelay(pdMS_TO_TICKS(1));
}
// ESP_LOGE("VL6180X", "开始距离测量");
// 开始距离测量
write8(dev, VL6180X_REG_SYSRANGE_START, 0x01);
// ESP_LOGE("VL6180X", "等待测量完成");
// 等待测量完成
while (!(read8(dev, VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO) & 0x04)) {
// ESP_LOGE("VL6180X", "等待测量完成");
vTaskDelay(pdMS_TO_TICKS(100));
}
// ESP_LOGE("VL6180X", "读取距离值");
// 读取距离值
uint8_t range = read8(dev, VL6180X_REG_RESULT_RANGE_VAL);
// ESP_LOGE("VL6180X", "清除中断");
// 清除中断
write8(dev, VL6180X_REG_SYSTEM_INTERRUPT_CLEAR, 0x07);
return range;
}
uint8_t vl6180x_get_address(vl6180x_dev_t* dev) {
return (dev != NULL) ? dev->i2c_addr : 0;
}
// 读取距离测量状态
uint8_t vl6180x_read_range_status(vl6180x_dev_t* dev) {
if (dev == NULL || !dev->initialized) {
return VL6180X_ERROR_SYSERR_1;
}
return (read8(dev, VL6180X_REG_RESULT_RANGE_STATUS) >> 4);
}
// 开始单次距离测量
bool vl6180x_start_range(vl6180x_dev_t* dev) {
if (dev == NULL || !dev->initialized) return false;
// 等待设备就绪
while ((read8(dev, VL6180X_REG_RESULT_RANGE_STATUS) & 0x01) == 0) {
vTaskDelay(pdMS_TO_TICKS(1));
}
// 开始测量
write8(dev, VL6180X_REG_SYSRANGE_START, 0x01);
return true;
}
// 检查测量是否完成
bool vl6180x_is_range_complete(vl6180x_dev_t* dev) {
if (dev == NULL || !dev->initialized) return false;
return (read8(dev, VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO) & 0x04) != 0;
}
// 等待测量完成
bool vl6180x_wait_range_complete(vl6180x_dev_t* dev) {
while (!(read8(dev,VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO) & 0x04))
;
return true;
}
// 读取距离测量结果
uint8_t vl6180x_read_range_result(vl6180x_dev_t* dev) {
if (dev == NULL || !dev->initialized) return 0;
if (!vl6180x_wait_range_complete(dev)) {
ESP_LOGE("VL6180X", "Range measurement timeout");
return 0;
}
// 读取距离值
uint8_t range = read8(dev, VL6180X_REG_RESULT_RANGE_VAL);
// 清除中断
write8(dev, VL6180X_REG_SYSTEM_INTERRUPT_CLEAR, 0x07);
return range;
}
// 启动连续测量模式 [1,5](@ref)
void vl6180x_start_range_continuous(vl6180x_dev_t* dev, uint16_t period_ms) {
if (dev == NULL || !dev->initialized) return;
// 设置测量间隔
write8(dev, SYSRANGE__INTERMEASUREMENT_PERIOD, (uint8_t)(period_ms / 10));
// 启动连续测量模式
write8(dev, VL6180X_REG_SYSRANGE_START, 0x03); // 连续模式
}
// 停止连续测量
void vl6180x_stop_range_continuous(vl6180x_dev_t* dev) {
if (dev == NULL || !dev->initialized) return;
// 停止测量
write8(dev, VL6180X_REG_SYSRANGE_START, 0x02); // 停止命令
vTaskDelay(pdMS_TO_TICKS(10));
}
// 读取光照强度(LUX) [3,7](@ref)
float vl6180x_read_lux(vl6180x_dev_t* dev, uint8_t gain) {
if (dev == NULL || !dev->initialized) return -1.0f;
// 设置增益
if (gain > 7) gain = VL6180X_ALS_GAIN_1;
write8(dev, VL6180X_REG_SYSALS_ANALOGUE_GAIN, 0x40 | gain);
// 开始光照测量
write8(dev, VL6180X_REG_SYSALS_START, 0x01);
// 等待测量完成
uint16_t timeout = 0;
while ((read8(dev, VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO) & 0x20) == 0) {
vTaskDelay(pdMS_TO_TICKS(1));
if (timeout++ > 1000) {
ESP_LOGE("VL6180X", "ALS measurement timeout");
return -1.0f;
}
}
// 读取光照值
uint16_t als_value = read16(dev, VL6180X_REG_RESULT_ALS_VAL);
// 清除中断
write8(dev, VL6180X_REG_SYSTEM_INTERRUPT_CLEAR, 0x07);
// 根据增益计算LUX值 [3](@ref)
float gain_values[] = {20.0f, 10.0f, 5.0f, 2.5f, 1.67f, 1.25f, 1.0f, 40.0f};
float actual_gain = gain_values[gain];
// 积分时间默认为100ms
float integration_time = 100.0f;
float lux = (0.32f * als_value * actual_gain) / integration_time;
return lux;
}
// 设置距离偏移量 [2,5](@ref)
void vl6180x_set_offset(vl6180x_dev_t* dev, uint8_t offset) {
if (dev == NULL || !dev->initialized) return;
write8(dev, VL6180X_REG_SYSRANGE_PART_TO_PART_RANGE_OFFSET, offset);
}
// 读取设备ID信息
void vl6180x_get_id(vl6180x_dev_t* dev, uint8_t* id_buf) {
if (dev == NULL || id_buf == NULL) return;
id_buf[0] = read8(dev,VL6180X_REG_IDENTIFICATION_MODEL_ID + 0);
id_buf[1] = read8(dev,VL6180X_REG_IDENTIFICATION_MODEL_ID + 1);
id_buf[2] = read8(dev,VL6180X_REG_IDENTIFICATION_MODEL_ID + 2);
id_buf[3] = read8(dev,VL6180X_REG_IDENTIFICATION_MODEL_ID + 3);
id_buf[4] = read8(dev,VL6180X_REG_IDENTIFICATION_MODEL_ID + 4);
id_buf[6] = read8(dev,VL6180X_REG_IDENTIFICATION_MODEL_ID + 6);
id_buf[7] = read8(dev,VL6180X_REG_IDENTIFICATION_MODEL_ID + 7);
}
// I2C底层读写函数
static uint16_t read16(vl6180x_dev_t* dev, uint16_t register_address) {
if (dev == NULL || !dev->initialized) return 0xFFFF;
uint8_t read_buffer[2] = {0};
uint8_t reg_addr_buffer[2] = {
(uint8_t)(register_address >> 8),
(uint8_t)(register_address & 0xFF)
};
esp_err_t ret = i2c_master_transmit_receive(dev->dev_handle,
reg_addr_buffer, 2,
read_buffer, 2,
pdMS_TO_TICKS(1000));
if (ret != ESP_OK) {
ESP_LOGE("VL6180X", "Read16 failed at reg 0x%04X: %s",
register_address, esp_err_to_name(ret));
return 0xFFFF;
}
return (uint16_t)((read_buffer[0] << 8) | read_buffer[1]);
}
static uint8_t read8(vl6180x_dev_t* dev, uint16_t register_address) {
if (dev == NULL || dev->dev_handle == NULL) {
ESP_LOGE("VL6180X", "Invalid device handle");
return 0;
}
esp_err_t ret;
uint8_t data_byte = 0;
// 将16位寄存器地址拆分为高8位和低8位
uint8_t reg_addr_buffer[2] = {
(uint8_t)(register_address >> 8), // 寄存器地址高字节
(uint8_t)(register_address & 0xFF) // 寄存器地址低字节
};
// 使用新版I2C主驱动的复合传输函数
ret = i2c_master_transmit_receive(dev->dev_handle,
reg_addr_buffer, 2, // 写入寄存器地址
&data_byte, 1, // 读取1字节数据
pdMS_TO_TICKS(1000)); // 超时时间
if (ret != ESP_OK) {
ESP_LOGE("VL6180X", "Read8 failed at reg 0x%04X: %s", register_address, esp_err_to_name(ret));
return 0;
}
// printf("data_byte: 0x%02X\n", data_byte); // 调试时使用,正常后注释掉
return data_byte;
}
static void write16(vl6180x_dev_t* dev, uint16_t register_address, uint16_t data) {
if (dev == NULL || !dev->initialized) return;
uint8_t write_buffer[4] = {
(uint8_t)(register_address >> 8),
(uint8_t)(register_address & 0xFF),
(uint8_t)(data >> 8),
(uint8_t)(data & 0xFF)
};
esp_err_t ret = i2c_master_transmit(dev->dev_handle, write_buffer, 4, pdMS_TO_TICKS(1000));
if (ret != ESP_OK) {
ESP_LOGE("VL6180X", "Write16 failed at reg 0x%04X: %s",
register_address, esp_err_to_name(ret));
}
}
/**
* @brief 向VL6180X寄存器写入一个字节,并验证是否成功
* @param dev 设备句柄
* @param register_address 16位寄存器地址
* @param data 要写入的数据
* @return esp_err_t ESP_OK表示写入并验证成功,否则失败
*/
static void write8(vl6180x_dev_t* dev, uint16_t register_address, uint8_t data) {
if (dev == NULL || !dev->initialized) {
ESP_LOGE("VL6180X", "Device not initialized or NULL");
}
uint8_t write_buffer[3] = {
(uint8_t)(register_address >> 8), // 寄存器地址高字节
(uint8_t)(register_address & 0xFF), // 寄存器地址低字节
data // 要写入的数据
};
// 1. 执行写入操作
esp_err_t ret = i2c_master_transmit(dev->dev_handle, write_buffer, 3, pdMS_TO_TICKS(1000));
if (ret != ESP_OK) {
ESP_LOGE("VL6180X", "I2C transmit failed at reg 0x%04X: %s", register_address, esp_err_to_name(ret));
}
// 短暂延时,确保设备完成写入操作[5](@ref)
vTaskDelay(pdMS_TO_TICKS(1));
// 2. 立即读取刚写入的寄存器值
uint8_t read_back = read8(dev, register_address); // 假设您有对应的read8函数
// 3. 比对写入值和读取值
if (read_back != data) {
// ESP_LOGE("VL6180X", "Verify FAILED at reg 0x%04X: wrote 0x%02X, read 0x%02X",
// register_address, data, read_back);
vTaskDelay(pdMS_TO_TICKS(10));
}
ESP_LOGD("VL6180X", "Successfully wrote 0x%02X to register 0x%04X", data, register_address);
}
头文件Adafruit_VL6180X.h
//Adafruit_VL6180X.h
#ifndef _ADAFRUIT_VL6180X_H
#define _ADAFRUIT_VL6180X_H
#ifdef __cplusplus
extern "C" {
#endif
#include "driver/i2c_master.h"
#include "esp_err.h"
#include "esp_log.h"
#include <stdbool.h>
#include <stdint.h>
// 引脚配置
#ifndef CONFIG_SDA_GPIO
#define CONFIG_SDA_GPIO GPIO_NUM_39
#endif
#ifndef CONFIG_SCL_GPIO
#define CONFIG_SCL_GPIO GPIO_NUM_38
#endif
// 设备常量
#define VL6180X_DEFAULT_I2C_ADDR 0x29
// 寄存器地址
#define VL6180X_REG_IDENTIFICATION_MODEL_ID 0x000
#define VL6180X_REG_SYSTEM_INTERRUPT_CONFIG 0x014
#define VL6180X_REG_SYSTEM_INTERRUPT_CLEAR 0x015
#define VL6180X_REG_SYSTEM_FRESH_OUT_OF_RESET 0x016
#define VL6180X_REG_SYSRANGE_START 0x018
#define VL6180X_REG_SYSRANGE_PART_TO_PART_RANGE_OFFSET 0x024
#define VL6180X_REG_SYSALS_START 0x038
#define VL6180X_REG_SYSALS_ANALOGUE_GAIN 0x03F
#define VL6180X_REG_SYSALS_INTEGRATION_PERIOD_HI 0x040
#define VL6180X_REG_SYSALS_INTEGRATION_PERIOD_LO 0x041
#define VL6180X_REG_RESULT_RANGE_STATUS 0x04d
#define VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO 0x04f
#define VL6180X_REG_RESULT_ALS_VAL 0x050
#define VL6180X_REG_RESULT_RANGE_VAL 0x062
#define VL6180X_REG_SLAVE_DEVICE_ADDRESS 0x212
#define SYSRANGE__INTERMEASUREMENT_PERIOD 0x001b
// ALS增益设置
#define VL6180X_ALS_GAIN_1 0x06
#define VL6180X_ALS_GAIN_1_25 0x05
#define VL6180X_ALS_GAIN_1_67 0x04
#define VL6180X_ALS_GAIN_2_5 0x03
#define VL6180X_ALS_GAIN_5 0x02
#define VL6180X_ALS_GAIN_10 0x01
#define VL6180X_ALS_GAIN_20 0x00
#define VL6180X_ALS_GAIN_40 0x07
// 错误代码
#define VL6180X_ERROR_NONE 0
#define VL6180X_ERROR_SYSERR_1 1
#define VL6180X_ERROR_SYSERR_5 5
#define VL6180X_ERROR_ECEFAIL 6
#define VL6180X_ERROR_NOCONVERGE 7
#define VL6180X_ERROR_RANGEIGNORE 8
#define VL6180X_ERROR_SNR 11
#define VL6180X_ERROR_RAWUFLOW 12
#define VL6180X_ERROR_RAWOFLOW 13
#define VL6180X_ERROR_RANGEUFLOW 14
#define VL6180X_ERROR_RANGEOFLOW 15
// 设备句柄结构体
typedef struct {
uint8_t i2c_addr;
i2c_master_bus_handle_t bus_handle;
i2c_master_dev_handle_t dev_handle;
bool initialized;
} vl6180x_dev_t;
// 初始化函数
bool vl6180x_init(vl6180x_dev_t* dev, uint8_t i2c_addr);
void vl6180x_cleanup(vl6180x_dev_t* dev);
// 设备配置函数
bool vl6180x_set_address(vl6180x_dev_t* dev, uint8_t new_addr);
uint8_t vl6180x_get_address(vl6180x_dev_t* dev);
// 距离测量函数
uint8_t vl6180x_read_range(vl6180x_dev_t* dev);//从这往下都没定义
uint8_t vl6180x_read_range_status(vl6180x_dev_t* dev);
bool vl6180x_start_range(vl6180x_dev_t* dev);
bool vl6180x_is_range_complete(vl6180x_dev_t* dev);
bool vl6180x_wait_range_complete(vl6180x_dev_t* dev);
uint8_t vl6180x_read_range_result(vl6180x_dev_t* dev);
// 连续测量模式
void vl6180x_start_range_continuous(vl6180x_dev_t* dev, uint16_t period_ms);
void vl6180x_stop_range_continuous(vl6180x_dev_t* dev);
// 光照测量函数
float vl6180x_read_lux(vl6180x_dev_t* dev, uint8_t gain);
// 设备配置函数
void vl6180x_set_offset(vl6180x_dev_t* dev, uint8_t offset);
void vl6180x_get_id(vl6180x_dev_t* dev, uint8_t* id_buf);
uint8_t vl6180x_read_range_enhanced(vl6180x_dev_t* dev);
#ifdef __cplusplus
}
#endif
#endif
主程序main.c
//main.c
#include <stdio.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "Adafruit_VL6180X.h"
void app_main(void)
{
vl6180x_dev_t sensor;
bool n=0;
if (vl6180x_init(&sensor, VL6180X_DEFAULT_I2C_ADDR)) {
printf("VL6180X initialized successfully\n");
n=1;
printf("Distance: %d mm\n", n);
}
while(1) {
if(n!=0){
uint8_t distance = vl6180x_read_range(&sensor);// 读取距离
uint8_t status = vl6180x_read_range_status(&sensor);
// status == VL6180X_ERROR_NONE
if (status == VL6180X_ERROR_NONE) {
// uint8_t distance = vl6180x_read_range(&sensor);
printf("Distance: %d mm\n", distance);
}
// 清理资源
// vl6180x_cleanup(&sensor);
}
vTaskDelay(pdMS_TO_TICKS(10)); // 延时10ms
// printf("Diaaaaaa");
}
}


更多推荐
所有评论(0)