1.简介
在研究了各位大神的代码后,结合购买模块时商家提供的arduino的VL53L0X驱动,我修改ardiuno的驱动写出了兼容C51的VL53L0X驱动。我的测试的单片机是STC8H3K64S4,IIC通信使用的是STC硬件的IIC。大家只需要把我的IIC驱动和显示代码修改成自己的,最后添加一个定时1ms的定时器作为VL53L0X的时基,就可以直接拿来用了。
这是本人第一次发帖,做的工作也比较简单,如果有什么做的不好的还请谅解。
参考的网站:
VL53L0X激光测距模块的单片机驱动程序 - 51单片机
使用上面网站的代码写出来的程序,这个代码只有最基本的测距功能,测距误差大概在±5%。对我刚刚接触VL53L0X时启发很大。
在使用商家提供的arduino的VL53L0X驱动后,由于设置了VL53L0X的相关寄存器,精度可以达到±1%。当然超过模块的1.2m的测距范围精度还是会差很多。
2.上代码
主函数 main.c
人机交互的相关代码替换成自己的就行了
void main()
{
unsigned int temp;
unsigned char high;
//初始化
gpio();
Timer2_Init(); //初始化定时器,用于传感器的时基
UartInit(); //初始化串口,用与显示传感器结果
P16 = 0; //我的开发板的LED
EA = 1;
IIC_Init(); //初始化IIC,用的是STC的硬件IIC
VL53L0X_Init(0); //初始化VL53L0X的相关功能寄存区
setTimeout(500); //设置超时时间 500ms
//模式选择
//#define LONG_RANGE
//#define HIGH_ACCURACY
#define HIGHT_SPEED
//长距离测距的相关API设置
#if defined LONG_RANGE
// lower the return signal rate limit (default is 0.25 MCPS)
VL53L0X_setSignalRateLimit(0.1);
// increase laser pulse periods (defaults are 14 and 10 PCLKs)
VL53L0X_setVcselPulsePeriod(0, 18);
VL53L0X_setVcselPulsePeriod(1, 14);
#endif
//高速测距的相关API设置
#if defined HIGH_SPEED
// reduce timing budget to 20 ms (default is about 33 ms)
VL53L0X_setMeasurementTimingBudget(20000);
//高精度测距的相关API设置
#elif defined HIGH_ACCURACY
// increase timing budget to 200 ms
VL53L0X_setMeasurementTimingBudget(200000);
#endif
while(1)
{
//读取一次VL53L0X的数据
temp = VL53L0X_readRangeSingleMillimeters();
//可以按照自己的显示模块修改
//向串口发送距离结果
//转换成ASCLL码
Uart_Send("Distance is " ,12);
high = 0x30 + temp / 10000;
Uart_Send(&high ,1);
high = 0x30 + temp % 10000 / 1000;
Uart_Send(&high ,1);
high = 0x30 + temp % 1000 / 100;
Uart_Send(&high ,1);
high = 0x30 + temp % 100 / 10;
Uart_Send(&high ,1);
high = 0x30 + temp % 10;
Uart_Send(&high ,1);
Uart_Send("mm" ,2);
//捕捉VL53L0X的超时
if(VL53L0X_timeoutOccurred())
Uart_Send("Timeout", 7);
Uart_Send("\r\n", 2);
}
}
void Uart1() interrupt 4
{
if(RI)
RI = 0;
}
VL53L0X的驱动 VL53L0X.c
代码太多了只显示一部分,详情看附件,大家用的时候记得添加时基就行了。
// Most of the functionality of this library is based on the VL53L0X API
// provided by ST (STSW-IMG005), and some of the explanatory comments are quoted
// or paraphrased from the API source code, API user manual (UM2039), and the
// VL53L0X datasheet.
#include "inc/VL53L0X.h"
#include "inc/VL53L0X_IIC.h"
#include "NodeHandler.h"
#include <string.h>
unsigned char stop_variable;
unsigned long measurement_timing_budget_us;
unsigned int io_timeout = 0, timeout_start_ms, t2;
bit did_timeout;
//===================================
//你自己的定时器时基定时1ms
void Time2() interrupt 12
{
t2++;
}
//==================================================
// Defines /////////////////////////////////////////////////////////////////////
// The Arduino two-wire interface uses a 7-bit number for the address,
// and sets the last bit correctly based on reads and writes
#define ADDRESS_DEFAULT 0x52
// Record the current time to check an upcoming timeout against
#define startTimeout() (timeout_start_ms = t2)
// Check if timeout is enabled (set to nonzero value) and has expired
#define checkTimeoutExpired() (io_timeout > 0 && ((unsigned int)t2 - timeout_start_ms) > io_timeout)
// Decode VCSEL (vertical cavity surface emitting laser) pulse period in PCLKs
// from register value
// based on VL53L0X_decode_vcsel_period()
#define decodeVcselPeriod(reg_val) (((reg_val) + 1) << 1)
// Encode VCSEL pulse period register value from period in PCLKs
// based on VL53L0X_encode_vcsel_period()
#define encodeVcselPeriod(period_pclks) (((period_pclks) >> 1) - 1)
IIC驱动
有人喜欢模拟IIC,有人喜欢硬件IIC,他们各有各的优点,大家按照自己的喜好替换调我的IIC驱动就行了
#define VL53L0X_address 0x52
//IIC写8位数据
void VL53L0X_Write(unsigned char address, unsigned char value)
{
P_SW2 = 0xB0;
Start();
SendData(VL53L0X_address);
RecvACK();
SendData(address);
RecvACK();
SendData(value);
RecvACK();
Stop();
Delay();
P_SW2 = 0x00;
}
//IIC写16位数据
void VL53L0X_Write16Bit(unsigned char address, unsigned int value)
{
P_SW2 = 0xB0;
VL53L0X_Write(address++, (value >> 8) & 0xFF);
VL53L0X_Write(address++, value & 0xFF);
P_SW2 = 0x00;
}
//IIC写32位数据
//void VL53L0X_Write32Bit(unsigned char address, unsigned long value)
//{
// Start();
// SendData(VL53L0X_address);
// RecvACK();
// SendData(address);
// RecvACK();
// SendData((value >> 24) & 0xFF);
// RecvACK();
// SendData((value >> 16) & 0xFF);
// RecvACK();
// SendData((value >> 8) & 0xFF);
// RecvACK();
// SendData(value & 0xFF);
// RecvACK();
// Stop();
// Delay();
//}
//写多位数据
void VL53L0X_WriteMulti(unsigned char address, unsigned char const * src, unsigned char count)
{
P_SW2 = 0xB0;
while(count--)
{
VL53L0X_Write(address++, *(src++));
}
P_SW2 = 0x00;
}
//IIC读8位数据
unsigned char VL53L0X_Read(unsigned char address)
{
unsigned char receive;
P_SW2 = 0xB0;
Start();
SendData(VL53L0X_address);
RecvACK();
SendData(address);
RecvACK();
Start();
SendData(VL53L0X_address + 1);
RecvACK();
receive = RecvData();
SendNAK();
Stop();
Delay();
P_SW2 = 0x00;
return receive;
}
//IIC读16位数据
unsigned int VL53L0X_Read16Bit(unsigned char address)
{
unsigned int receive;
P_SW2 = 0xB0;
receive = VL53L0X_Read(address++) << 8;
receive |= VL53L0X_Read(address);
P_SW2 = 0x00;
return receive;
}
//IIC读多位数据
void VL53L0X_ReadMulti(unsigned char address, unsigned char * dst, unsigned char count)
{
while(count--)
{
*(dst++) = VL53L0X_Read(address++);
}
P_SW2 = 0x00;
}
3.其他
说一个我的IIC编程遇到的问题,我在IIC连续读SDA的数据的时候会存在有时读到的数据不稳定的情况
连续读的时候,如下读两个字节
//IIC读16位数据
unsigned int VL53L0X_Read16Bit(unsigned char address)
{
unsigned int receive;
IICStart();
IICSendData(VL53L0X_address);
IICWaitACK();
IICSendData(address);
IICWaitACK();
IICStop();
IICStart();
IICSendData(VL53L0X_address + 1);
IICWaitACK();
//VL53L0X的内部寄存器索引会在读完一个寄存器后自加1
receive = IICRecvData() << 8;
IICSendACK(1);
//索引加1后读下一个寄存器的数据
receive |= IICRecvData();
IICSendACK(0);
IICStop();
return receive;
}
VL53L0X的内部寄存器索引会在读完一个寄存器后自加1,索引加1后读下一个寄存器的数据。
那么如果这个自加1的索引自加的速度跟不上你IIC读取的速度呢。
这样IIC读取的数据就会不可靠。
连续读两个字节,我修改成连续两次读一个字节后,数据的读取就稳定许多了
//IIC读16位数据
unsigned int VL53L0X_Read16Bit(unsigned char address)
{
unsigned int receive;
P_SW2 = 0xB0;
receive = VL53L0X_Read(address++) << 8; //连续两次读取一个字节
receive |= VL53L0X_Read(address);
P_SW2 = 0x00;
return receive;
}
或者大家有更好的见解也可以告诉我,毕竟我也是刚刚开始研究IIC,对IIC的认识也可能有错误(说不定我的程序就是建立在BUG上的 XD)
4.结果
5.工程源码及附件
链接:https://pan.baidu.com/s/1w-9VU3cBssHT22YotEhmUg
提取码:hkvx
我在51黑电子论坛也写了一篇文章,但是因为编辑问题导致原帖子显示有问题,我又来csdn写了一篇