文章目录
VL6180X寄存器手册I2C读写读取ID(无需初始化)初始化代码读取距离读取环境光强度测试代码
VL6180测距原理就是TOF,超声波也可以测距,但是这个测距是用红外光。
VL6180X集成了测距、环境光传感器、接近传感器
测距(RANGE):0~100mm精度高,可以到200mm,但是我试过200+以上直接255了;
环境光 ambient light sensor(ALS):测光强,不同增益等级,0-100 Lux,我的模块没有这个功能,但有代码(可能会出错)。
以下是软件I2C代码,硬件I2C没试过,可能可以用,不过时序都一样
VL6180X寄存器手册
#define VL6180X_DEFAULT_ID 0xB4
#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_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_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
没用到之前别去看寄存器,浪费时间。。
I2C读写
VL6180X的寄存器是16位的,也就是0xXXXX,切记
u8
VL6180X_WriteByte(u16 reg
,u8 data
)
{
uint8_t Index_H
= (uint8_t
)(reg
>> 8);
uint8_t Index_L
= (uint8_t
)(reg
& 0xFF);
I2C_Start();
I2C_Send_Byte((VL6180X_DEFAULT_I2C_ADDR
<<1)|0);
if(I2C_Wait_Ack())
{
I2C_Stop();
return 1;
}
I2C_Send_Byte(Index_H
);
I2C_Wait_Ack();
I2C_Send_Byte(Index_L
);
I2C_Wait_Ack();
I2C_Send_Byte(data
);
if(I2C_Wait_Ack())
{
I2C_Stop();
return 1;
}
I2C_Stop();
return 0;
}
u8
VL6180X_ReadByte(u16 reg
)
{
u8 res
;
uint8_t Index_H
= (uint8_t
)(reg
>> 8);
uint8_t Index_L
= (uint8_t
)(reg
& 0xff);
I2C_Start();
I2C_Send_Byte((VL6180X_DEFAULT_I2C_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((VL6180X_DEFAULT_I2C_ADDR
<<1)|1);
I2C_Wait_Ack();
res
=I2C_Read_Byte(0);
I2C_Stop();
return res
;
}
这里要取寄存器的高位和地位,因为这是十六位地址,I2C需要写两次
读取ID(无需初始化)
uint8_t
VL6180X_Read_ID(void)
{
return VL6180X_ReadByte(VL6180X_REG_IDENTIFICATION_MODEL_ID
);
}
正确地址是0xB4,拿来验证下I2C的读写是否有问题,记住寄存器地址是16位的!没用16位写入地址会一直变。。(我试过)
初始化代码
uint8_t
VL6180X_Init(void)
{
if(VL6180X_Read_ID() == VL6180X_DEFAULT_ID
)
{
VL6180X_WriteByte(0x0207, 0x01);
VL6180X_WriteByte(0x0208, 0x01);
VL6180X_WriteByte(0x0096, 0x00);
VL6180X_WriteByte(0x0097, 0xfd);
VL6180X_WriteByte(0x00e3, 0x00);
VL6180X_WriteByte(0x00e4, 0x04);
VL6180X_WriteByte(0x00e5, 0x02);
VL6180X_WriteByte(0x00e6, 0x01);
VL6180X_WriteByte(0x00e7, 0x03);
VL6180X_WriteByte(0x00f5, 0x02);
VL6180X_WriteByte(0x00d9, 0x05);
VL6180X_WriteByte(0x00db, 0xce);
VL6180X_WriteByte(0x00dc, 0x03);
VL6180X_WriteByte(0x00dd, 0xf8);
VL6180X_WriteByte(0x009f, 0x00);
VL6180X_WriteByte(0x00a3, 0x3c);
VL6180X_WriteByte(0x00b7, 0x00);
VL6180X_WriteByte(0x00bb, 0x3c);
VL6180X_WriteByte(0x00b2, 0x09);
VL6180X_WriteByte(0x00ca, 0x09);
VL6180X_WriteByte(0x0198, 0x01);
VL6180X_WriteByte(0x01b0, 0x17);
VL6180X_WriteByte(0x01ad, 0x00);
VL6180X_WriteByte(0x00ff, 0x05);
VL6180X_WriteByte(0x0100, 0x05);
VL6180X_WriteByte(0x0199, 0x05);
VL6180X_WriteByte(0x01a6, 0x1b);
VL6180X_WriteByte(0x01ac, 0x3e);
VL6180X_WriteByte(0x01a7, 0x1f);
VL6180X_WriteByte(0x0030, 0x00);
VL6180X_WriteByte(0x0011, 0x10);
VL6180X_WriteByte(0x010a, 0x30);
VL6180X_WriteByte(0x003f, 0x46);
VL6180X_WriteByte(0x0031, 0xFF);
VL6180X_WriteByte(0x0040, 0x63);
VL6180X_WriteByte(0x002e, 0x01);
VL6180X_WriteByte(0x001b, 0x09);
VL6180X_WriteByte(0x003e, 0x31);
VL6180X_WriteByte(0x0014, 0x24);
return 0;
}
else return 1;
}
初始化就是设置一些寄存器,这是官方提供的,需要设置自己的模式自己改寄存器就行了。
读取距离
uint8_t
VL6180X_Read_Range(void)
{
uint8_t range
= 0;
while(!(VL6180X_ReadByte(VL6180X_REG_RESULT_RANGE_STATUS
) & 0x01));
VL6180X_WriteByte(VL6180X_REG_SYSRANGE_START
,0x01);
while(!(VL6180X_ReadByte(VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO
) & 0x04));
range
= VL6180X_ReadByte(VL6180X_REG_RESULT_RANGE_VAL
);
VL6180X_WriteByte(VL6180X_REG_SYSTEM_INTERRUPT_CLEAR
,0x07);
return range
;
}
有注释,我写的很清楚,大致是读取一些寄存器的状态,设置寄存器启动转化。最后做好处理用于下次测量。 范围是0~200mm,超了的话会直接255。
读取环境光强度
float VL6180X_Read_Lux(uint8_t Gain
)
{
float lux
;
uint8_t reg
;
reg
= VL6180X_ReadByte(VL6180X_REG_SYSTEM_INTERRUPT_CONFIG
);
reg
&= ~0x38;
reg
|= (0x4<<3);
VL6180X_WriteByte(VL6180X_REG_SYSALS_INTEGRATION_PERIOD_HI
,0);
VL6180X_WriteByte(VL6180X_REG_SYSALS_INTEGRATION_PERIOD_LO
,100);
if (Gain
> VL6180X_ALS_GAIN_40
)
{
Gain
= VL6180X_ALS_GAIN_40
;
}
VL6180X_WriteByte(VL6180X_REG_SYSALS_ANALOGUE_GAIN
, 0x40 | Gain
);
VL6180X_WriteByte(VL6180X_REG_SYSALS_START
, 0x1);
while (4 != ((VL6180X_ReadByte(VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO
) >> 3) & 0x7));
lux
= VL6180X_Read_HalfWold(VL6180X_REG_RESULT_ALS_VAL
);
VL6180X_WriteByte(VL6180X_REG_SYSTEM_INTERRUPT_CLEAR
,0x07);
lux
*= 0.32f;
switch(Gain
) {
case VL6180X_ALS_GAIN_1
:
break;
case VL6180X_ALS_GAIN_1_25
:
lux
/= 1.25f;
break;
case VL6180X_ALS_GAIN_1_67
:
lux
/= 1.76f;
break;
case VL6180X_ALS_GAIN_2_5
:
lux
/= 2.5f;
break;
case VL6180X_ALS_GAIN_5
:
lux
/= 5;
break;
case VL6180X_ALS_GAIN_10
:
lux
/= 10;
break;
case VL6180X_ALS_GAIN_20
:
lux
/= 20;
break;
case VL6180X_ALS_GAIN_40
:
lux
/= 20;
break;
}
lux
*= 100;
lux
/= 100;
return lux
;
}
需要读取两个字节
u8
VL6180X_Read_HalfWold(u16 reg
)
{
u16 res
;
uint8_t Index_H
= (uint8_t
)(reg
>> 8);
uint8_t Index_L
= (uint8_t
)(reg
& 0xff);
I2C_Start();
I2C_Send_Byte((VL6180X_DEFAULT_I2C_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((VL6180X_DEFAULT_I2C_ADDR
<<1)|1);
I2C_Wait_Ack();
res
= I2C_Read_Byte(1);
res
<<= 8;
res
|= I2C_Read_Byte(0);
I2C_Stop();
return res
;
}
光强的我没试过,这些代码都是一直Arduino的驱动到STM32,我看了寄存器大概知道什么意思。这个代码要是能用可以说一句,让大家放心。
测试代码
int main()
{
u8 ex_Range
= 0;
delay_init(168);
USART_Config();
MY_I2C_GPIO_Config();
printf("\r\nVL6180X测距实验\r\n");
if(VL6180X_Init() == 0) printf("\r\nVL6180X初始化成功!\r\n");
delay_ms(2000);
while(1)
{
ex_Range
= VL6180X_Read_Range();
printf("\r\n Current Range:%d mm",ex_Range
);
delay_ms(100);
}
}