STM32F4+VL530L0x激光测距cubemx实现

  • Post author:
  • Post category:其他




前言


提示:本程序测试主控使用STM32F427VGT6系列单片机,使用cubemx作为开发工具,串口波特率为115200,使用VL530L0模块,使用IIC通信,可移植到相关STM32F4型号单片机上




一、STM32cubemx配置



a.配置RCC


RCC设置,选择HSE(外部高速时钟)为Crystal/Ceramic Resonator(晶振/陶瓷谐振器)

在这里插入图片描述



b.配置SYS



##c, 配置USART


这里使用串口1,波特率设为115200,开启中断,用于接收VL530的数据

在这里插入图片描述

在这里插入图片描述



c.配置VL530使能口


这里使用PB8,PB9作为SDA,SCL配置口,这里设为输出模式,电平拉高

在这里插入图片描述



d.时钟线配置


配置系统目录为180M最高速度,只用调节SYSCLK其它即可自动配置,时钟配置不同型号单片机可能不同,这里我设置为180MHZ

在这里插入图片描述



二、STM32F4 keil配置



1.引入库



a.引入IIC口配置


myiic.c配置

#include "myiic.h"
#include "delay.h"
//初始化IIC
void IIC_Init(void)
{			
  GPIO_InitTypeDef  GPIO_InitStructure;
	IIC_SCL=1;
	IIC_SDA=1;
}
//产生IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();     //sda线输出
	IIC_SDA=1;	  	  
	IIC_SCL=1;
	delay_us(4);
 	IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	IIC_SCL=0;
	IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	IIC_SCL=1; 
	IIC_SDA=1;//发送I2C总线结束信号
	delay_us(4);							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	IIC_SDA=1;delay_us(1);	   
	IIC_SCL=1;delay_us(1);	 
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL=0;//时钟输出0 	   
	return 0;  
} 
//产生ACK应答
void IIC_Ack(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}
//不产生ACK应答		    
void IIC_NAck(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
	SDA_OUT(); 	    
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1; 	  
		delay_us(2);   //对TEA5767这三个延时都是必须的
		IIC_SCL=1;
		delay_us(2); 
		IIC_SCL=0;	
		delay_us(2);
    }	 
} 	    
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        IIC_SCL=0; 
        delay_us(2);
		IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
		delay_us(1); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}


myiic.h配置

#ifndef __MYIIC_H
#define __MYIIC_H
#include "sys.h"
#include "stdio.h"
#include "main.h"
#include "string.h"
#include "sys.h"		   
//IO方向设置
#define SDA_IN()  {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;}	//PB9输入模式
#define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //PB9输出模式
//IO操作函数	 
#define IIC_SCL    PBout(8) //SCL
#define IIC_SDA    PBout(9) //SDA	 
#define READ_SDA   PBin(9)  //输入SDA 

//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口				 
void IIC_Start(void);				//发送IIC开始信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); 				//IIC等待ACK信号
void IIC_Ack(void);					//IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号

void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);	  
#endif



b.引入VL530底层配置


VL530L0.c配置:

#include "VL53L0.h"
#include "myiic.h"
uint16_t bswap(u8 b[])
{
	uint16_t val = ((b[0]<< 8) & b[1]);
	return val;
}

uint16_t VL53L0X_decode_vcsel_period(short vcsel_period_reg)
{
	uint16_t vcsel_period_pclks = (vcsel_period_reg + 1) <<1;
	return vcsel_period_pclks;
}

uint16_t makeuint16(int lsb, int msb)
{
    return ((msb & 0xFF) << 8) | (lsb & 0xFF);
}

//IIC连续写
//addr:器件地址 
//reg:寄存器地址
//len:写入长度
//buf:数据区
//返回值:0,正常
//    其他,错误代码
u8 VL53L0X_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
	u8 i; 
    IIC_Start(); 
	IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令	
	if(IIC_Wait_Ack())	//等待应答
	{
		IIC_Stop();		 
		return 1;		
	}
    IIC_Send_Byte(reg);	//写寄存器地址
    IIC_Wait_Ack();		//等待应答
	for(i=0;i<len;i++)
	{
		IIC_Send_Byte(buf[i]);	//发送数据
		if(IIC_Wait_Ack())		//等待ACK
		{
			IIC_Stop();	 
			return 1;		 
		}		
	}    
    IIC_Stop();	 
	return 0;	
} 
//IIC连续读
//addr:器件地址
//reg:要读取的寄存器地址
//len:要读取的长度
//buf:读取到的数据存储区
//返回值:0,正常
//    其他,错误代码
u8 VL53L0X_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{ 
 	IIC_Start(); 
	IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令	
	if(IIC_Wait_Ack())	//等待应答
	{
		IIC_Stop();		 
		return 1;		
	}
    IIC_Send_Byte(reg);	//写寄存器地址
    IIC_Wait_Ack();		//等待应答
    IIC_Start();
	IIC_Send_Byte((addr<<1)|1);//发送器件地址+读命令	
    IIC_Wait_Ack();		//等待应答 
	while(len)
	{
		if(len==1)*buf=IIC_Read_Byte(0);//读数据,发送nACK 
		else *buf=IIC_Read_Byte(1);		//读数据,发送ACK  
		len--;
		buf++; 
	}    
    IIC_Stop();	//产生一个停止条件 
	return 0;	
}
//IIC写一个字节 
//reg:寄存器地址
//data:数据
//返回值:0,正常
//    其他,错误代码
u8 VL53L0X_Write_Byte(u8 reg,u8 data) 				 
{ 
  IIC_Start(); 
	IIC_Send_Byte((VL53L0X_Add<<1)|0);//发送器件地址+写命令	
	if(IIC_Wait_Ack())	//等待应答
	{
		IIC_Stop();		 
		return 1;		
	}
    IIC_Send_Byte(reg);	//写寄存器地址
    IIC_Wait_Ack();		//等待应答 
	IIC_Send_Byte(data);//发送数据
	if(IIC_Wait_Ack())	//等待ACK
	{
		IIC_Stop();	 
		return 1;		 
	}		 
    IIC_Stop();	 
	return 0;
}
//IIC读一个字节 
//reg:寄存器地址 
//返回值:读到的数据
u8 VL53L0X_Read_Byte(u8 reg)
{
	u8 res;
    IIC_Start(); 
	//IIC_Send_Byte((VL53L0X_Add<<1)|0);//发送器件地址+写命令	
	IIC_Send_Byte(0x52);//发送器件地址+写命令	
	IIC_Wait_Ack();		//等待应答 
    IIC_Send_Byte(reg);	//写寄存器地址
    IIC_Wait_Ack();		//等待应答
    IIC_Start();
	IIC_Send_Byte(0x53 );//发送器件地址+读命令	
    IIC_Wait_Ack();		//等待应答 
	res=IIC_Read_Byte(0);//读取数据,发送nACK 
    IIC_Stop();			//产生一个停止条件 
	return res;		
}


