STM32驱动VL6180X测距

tech2024-07-27  52

文章目录

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 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

没用到之前别去看寄存器,浪费时间。。

I2C读写

VL6180X的寄存器是16位的,也就是0xXXXX,切记

//写 reg寄存器 data数据 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(); //等待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位数据 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);//读取数据,发送nACK 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); // Recommended : Public registers - See data sheet for more detail VL6180X_WriteByte(0x0011, 0x10); // Enables polling for 'New Sample ready' // when measurement completes VL6180X_WriteByte(0x010a, 0x30); // Set the averaging sample period // (compromise between lower noise and // increased execution time) VL6180X_WriteByte(0x003f, 0x46); // Sets the light and dark gain (upper // nibble). Dark gain should not be // changed. !上半字节要写入0x4 默认增益是1.0 VL6180X_WriteByte(0x0031, 0xFF); // sets the # of range measurements after // which auto calibration of system is // performed VL6180X_WriteByte(0x0040, 0x63); // Set ALS integration time to 100ms VL6180X_WriteByte(0x002e, 0x01); // perform a single temperature calibration // of the ranging sensor // Optional: Public registers - See data sheet for more detail VL6180X_WriteByte(0x001b, 0x09); //测量间隔 轮询模式 // period to 100ms 每步10ms->0-10ms VL6180X_WriteByte(0x003e, 0x31); //测量周期 ALS模式 // to 500ms VL6180X_WriteByte(0x0014, 0x24); // Configures interrupt on 'New Sample // Ready threshold event' 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); //单次触发模式 //等待新样本就绪阈值事件(New Sample Ready threshold event) 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); //0111b 清除了三种中断标志 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; //[5:3]清0 reg |= (0x4<<3); //开启转换New sample ready 开启转换 VL6180X_WriteByte(VL6180X_REG_SYSALS_INTEGRATION_PERIOD_HI,0); VL6180X_WriteByte(VL6180X_REG_SYSALS_INTEGRATION_PERIOD_LO,100); //101ms 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); //连续模式 // New Sample Ready threshold event 新样本就绪 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); //0111b 清除了三种中断标志 //矫正增益算法 lux *= 0.32f; // calibrated count/lux 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; // integration time in ms return lux; }

需要读取两个字节

//VL6180X读取16位数据 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);//读取数据,发送ACK res <<= 8; res |= I2C_Read_Byte(0);//读取数据,发送nACK I2C_Stop(); //产生一个停止条件 return res; }

光强的我没试过,这些代码都是一直Arduino的驱动到STM32,我看了寄存器大概知道什么意思。这个代码要是能用可以说一句,让大家放心。

测试代码

int main() { /*Parameter Configuration*/ u8 ex_Range = 0; /*Init*/ delay_init(168); USART_Config(); MY_I2C_GPIO_Config(); //I2C初始化 /*Configuration Operation*/ printf("\r\nVL6180X测距实验\r\n"); if(VL6180X_Init() == 0) printf("\r\nVL6180X初始化成功!\r\n"); delay_ms(2000); /*LOOP*/ while(1) { ex_Range = VL6180X_Read_Range(); printf("\r\n Current Range:%d mm",ex_Range); delay_ms(100); } }
最新回复(0)