完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
最近学习stm32单片机,用VL53L0X这个传感器进行开发,花了不少时间和精力,写这个博客一个是为了记录自己的学习过程另外一个是感谢网上各位网友的帮助。我一直秉持分享的精神同时取之大众馈之大众。谨用这篇博客感谢各位的帮助。 我以前没学过stm32这次是第一次着手做stm32。关于里面的很多东西我是用Linux的思想来理解的,所以可能会有很多解释不正确,还望大家指出共同进步 VL53L0X最远测距的距离是2m,精度可以是2mm。原理很简单,发射激光到反射物,激光折射回来给接收元件,然后VL53L0X内部计算出时间和距离最后通过stm32单片机打印出来。VL53L0X的通信是基于I2C的,关于I2C协议大家可以去搜索其他的,以后有时间我会写一篇文章,这里就不赘述了。 首先我们知道VL53L0X的设备地址是0x52(初始状态的,这个地址是可以修改的)。然后我们看一下VL53L0X需要接到stm32的引脚。分别是GND,VDD,SDA,SCL,XSHUT(这里不使用GPIO1)。下面是VL53L0X与stm32引脚对应关系: SDA-->PA2,SCL-->PA3,XSHUT-->PA5(如果需要的话可以做修改,要同时修改vl53l0x_i2c.c,vl53l0x_i2c.h和vl53l0x.c里面对应的引脚) 原理性的东西我暂时不说太多以后有时间会补充,这里注意一下,0x52是写命令的,0x53是读命令的,这个跟I2C的读写命令是有关的。I2C传输中,最后一个bit是0代表四write,最后一个bit是1代表是read。在这里再啰嗦一句,有部分网友的设备地址可能是0x29,为什么呢?如果仔细看他们的I2C读写操作函数就会发现,他们的I2C读写操作是对地址进行了左移一位的操作,0x29左移一位就是0x52大家可以算一下。那读操作呢,在左移一位之后或上1就会变成0x53,那就是读地址了。我用的是0x52,因为I2C操作函数没有左移,但是读地址还是要或上1的,这个大家看代码要注意,下面代码分析会讲。接下来直接看代码了。我只分析关键代码,最后的工程会分享给大家! if(vl53l0x_init(&vl53l0x_dev)) //vl53l0x初始化 { printf("VL53L0X_Init Error!!!rn"); delay_ms(200); } else { printf("VL53L0X_Init OKrn"); VL53L0X_RdByte(&vl53l0x_dev,0xc0,&data); printf("register1:0x%xrn",data); printf("vl53l0x_dev.I2cDevAddr = 0x%xrn",vl53l0x_dev.I2cDevAddr); } if(vl53l0x_set_mode(&vl53l0x_dev,mode)) //配置测量模式 { printf("Mode Set Error!!!rn"); } else printf("Mode Set OK!!!rn"); while(1) { //执行一次测量 Status = vl53l0x_start_single_test(&vl53l0x_dev,&vl53l0x_data,buf); if(Status==VL53L0X_ERROR_NONE) printf("d: %4immrn",Distance_data);//打印测量距离 else printf("Measurement is Error!!!rn"); } 上面是main函数的部分代码。首先看vl53l0x_init(&vl53l0x_dev); VL53L0X_Error vl53l0x_init(VL53L0X_Dev_t *dev) { GPIO_InitTypeDef GPIO_InitStructure; VL53L0X_Error Status = VL53L0X_ERROR_NONE; VL53L0X_Dev_t *pMyDevice = dev; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // 配置XSHUT引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); pMyDevice->I2cDevAddr = VL53L0X_Addr;//I2C地址,默认0x52,定义成宏了 pMyDevice->comms_type = 1; //I2C通信,0代表spi pMyDevice->comms_speed_khz = 400; //I2C速率,这个手册上有 VL53L0X_i2c_init();//这个是I2C的初始化,配置SDA和SCL引脚的,自己去看吧 //使能XSHUT引脚 VL53L0X_Xshut=0; delay_ms(30); VL53L0X_Xshut=1; delay_ms(30); vl53l0x_Addr_set(pMyDevice,0x52);//这里是设置VL53L0X的地址的,但是好像这里没成功。可以自行研究 if(Status!=VL53L0X_ERROR_NONE) goto error; Status = VL53L0X_DataInit(pMyDevice);//这个是VL53L0X自己的函数,初始化设备的 if(Status!=VL53L0X_ERROR_NONE) goto error; delay_ms(2); Status = VL53L0X_GetDeviceInfo(pMyDevice,&vl53l0x_dev_info);//这个是获取设备信息,也是他自己的函数 if(Status!=VL53L0X_ERROR_NONE) goto error; error: if(Status!=VL53L0X_ERROR_NONE) { print_pal_error(Status);//打印错误信息 return Status; } return Status; } 这个函数就是初始化VL53L0X这个传感器的。首先是引脚,然后设置通信模式和速率,初始化设备和获取设备信息。这里面的修改设备地址其实是没有成功的,可以自己debug进去看,至于为什么没有成功是他里面的一个判断条件有问题,有兴趣可以看看。然后我们看一下vl53l0x_set_mode(&vl53l0x_dev,mode)这个函数 VL53L0X_Error vl53l0x_set_mode(VL53L0X_Dev_t *dev,u8 mode) { VL53L0X_Error status = VL53L0X_ERROR_NONE; uint8_t VhvSettings; uint8_t PhaseCal; uint32_t refSpadCount; uint8_t isApertureSpads; //vl53l0x_reset(dev); status = VL53L0X_StaticInit(dev); //设备初始化 if(status!=VL53L0X_ERROR_NONE) goto error; delay_ms(2); status = VL53L0X_PerformRefCalibration(dev, &VhvSettings, &PhaseCal); if(status!=VL53L0X_ERROR_NONE) goto error; delay_ms(2); status = VL53L0X_PerformRefSpadManagement(dev, &refSpadCount, &isApertureSpads); if(status!=VL53L0X_ERROR_NONE) goto error; delay_ms(2); } 这个函数有很多内容的,我暂时就讲两个,后面的那些其实都是一下设定,虽然我暂时也没很弄明白,但是我对比了很多代码基本都是这个流程,所以就不具体研究。这里的mode是测量模式分四种,默认,高精度,长距离,高速率。我只测量长距离和默认两种。默认的最远距离是1.25m左右,精度是3mm-1cm,长距离最远可以测距2.1m左右,精度在4cm左右。 上面的两个函数分别介绍一下。这两函数都是官方提供的API VL53L0X_PerformRefCalibration这个函数呢是Ref校准,有什么作用呢?按照官方的解释 是参考校准,但是参考校准是什么他没说,我也不知道。还说会清除中断。说得我也不懂,但是这个很重要的,不执行参考没办法测量这个函数在测量之前执行的。 VL53L0X_PerformRefSpadManagement,这个函数也是要在测量之前执行的,否则会出错的。 我个人的理解是,这两个函数其实就是启动这个传感器来发射脉冲的,但是我不知道这样理解是否正确 然后基本上就结束了。说说我耗时的地方 u8 VL_IIC_Read_Byte(unsigned char ack) { unsigned char i,receive=0; VL_SDA_IN(); for(i=0;i<8;i++ ) { VL_IIC_SCL=0; delay_us(4); VL_IIC_SCL=1; receive<<=1; if(VL_READ_SDA)receive++; delay_us(4); //1 } if (!ack) VL_IIC_NAck(); else VL_IIC_Ack(); return receive; } 就是上面这个函数,这个函数是不正确的。这个是I2C的read函数,后来参考一位网友的代码修改成如下: u8 VL_IIC_Read_Byte(void) { unsigned char i,receive=0; VL_SDA_IN();// VL_IIC_SDA = 1; delay_us(4); for(i=0;i<8;i++ ) { receive<<=1; VL_IIC_SCL=0; delay_us(4); VL_IIC_SCL=1; delay_us(4); if(VL_READ_SDA) receive |= 0x01; delay_us(4); //1 } VL_IIC_SCL = 0; return receive; } 至于这两个差别我在这里就不分析了,大家自行理解。我就是卡在这里花了两个星期才搞定这个传感器。这里面说明,I2C最重要的还是协议实现是否正确,以后写I2C的项目,一定要写好read和write个人推荐第二个read的写法。因为很多单片机都是这样写的。然后第一种写法是一个网友分享的代码里面的,该网友说他是可以执行的,但是在我的环境里没办法执行。所以拿到别人的源码不一定就是可以用的,要根据自己的情况修改,当然不是说别人的代码有错,毕竟别人验证成功了,只能说情况不一样,结果就可能不一样。 最后要做个说明总结:我使用的是stm32f103vet6的CPU,不知道你们修改CPU型号和引脚之后是否能正常执行。如果不行我们再交流。然后我会给出这两份代码的下载链接,都是原作者的(我很注重别人的版权)。另外我会给出我自己结合两位作者的代码。因为只能上传到CSDN的下载,肯定需要C币的,我会把他设置到最低,如果你们有积分就去下,因为有时候我也需要积分去下东西,毕竟不是每个人都很愿意无偿分享。但是如果你像我一样没有积分,在下面给我留言,看到邮件之后我会在24小时之内给你发送我自己的代码。 最后,这篇文章应该还有补充的,里面还有还有很多知识的,而且最近我开始做VL53L1X这个传感器可以达到4m。以后再更新。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1763 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1617 浏览 1 评论
1059 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
723 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1670 浏览 2 评论
1932浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
725浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
564浏览 3评论
591浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
549浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-21 01:59 , Processed in 0.994941 second(s), Total 47, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号