VL53L0.h:

#ifndef _VL53L0_H
#define _VL53L0_H

#define VL53L0X_REG_IDENTIFICATION_MODEL_ID         0xc0
#define VL53L0X_REG_IDENTIFICATION_REVISION_ID      0xc2
#define VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD   0x50
#define VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD 0x70
#define VL53L0X_REG_SYSRANGE_START                  0x00
#define VL53L0X_REG_RESULT_INTERRUPT_STATUS         0x13
#define VL53L0X_REG_RESULT_RANGE_STATUS             0x14
#define VL53L0X_Add 0x29

#include "sys.h"

u8 VL53L0X_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf);//连续写
u8 VL53L0X_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf);//连续读
u8 VL53L0X_Write_Byte(u8 reg,u8 data);//写一个字节
u8 VL53L0X_Read_Byte(u8 reg);//读一个字节
uint16_t bswap(u8 b[]); 				 
uint16_t VL53L0X_decode_vcsel_period(short vcsel_period_reg);	
uint16_t makeuint16(int lsb, int msb);		 
#endif



2.读取数据



a.初始化配置


主函数初始化配置

#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "fmc.h"

#include "myiic.h"                     //测距初始化
#include "VL53L0.h"                      //测距初始化


定义相关变量

float data[2],i;
uint8_t  pcStr[20];
uint8_t aTxStartMessage;//储存接收的数据
uint8_t USART_RX_STA;
int z1,js,bzpd=0,bzpd1=0;
int temp0,temp1,temp2;
static int  x,y,z,xz,yz=0;                   //串口接收到的横纵坐标  
extern uint16_t msHcCount;
float length=0;
extern int jd1,asd;
u8 val = 0;                    //测距函数定义
u8 gbuf[16];
u8 DeviceRangeStatusInternal;


在mian函数中添加声明初始化

    SystemClock_Config();
    IIC_Init();                     //使能定义,已经移植到cube
     MX_USART1_UART_Init(); 
	uint32_t cnt = 0;
	uint16_t count[3];
	  MX_GPIO_Init();
    MX_FMC_Init();



b.获取数据


在while(1)中添加如下代码

		 while(cnt < 100)
		 {
					HAL_Delay(10);  
				val = VL53L0X_Read_Byte(VL53L0X_REG_RESULT_RANGE_STATUS);
				if( val & 0x01) break;
				cnt++;
		 }
		 VL53L0X_Read_Len(VL53L0X_Add, 0x14 , 12, gbuf);		
		 count[0] = makeuint16(gbuf[7], gbuf[6]);
		 count[1] = makeuint16(gbuf[9], gbuf[8]);
		 count[2] = makeuint16(gbuf[11], gbuf[10]);
		 DeviceRangeStatusInternal = ((gbuf[0] & 0x78) >> 3);
		 printf("\r\n ambient count = %4d signal count = %4d distance = %4d status = %d ",count[0],count[1],count[2],DeviceRangeStatusInternal);
		// data_analy(count[2]);
		HAL_Delay(200);  



c.结果展示


连接串口线到电脑,设置波特率为115200,即可看到相关数据

在这里插入图片描述

在这里插入图片描述




3.总结


数据中第一个是环境统计,第二个是信号数统计,如果前方物体越平滑,值越小趋近1,如果前方物体有多个凹凸面,或者检查到多个物体玛者信号数越大,第三个就是相对距离,单位是mm,我用的是一个简单的测距模块,测试精度为20mm—3m,如果高低于这个范围,则会显示20或者8190,一般在1m中效果最佳,准确度比HC05.06要高很多,适合近距离测距,本文章只粘贴了一部分主要程序,如果有需要完整工程可以在下面链接下载,比赛准备用,有缺陷之处,还望请各位大佬指教



三.程序下载链接

https://download.csdn.net/download/weixin_44984773/20357255?spm=1001.2014.3001.5501



版权声明:本文为weixin_44984773原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。