用一组iic总线驱动多个lv6180x模块。
//头文件
#ifndef __VL6180X_H
#define __VL6180X_H
#include "./board_iic/myiic.h"
#include "./delay/delay.h"
/*iic驱动移植****************************/
#define I2C_Init iic_init
#define I2C_Start iic_start
#define I2C_Stop iic_stop
#define I2C_Wait_Ack iic_wait_ack
#define I2C_Send_Byte iic_send_byte
#define I2C_Read_Byte iic_read_byte
/*************************************/
#define LV6180x_MODULE_NUM_MAX 4 //最大连接4个模块
//模块地址
#define LV6180x_MODULE_1_ADDR 0x2a
#define LV6180x_MODULE_2_ADDR 0x2b
#define LV6180x_MODULE_3_ADDR 0x2c
#define LV6180x_MODULE_4_ADDR 0x2d
typedef enum
{
LV6180x_MODULE_1,
LV6180x_MODULE_2,
LV6180x_MODULE_3,
LV6180x_MODULE_4,
LV6180x_MODULE_MAX //模块数量不要超过4个
}lv6180x_module_name;
typedef struct
{
GPIO_TypeDef* GPIOx;
uint16_t GPIO_Pin;
}lv6180x_shdn_gpio;
typedef struct
{
uint8_t lv6180x_iic_addr;
lv6180x_shdn_gpio lv6180x_shdn;
}lv6180x_module_info;
uint8_t VL6180X_Init(void);
//距离单位毫米
uint8_t VL6180X_Read_Range(lv6180x_module_name lv6180x_name);
#endif
//.c驱动文件
#include "vl6180x.h"
#include <string.h>
/*寄存器**************************************************************************************/
#define VL6180X_DEFAULT_ID 0xB4
//#define I2C_DEBUG
#define VL6180X_DEFAULT_I2C_ADDR 0x29 ///< The fixed I2C addres
/*------------------VL6180X内部寄存器------------------*/
///! Device model identification number
#define VL6180X_REG_IDENTIFICATION_MODEL_ID 0x000
///! Interrupt configuration
#define VL6180X_REG_SYSTEM_INTERRUPT_CONFIG 0x014
///! Interrupt clear bits
#define VL6180X_REG_SYSTEM_INTERRUPT_CLEAR 0x015
///! Fresh out of reset bit
#define VL6180X_REG_SYSTEM_FRESH_OUT_OF_RESET 0x016
///! Trigger Ranging
#define VL6180X_REG_SYSRANGE_START 0x018
///! Trigger Lux Reading
#define VL6180X_REG_SYSALS_START 0x038
///! Lux reading gain
#define VL6180X_REG_SYSALS_ANALOGUE_GAIN 0x03F
///! Integration period for ALS mode, high byte
#define VL6180X_REG_SYSALS_INTEGRATION_PERIOD_HI 0x040
///! Integration period for ALS mode, low byte
#define VL6180X_REG_SYSALS_INTEGRATION_PERIOD_LO 0x041
///! Specific error codes
#define VL6180X_REG_RESULT_RANGE_STATUS 0x04d
///! Interrupt status
#define VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO 0x04f
///! Light reading value
#define VL6180X_REG_RESULT_ALS_VAL 0x050
///! Ranging reading value
#define VL6180X_REG_RESULT_RANGE_VAL 0x062
#define VL6180X_ALS_GAIN_1 0x06 ///< 1x gain
#define VL6180X_ALS_GAIN_1_25 0x05 ///< 1.25x gain
#define VL6180X_ALS_GAIN_1_67 0x04 ///< 1.67x gain
#define VL6180X_ALS_GAIN_2_5 0x03 ///< 2.5x gain
#define VL6180X_ALS_GAIN_5 0x02 ///< 5x gain
#define VL6180X_ALS_GAIN_10 0x01 ///< 10x gain
#define VL6180X_ALS_GAIN_20 0x00 ///< 20x gain
#define VL6180X_ALS_GAIN_40 0x07 ///< 40x gain
#define VL6180X_ERROR_NONE 0 ///< Success!
#define VL6180X_ERROR_SYSERR_1 1 ///< System error
#define VL6180X_ERROR_SYSERR_5 5 ///< Sysem error
#define VL6180X_ERROR_ECEFAIL 6 ///< Early convergence estimate fail
#define VL6180X_ERROR_NOCONVERGE 7 ///< No target detected
#define VL6180X_ERROR_RANGEIGNORE 8 ///< Ignore threshold check failed
#define VL6180X_ERROR_SNR 11 ///< Ambient conditions too high
#define VL6180X_ERROR_RAWUFLOW 12 ///< Raw range algo underflow
#define VL6180X_ERROR_RAWOFLOW 13 ///< Raw range algo overflow
#define VL6180X_ERROR_RANGEUFLOW 14 ///< Raw range algo underflow
#define VL6180X_ERROR_RANGEOFLOW 15 ///< Raw range algo overflow
/*end****************************************************************************************/
//注册模块
static lv6180x_module_info s_lv6180x_module_info_t[LV6180x_MODULE_MAX]=
{
{LV6180x_MODULE_1_ADDR,GPIOB,GPIO_PIN_5},
{LV6180x_MODULE_2_ADDR,GPIOB,GPIO_PIN_3},
{0x00,NULL,0},
{0x00,NULL,0},
};//模块信息参数
//------------------------------------------------------
//支持lv6180x多模块连接在一组iic总线上
//shdn引脚输出电平
static void vl6180x_shdn_set_pin(uint8_t lv6180x_name,uint8_t val)
{
HAL_GPIO_WritePin(s_lv6180x_module_info_t[lv6180x_name].lv6180x_shdn.GPIOx,\
s_lv6180x_module_info_t[lv6180x_name].lv6180x_shdn.GPIO_Pin,val);//
}
//配置CL6180X模块的SHDN脚
static void vl6180x_shdn_gpio_config(lv6180x_module_info lc6180x_s)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
lv6180x_shdn_gpio SHDN_GPIOx=lc6180x_s.lv6180x_shdn;
//打开对应RCC
if(SHDN_GPIOx.GPIOx == GPIOA)
__HAL_RCC_GPIOA_CLK_ENABLE();
else if(SHDN_GPIOx.GPIOx == GPIOB)
__HAL_RCC_GPIOB_CLK_ENABLE();
else if(SHDN_GPIOx.GPIOx == GPIOC)
__HAL_RCC_GPIOC_CLK_ENABLE();
else if(SHDN_GPIOx.GPIOx == GPIOD)
__HAL_RCC_GPIOD_CLK_ENABLE();
else
printf("SHDN_GPIOx.GPIOx=%#x error\r\n",SHDN_GPIOx.GPIOx);
//初始化pin
GPIO_InitStruct.Pin = SHDN_GPIOx.GPIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(SHDN_GPIOx.GPIOx,&GPIO_InitStruct);
HAL_GPIO_WritePin(SHDN_GPIOx.GPIOx,SHDN_GPIOx.GPIO_Pin,0);//拉低 不启动模块
}
//写 reg寄存器 data数据
static uint8_t VL6180X_AddrWriteByte(uint8_t addr,uint16_t reg,uint8_t data)
{
uint8_t Index_H = (uint8_t)(reg >> 8);
uint8_t Index_L = (uint8_t)(reg & 0xFF);
I2C_Start();
I2C_Send_Byte((addr<<1)|0);
if(I2C_Wait_Ack()) //等待应答
{
I2C_Stop();
return 1;
}
I2C_Send_Byte(Index_H);
I2C_Wait_Ack(); //等待ACK
I2C_Send_Byte(Index_L);
I2C_Wait_Ack(); //等待ACK
I2C_Send_Byte(data);
if(I2C_Wait_Ack()) //等待ACK
{
I2C_Stop();
return 1;
}
I2C_Stop();
return 0;
}
//VL6180X读取8位数据
static uint8_t VL6180X_AddrReadByte(uint8_t addr,uint16_t reg)
{
uint8_t res=0;
uint8_t Index_H = (uint8_t)(reg >> 8);
uint8_t Index_L = (uint8_t)(reg & 0xff);
I2C_Start();
I2C_Send_Byte((addr<<1)|0);//发送器件地址+写命令
I2C_Wait_Ack(); //等待应答
I2C_Send_Byte(Index_H); //写寄存器地址
I2C_Wait_Ack(); //等待应答
I2C_Send_Byte(Index_L); //写寄存器地址
I2C_Wait_Ack();
I2C_Start();
I2C_Send_Byte((addr<<1)|1);//发送器件地址+读命令
I2C_Wait_Ack(); //等待应答
res=I2C_Read_Byte(0);//读取数据,发送nACK
I2C_Stop(); //产生一个停止条件
return res;
}
//读取总线地址
static uint8_t VL6180X_Read_Addr(uint8_t addr)
{
uint8_t ret_addr=0;
ret_addr=VL6180X_AddrReadByte(addr,0x0212);
return ret_addr;
}
//修改总线地址
static void VL6180X_Write_Addr(uint8_t addr)
{
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0212,addr);
}
//读取id
static uint8_t VL6180X_Read_ID(uint8_t addr)
{
return VL6180X_AddrReadByte(addr,VL6180X_REG_IDENTIFICATION_MODEL_ID);
}
//向模块写入配置参数
static uint8_t VL6180X_Modele_Write_Config(void)
{
if(VL6180X_Read_ID(VL6180X_DEFAULT_I2C_ADDR) != VL6180X_DEFAULT_ID)//检查id是否正确
{
return 0 ;
}
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0207, 0x01);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0208, 0x01);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0096, 0x00);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0097, 0xfd);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00e3, 0x00);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00e4, 0x04);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00e5, 0x02);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00e6, 0x01);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00e7, 0x03);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00f5, 0x02);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00d9, 0x05);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00db, 0xce);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00dc, 0x03);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00dd, 0xf8);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x009f, 0x00);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00a3, 0x3c);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00b7, 0x00);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00bb, 0x3c);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00b2, 0x09);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00ca, 0x09);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0198, 0x01);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x01b0, 0x17);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x01ad, 0x00);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x00ff, 0x05);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0100, 0x05);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0199, 0x05);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x01a6, 0x1b);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x01ac, 0x3e);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x01a7, 0x1f);
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0030, 0x00);
// Recommended : Public registers - See data sheet for more detail
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0011, 0x10); // Enables polling for 'New Sample ready'
// when measurement completes
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x010a, 0x30); // Set the averaging sample period
// (compromise between lower noise and
// increased execution time)
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x003f, 0x46); // Sets the light and dark gain (upper
// nibble). Dark gain should not be
// changed. !上半字节要写入0x4 默认增益是1.0
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0031, 0xFF); // sets the # of range measurements after
// which auto calibration of system is
// performed
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0040, 0x63); // Set ALS integration time to 100ms
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x002e, 0x01); // perform a single temperature calibration
// of the ranging sensor
// Optional: Public registers - See data sheet for more detail
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x001b, 0x09); //测量间隔 轮询模式
// period to 100ms 每步10ms->0-10ms
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x003e, 0x31); //测量周期 ALS模式
// to 500ms
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0014, 0x24); // Configures interrupt on 'New Sample
// Ready threshold event'
//VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0212,0x2a);//
if(VL6180X_AddrReadByte(VL6180X_DEFAULT_I2C_ADDR,VL6180X_REG_SYSTEM_FRESH_OUT_OF_RESET) == 1)
{
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,VL6180X_REG_SYSTEM_FRESH_OUT_OF_RESET,0x00);
printf("0x016\r\n");
}
}
#if 0
/// @brief VL6180X_Modele_Info_register 注册模块信息
/// @param lv6180x_name 模块序列
/// @param info 信息
/// @return 1注册成功 0注册失败
uint8_t VL6180X_Modele_Info_register(lv6180x_module_name lv6180x_id,lv6180x_module_info info )
{
if(lv6180x_id >= LV6180x_MODULE_NUM_MAX)
{
printf("lv6180x_id=%d error\r\n");
return 0;
}
s_lv6180x_module_info_t[lv6180x_id]=info;//保存参数
vl6180x_shdn_gpio_config(s_lv6180x_module_info_t[lv6180x_id]);//shdn脚初始化
return 1;
}
#endif
#define VL6180X_INIT_INFO_DEBUG
/// @brief VL6180X_Init 初始化
/// @param
/// @return
uint8_t VL6180X_Init(void)
{
uint8_t i=0;
uint8_t ret=0;
I2C_Init();//iic初始化
for (i = 0; i < LV6180x_MODULE_NUM_MAX; i++)
{
if(s_lv6180x_module_info_t[i].lv6180x_iic_addr != 0x00)
{
vl6180x_shdn_gpio_config(s_lv6180x_module_info_t[i]);//shdn脚初始化
}
}
for (i = 0; i < LV6180x_MODULE_NUM_MAX; i++)
{
if(s_lv6180x_module_info_t[i].lv6180x_iic_addr != 0x00)
{
vl6180x_shdn_set_pin(i,1);//拉高引脚
ret=VL6180X_Modele_Write_Config();//写入参数
VL6180X_Write_Addr(s_lv6180x_module_info_t[i].lv6180x_iic_addr);//修改总线地址
#ifdef VL6180X_INIT_INFO_DEBUG
printf("ret =%d\r\n",ret);
printf("VL6180X_Addr[%#x]\r\n",VL6180X_Read_Addr(s_lv6180x_module_info_t[i].lv6180x_iic_addr));
printf("VL6180X_id[%#x]\r\n",VL6180X_Read_ID(s_lv6180x_module_info_t[i].lv6180x_iic_addr));
#endif
}
}
return ret;
}
static uint8_t VL6180_Poll_Range(uint8_t addr)
{
uint8_t status=0;
uint8_t range_status=0;
//检测状态
status= VL6180X_AddrReadByte(addr,VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO);
range_status = status & 0x07;
//等待新的测量就绪状态
while (range_status != 0x04)
{
status =VL6180X_AddrReadByte(addr,VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO);
range_status = status & 0x07;
}
}
static void VL6180_Clear_Interrupts(uint8_t addr)
{
VL6180X_AddrWriteByte(addr,VL6180X_REG_SYSTEM_INTERRUPT_CLEAR,0x07);
}
//距离单位毫米
uint8_t VL6180X_Read_Range(lv6180x_module_name lv6180x_name)
{
uint8_t range = 0;
uint8_t iic_addr=s_lv6180x_module_info_t[lv6180x_name].lv6180x_iic_addr;
if(iic_addr == 0x00)
{
return 0xff;
}
VL6180X_AddrWriteByte(iic_addr,VL6180X_REG_SYSRANGE_START,0x01); //单次触发模式
VL6180_Poll_Range(iic_addr);
range = VL6180X_AddrReadByte(iic_addr,VL6180X_REG_RESULT_RANGE_VAL);
//获取完数据,清楚中断位
VL6180_Clear_Interrupts(iic_addr);
return range;
}
一组iic总线驱动多个lv6180x模块的要点。
1.每个lv6180x的物理地址总线是0x29,只要断电重启,都是该地址
2.通过0x0212寄存器,可以零时修改总线地址,替换掉0x29.修改地址只是临时的,模块断电将自动变回0x29
//修改总线地址
//修改总线地址
static void VL6180X_Write_Addr(uint8_t addr)
{
VL6180X_AddrWriteByte(VL6180X_DEFAULT_I2C_ADDR,0x0212,addr);
}
3.通过SHDN引脚,可以断开模块,通过驱动SHDN引脚来修改模块地址。
for (i = 0; i < LV6180x_MODULE_NUM_MAX; i++)
{
if(s_lv6180x_module_info_t[i].lv6180x_iic_addr != 0x00)
{
vl6180x_shdn_gpio_config(s_lv6180x_module_info_t[i]);//shdn脚初始化
}
}
for (i = 0; i < LV6180x_MODULE_NUM_MAX; i++)
{
if(s_lv6180x_module_info_t[i].lv6180x_iic_addr != 0x00)
{
vl6180x_shdn_set_pin(i,1);//拉高引脚
ret=VL6180X_Modele_Write_Config();//写入参数
VL6180X_Write_Addr(s_lv6180x_module_info_t[i].lv6180x_iic_addr);//修改总线地址
#ifdef VL6180X_INIT_INFO_DEBUG
printf("ret =%d\r\n",ret);
printf("VL6180X_Addr[%#x]\r\n",VL6180X_Read_Addr(s_lv6180x_module_info_t[i].lv6180x_iic_addr));
printf("VL6180X_id[%#x]\r\n",VL6180X_Read_ID(s_lv6180x_module_info_t[i].lv6180x_iic_addr));
#endif
}
//已经封装好,移植只需要简单修改几个参数就能用
1.替换成自己的iic驱动名字
/*iic驱动移植****************************/
#define I2C_Init iic_init
#define I2C_Start iic_start
#define I2C_Stop iic_stop
#define I2C_Wait_Ack iic_wait_ack
#define I2C_Send_Byte iic_send_byte
#define I2C_Read_Byte iic_read_byte
/*************************************/
2.LV6180x_MODULE_1_ADDR 宏定义需要设置的地址,
lv6180x_module_name 模块的名字
//模块地址
#define LV6180x_MODULE_1_ADDR 0x2a
#define LV6180x_MODULE_2_ADDR 0x2b
#define LV6180x_MODULE_3_ADDR 0x2c
#define LV6180x_MODULE_4_ADDR 0x2d
typedef enum
{
LV6180x_MODULE_1,
LV6180x_MODULE_2,
LV6180x_MODULE_3,
LV6180x_MODULE_4,
LV6180x_MODULE_MAX //模块数量不要超过4个
}lv6180x_module_name;
3.注册模块
//注册模块
static lv6180x_module_info s_lv6180x_module_info_t[LV6180x_MODULE_MAX]=
{
{LV6180x_MODULE_1_ADDR,GPIOB,GPIO_PIN_5},
{LV6180x_MODULE_2_ADDR,GPIOB,GPIO_PIN_3},
{0x00,NULL,0},
{0x00,NULL,0},
};//模块信息参数
//完成移植
然后在main里面调用就好
1初始化
if(VL6180X_Init() == 0)
{
delay_ms(500);
printf("error\r\n");
}
2.获取距离
u8 distance_1 =0;
u8 distance_2 =0;
while(1)
{
//VL53L1_single_test(&VL53L0x_dev,&VL53L0x_data);
distance_1=VL6180X_Read_Range(LV6180x_MODULE_1);
distance_2=VL6180X_Read_Range(LV6180x_MODULE_2);
printf("LV6180x_MODULE_1 ->distance_1=%d mm\r\n",distance_1);
printf("LV6180x_MODULE_2 ->distance_2=%d mm\r\n",distance_2);
vTaskDelay(1000);
}
完成
//第二个模块误差有点大,应该和线有关,换了线误差好了一点。连接的线要好一点,尽量短。