十八届智能车负压电磁组(四):赛道特殊元素处理篇

文章目录

前言

一、圆环

二、坡道和障碍物

三、其他元素

四、附录


前言

在上一篇中,我们已经讲述了通过差速控制可以让小车快速的过弯,但对于赛道上一些特殊元素,需要我们单独处理,为此,本篇主要讲解一些特殊元素的处理方法。

一、圆环

对于圆环,主要分5步来完成。

首先是判断为圆环,这一步至关重要,如果检测出错的话,那么小车可能就不能正确入环。

思路:从上图来看,当小车从0位置前进到1位置时,属于正常循迹,当小车到达1位置后,我们可以检测到,电感值都会有所变大,但出现以下特点,

(1)水平电感1和4的电感值是直道上的电感值约2倍,尤其是4电感。

(2)斜电感3和5之间数值相差较大,且5会大于3,根据这个也可以判断圆环是左环还是右环。

那么,我们可以判定其为圆环,标志位RingFlag=1;

此时车继续往前走,会出现一个现象:由于靠近圆环一侧电感值会比远离圆环一侧电感值大,通过差比和计算,会使得车向靠近圆环方向运动,但是当车接近2位置之后,两侧电感值又相差不多,通过差比和又会使得车向外侧运动,如下图:(这里不得不指明:上面的图只是一个示意图,并不是真实情况下的缩小版)

这里只是一个示意图,可以看出会导致车身在入环时,车身不正,那么我们在下一步判断入环时,会很困难(因为车身姿态不正,我们无法预估车什么时候需要入环),而且还有一个隐患是,当小车向圆环外侧运动时,由于速度比较快,很容易就冲出赛道,所以,需要想一个办法来避免小车从1位置运动到2位置时,向圆环内运动,或者想办法减小向圆环内运动的幅度。

方案一:

我们在判断其是圆环时,即车在位置1时,通过人为的控制舵机,让其以固定角度向前运行,运行到2时,判断是入环点,RingFlag=2;

方案二:

车在位置1时,调整十八届智能车负压电磁组(二):舵机方向控制篇中,差比和公式中的A,B,C,P四个参数,使得误差Error变化平缓,这里可以采用串口将小车从位置1到2这一段路程7个电感的ADC值传输到电脑,然后通过MATLAB将其Error计算出来,然后再调整四个参数,直到满意为止。当小车趋近于直线运行到2位置时,判断是入环点,RingFlag=2;

当RingFlag=2时,到达入环点,通过舵机固定打角,陀螺仪积分来计算当前角度,当陀螺仪角度为30°(这里可以根据需要进行更改)时,到达位置3,RingFlag=3;表明车已进入圆环,然后切换为电感控制舵机,注意此时陀螺仪仍然在计算角度(注意:当RingFlag=3切换为电感循迹时,需要把差比和公式中的A,B,C,P四个参数还原为原来的参数不然小车无法正常循迹)。

当陀螺仪积分角度接近360°(绕一圈)之后,表面小车已经到达出环点,即位置2,RingFlag=4,然后,再将差比和公式中的A,B,C,P四个参数设置为从位置1到位置2时的参数,即让小车从位置2再近似直线运行到4位置,RingFlag=5,然后到达位置4之后,将A,B,C,P四个参数恢复为原来的参数

二、坡道和障碍物

对于坡道的判断,如果只依靠电感是不太可行的,对于坡道来说,由于电磁线是铺设在坡道上面的,当小车靠近坡道时,电感值会明显增大,但是当检测到电感值增大时,车前瞻离坡道已经很近了,如果是障碍物,那么车将无法避开,所以坡道和障碍物都需要借助TOF模块。这里分享两种方案。

方案一:借助两个TOF测距模块

两个TOF模块按照上下来安装,如果是坡道,那么上下两个TOF模块测得的距离会有一定的差值,如果是障碍物的话,差值会很小,以此可以判断出坡道和障碍物。

方案二:人为设置+一个TOF模块

所谓人为设置就是根据赛场上坡道和障碍物的顺序,人为设定坡道和障碍物程序的运行顺序。

当判断出是坡道和障碍物之后,就很容易处理了,如果是坡道,那么当电感值增大的时候就适当降低速度,不至于飞坡。

如果是障碍物的话,根据三步或者四步来避开:

 当在1位置检测到障碍物时,陀螺仪开始积分,然后设置一个目标角度Traget_angle(假设为45°),然后传给舵机方向环,同时编码器开始计数,当编码器计数到达设定的阈值,即到达位置2,再设置目标角度为0°,编码器停止积分,小车在方向环的控制下一直运行,然后通过电感ADC值进行检测,判断是否回到赛道上,即位置3,若检测到赛道上就切换为电磁循迹。

三、其他元素

至于其他元素我觉得没必要判断,直接冲就完了。

四、附录

如果采用两个TOF测距模块的话,需要更改一下逐飞提供的代码。由于TOF模块使用的是IIC通讯,可以使用软件IIC和硬件IIC来实现数据传输,我们这里使用软件IIC。

主要是通过枚举来定义多个TOF模块。

下面是源码:

/*********************************************************************************************************************
* MM32F527X-E9P Opensourec Library 即(MM32F527X-E9P 开源库)是一个基于官方 SDK 接口的第三方开源库
* Copyright (c) 2022 SEEKFREE 逐飞科技
* 
* 本文件是 MM32F527X-E9P 开源库的一部分
* 
* MM32F527X-E9P 开源库 是免费软件
* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款
* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它
* 
* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证
* 甚至没有隐含的适销性或适合特定用途的保证
* 更多细节请参见 GPL
* 
* 您应该在收到本开源库的同时收到一份 GPL 的副本
* 如果没有,请参阅<https://www.gnu.org/licenses/>
* 
* 额外注明:
* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本
* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中
* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件
* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明)
* 
* 文件名称          zf_device_dl1a
* 公司名称          成都逐飞科技有限公司
* 版本信息          查看 libraries/doc 文件夹内 version 文件 版本说明
* 开发环境          MDK 5.37
* 适用平台          MM32F527X_E9P
* 店铺链接          https://seekfree.taobao.com/
* 
* 修改记录
* 日期              作者                备注
* 2022-08-10        Teternal            first version
********************************************************************************************************************/
/*********************************************************************************************************************
* 接线定义:
*                   ------------------------------------
*                   模块管脚            单片机管脚
*                   SCL                 查看 zf_device_dl1a.h 中 DL1A_SCL_PIN  宏定义
*                   SDA                 查看 zf_device_dl1a.h 中 DL1A_SDA_PIN  宏定义
*                   VCC                 5V 电源
*                   GND                 电源地
*                   ------------------------------------
*                   ------------------------------------
********************************************************************************************************************/

#ifndef _ZF_DEVICE_DL1A_H_
#define _ZF_DEVICE_DL1A_H_

#include "common.h"
#include "board.h"

// 需要注意的是 DL1A 手册最高支持 400KHz 的 IIC 通信速率
// 需要注意的是 DL1A 手册最高支持 400KHz 的 IIC 通信速率
// 需要注意的是 DL1A 手册最高支持 400KHz 的 IIC 通信速率

typedef enum
{
	DL1A_1 = 0,
	DL1A_2 = 1,
	DL1A_3 = 2,
}DL1A_enum;//DL1A枚举

#define DL1A1_SCL_P65 P65
#define DL1A1_SDA_P63 P63
#define DL1A1_XS_P47  P47

#define DL1A2_SCL_P15 P15
#define DL1A2_SDA_P14 P14
#define DL1A2_XS_P16  P16

#define DL1A3_SCL_P51 P51
#define DL1A3_SDA_P50 P50
#define DL1A3_XS_P37  P37

//====================================================软件 IIC 驱动====================================================
#define DL1A_SOFT_IIC_DELAY      (30 )                                        // 软件 IIC 的时钟延时周期 数值越小 IIC 通信速率越快
//#define DL1A_SCL_PIN             (P65 )                                       // 软件 IIC SCL 引脚 连接 DL1A 的 SCL 引脚
//#define DL1A_SDA_PIN             (P63 )                                       // 软件 IIC SDA 引脚 连接 DL1A 的 SDA 引脚
//====================================================软件 IIC 驱动====================================================


//#define DL1A_XSHUT_PIN           (P47)
#define DL1A_TIMEOUT_COUNT       (0x00FF)                                    // DL1A 超时计数

//================================================定义 DL1A 内部地址================================================
#define DL1A_DEV_ADDR                                    (0x52 >> 1)         // 0b0101001

#define DL1A_SYSRANGE_START                              (0x00)

#define DL1A_SYSTEM_SEQUENCE_CONFIG                      (0x01)
#define DL1A_SYSTEM_INTERMEASUREMENT_PERIOD              (0x04)
#define DL1A_SYSTEM_RANGE_CONFIG                         (0x09)
#define DL1A_SYSTEM_INTERRUPT_GPIO_CONFIG                (0x0A)
#define DL1A_SYSTEM_INTERRUPT_CLEAR                      (0x0B)
#define DL1A_SYSTEM_THRESH_HIGH                          (0x0C)
#define DL1A_SYSTEM_THRESH_LOW                           (0x0E)
#define DL1A_SYSTEM_HISTOGRAM_BIN                        (0x81)

#define DL1A_RESULT_INTERRUPT_STATUS                     (0x13)
#define DL1A_RESULT_RANGE_STATUS                         (0x14)
#define DL1A_RESULT_PEAK_SIGNAL_RATE_REF                 (0xB6)
#define DL1A_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN       (0xBC)
#define DL1A_RESULT_CORE_RANGING_TOTAL_EVENTS_RTN        (0xC0)
#define DL1A_RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF       (0xD0)
#define DL1A_RESULT_CORE_RANGING_TOTAL_EVENTS_REF        (0xD4)

#define DL1A_PRE_RANGE_CONFIG_MIN_SNR                    (0x27)
#define DL1A_PRE_RANGE_CONFIG_VCSEL_PERIOD               (0x50)
#define DL1A_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI          (0x51)
#define DL1A_PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO          (0x52)
#define DL1A_PRE_RANGE_CONFIG_VALID_PHASE_LOW            (0x56)
#define DL1A_PRE_RANGE_CONFIG_VALID_PHASE_HIGH           (0x57)
#define DL1A_PRE_RANGE_CONFIG_SIGMA_THRESH_HI            (0x61)
#define DL1A_PRE_RANGE_CONFIG_SIGMA_THRESH_LO            (0x62)
#define DL1A_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT          (0x64)

#define DL1A_FINAL_RANGE_CONFIG_VALID_PHASE_LOW          (0x47)
#define DL1A_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH         (0x48)
#define DL1A_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT (0x44)
#define DL1A_FINAL_RANGE_CONFIG_MIN_SNR                  (0x67)
#define DL1A_FINAL_RANGE_CONFIG_VCSEL_PERIOD             (0x70)
#define DL1A_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI        (0x71)
#define DL1A_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO        (0x72)

#define DL1A_GLOBAL_CONFIG_VCSEL_WIDTH                   (0x32)
#define DL1A_GLOBAL_CONFIG_SPAD_ENABLES_REF_0            (0xB0)
#define DL1A_GLOBAL_CONFIG_SPAD_ENABLES_REF_1            (0xB1)
#define DL1A_GLOBAL_CONFIG_SPAD_ENABLES_REF_2            (0xB2)
#define DL1A_GLOBAL_CONFIG_SPAD_ENABLES_REF_3            (0xB3)
#define DL1A_GLOBAL_CONFIG_SPAD_ENABLES_REF_4            (0xB4)
#define DL1A_GLOBAL_CONFIG_SPAD_ENABLES_REF_5            (0xB5)
#define DL1A_GLOBAL_CONFIG_REF_EN_START_SELECT           (0xB6)

#define DL1A_ALGO_PART_TO_PART_RANGE_OFFSET_MM           (0x28)
#define DL1A_ALGO_PHASECAL_LIM                           (0x30)
#define DL1A_ALGO_PHASECAL_CONFIG_TIMEOUT                (0x30)

#define DL1A_HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT       (0x33)
#define DL1A_HISTOGRAM_CONFIG_READOUT_CTRL               (0x55)

#define DL1A_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD         (0x4E)
#define DL1A_DYNAMIC_SPAD_REF_EN_START_OFFSET            (0x4F)

#define DL1A_MSRC_CONFIG_TIMEOUT_MACROP                  (0x46)
#define DL1A_MSRC_CONFIG                                 (0x60)

#define DL1A_IDENTIFICATION_MODEL_ID                     (0xC0)
#define DL1A_IDENTIFICATION_REVISION_ID                  (0xC2)

#define DL1A_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS       (0x20)

#define DL1A_POWER_MANAGEMENT_GO1_POWER_FORCE            (0x80)

#define DL1A_GPIO_HV_MUX_ACTIVE_HIGH                     (0x84)

#define DL1A_I2C_SLAVE_DEVICE_ADDRESS                    (0x8A)

#define DL1A_SOFT_RESET_GO2_SOFT_RESET_N                 (0xBF)

#define DL1A_OSC_CALIBRATE_VAL                           (0xF8)

#define DL1A_IO_VOLTAGE_CONFIG                           (0x89)              // IO 电压设置寄存器地址 默认 1V8 使用修改为 2V8

//================================================定义 DL1A 内部地址================================================

#define DL1A_MIN_TIMING_BUDGET                           (20000)

#define DL1A_GET_START_OVERHEAD                          (1910)
#define DL1A_SET_START_OVERHEAD                          (1320)
#define DL1A_END_OVERHEAD                                (960 )
#define DL1A_TCC_OVERHEAD                                (590 )
#define DL1A_DSS_OVERHEAD                                (690 )
#define DL1A_MSRC_OVERHEAD                               (660 )
#define DL1A_PRERANGE_OVERHEAD                           (660 )
#define DL1A_FINALlRANGE_OVERHEAD                        (550 )

typedef enum
{
    DL1A_VCSEL_PERIOD_PER_RANGE,
    DL1A_VCSEL_PERIOD_FINAL_RANGE,
}dl1a_vcsel_period_type_enum;

typedef struct
{
    uint8 tcc;
    uint8 msrc;
    uint8 dss;
    uint8 pre_range;
    uint8 final_range;
}dl1a_sequence_enables_step_struct;

typedef struct
{
    uint16 pre_range_vcsel_period_pclks;
    uint16 final_range_vcsel_period_pclks;

    uint16 msrc_dss_tcc_mclks;
    uint16 pre_range_mclks;
    uint16 final_range_mclks;
    uint32 msrc_dss_tcc_us;
    uint32 pre_range_us;
    uint32 final_range_us;
}dl1a_sequence_timeout_step_struct;

extern uint8 dl1a_finsh_flag[3];
extern uint16 dl1a_distance_mm[3];
void 	dl1a_get_distance (DL1A_enum DL1A_n);

uint8  dl1a_read_range   (void);

uint8  dl1a_init         (DL1A_enum DL1A_n);

#endif
/*********************************************************************************************************************
* MM32F527X-E9P Opensourec Library 即(MM32F527X-E9P 开源库)是一个基于官方 SDK 接口的第三方开源库
* Copyright (c) 2022 SEEKFREE 逐飞科技
* 
* 本文件是 MM32F527X-E9P 开源库的一部分
* 
* MM32F527X-E9P 开源库 是免费软件
* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款
* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它
* 
* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证
* 甚至没有隐含的适销性或适合特定用途的保证
* 更多细节请参见 GPL
* 
* 您应该在收到本开源库的同时收到一份 GPL 的副本
* 如果没有,请参阅<https://www.gnu.org/licenses/>
* 
* 额外注明:
* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本
* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中
* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件
* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明)
* 
* 文件名称          zf_device_dl1a
* 公司名称          成都逐飞科技有限公司
* 版本信息          查看 libraries/doc 文件夹内 version 文件 版本说明
* 开发环境          MDK 5.37
* 适用平台          MM32F527X_E9P
* 店铺链接          https://seekfree.taobao.com/
* 
* 修改记录
* 日期              作者                备注
* 2022-08-10        Teternal            first version
********************************************************************************************************************/
/*********************************************************************************************************************
* 接线定义:
*                   ------------------------------------
*                   模块管脚            单片机管脚
*                   SCL                 查看 zf_device_dl1a.h 中 DL1A_SCL_PIN  宏定义
*                   SDA                 查看 zf_device_dl1a.h 中 DL1A_SDA_PIN  宏定义
*                   VCC                 5V 电源
*                   GND                 电源地
*                   ------------------------------------
********************************************************************************************************************/


#include "zf_delay.h"
#include "SEEKFREE_DL1A.h"


#pragma warning disable = 183


uint8 dl1a_finsh_flag[3];
uint16 dl1a_distance_mm[3];
bit GET_DL1A_SDA(DL1A_enum DL1A_n)
{
	switch(DL1A_n)
	{
		case DL1A_1: return DL1A1_SDA_P63;
		case DL1A_2: return DL1A2_SDA_P14;
		case DL1A_3: return DL1A3_SDA_P50;
		default:break;
	}		
}
void DL1A_SDA_LOW(DL1A_enum DL1A_n)
{
	switch(DL1A_n)
	{
		case DL1A_1: DL1A1_SDA_P63 = 0;break;
		case DL1A_2: DL1A2_SDA_P14 = 0;break;
		case DL1A_3: DL1A3_SDA_P50 = 0;break;
		default:break;
	}	
}
void DL1A_SDA_HIGH(DL1A_enum DL1A_n)
{
	switch(DL1A_n)
	{
		case DL1A_1: DL1A1_SDA_P63 = 1;break;
		case DL1A_2: DL1A2_SDA_P14 = 1;break;
		case DL1A_3: DL1A3_SDA_P50 = 1;break;
		default:break;
	}	
}

void DL1A_SCL_LOW(DL1A_enum DL1A_n)
{
	switch(DL1A_n)
	{
		case DL1A_1: DL1A1_SCL_P65 = 0;break;
		case DL1A_2: DL1A2_SCL_P15 = 0;break;
		case DL1A_3: DL1A3_SCL_P51 = 0;break;
		default:break;
	}	
}
void DL1A_SCL_HIGH(DL1A_enum DL1A_n)
{
	switch(DL1A_n)
	{
		case DL1A_1: DL1A1_SCL_P65 = 1;break;
		case DL1A_2: DL1A2_SCL_P15 = 1;break;
		case DL1A_3: DL1A3_SCL_P51 = 1;break;
		default:break;
	}	
}

void DL1A1_XS_LOW(DL1A_enum DL1A_n)
{
	switch(DL1A_n)
	{
		case DL1A_1: DL1A1_XS_P47 = 0;break;
		case DL1A_2: DL1A2_XS_P16 = 0;break;
		case DL1A_3: DL1A3_XS_P37 = 0;break;
		default:break;
	}	
}
void DL1A1_XS_HIGH(DL1A_enum DL1A_n)
{
	switch(DL1A_n)
	{
		case DL1A_1: DL1A1_XS_P47 = 1;break;
		case DL1A_2: DL1A2_XS_P16 = 1;break;
		case DL1A_3: DL1A3_XS_P37 = 1;break;
		default:break;
	}	
}


#define ack 1      //主应答
#define no_ack 0   //从应答	

//-------------------------------------------------------------------------------------------------------------------
//  @brief      模拟IIC延时
//  @return     void						
//  @since      v1.0
//  Sample usage:				如果IIC通讯失败可以尝试增加j的值
//-------------------------------------------------------------------------------------------------------------------
static void dl1a_simiic_delay(void)
{
    uint16 j=DL1A_SOFT_IIC_DELAY;   
	while(j--);
}

//内部使用,用户无需调用
static void dl1a_simiic_start(DL1A_enum DL1A_n)
{
	DL1A_SDA_HIGH(DL1A_n);
	DL1A_SCL_HIGH(DL1A_n);
	dl1a_simiic_delay();
	DL1A_SDA_LOW(DL1A_n);
	dl1a_simiic_delay();
	DL1A_SCL_LOW(DL1A_n);
}

//内部使用,用户无需调用
static void dl1a_simiic_stop(DL1A_enum DL1A_n)
{
	DL1A_SDA_LOW(DL1A_n);
	DL1A_SCL_LOW(DL1A_n);
	dl1a_simiic_delay();
	DL1A_SCL_HIGH(DL1A_n);
	dl1a_simiic_delay();
	DL1A_SDA_HIGH(DL1A_n);
	dl1a_simiic_delay();
}

//主应答(包含ack:SDA=0和no_ack:SDA=0)
//内部使用,用户无需调用
static void dl1a_simiic_sendack(DL1A_enum DL1A_n,unsigned char ack_dat)
{
    DL1A_SCL_LOW(DL1A_n);
	dl1a_simiic_delay();
	if(ack_dat) DL1A_SDA_LOW(DL1A_n);
    else    	DL1A_SDA_HIGH(DL1A_n);

    DL1A_SCL_HIGH(DL1A_n);
    dl1a_simiic_delay();
    DL1A_SCL_LOW(DL1A_n);
    dl1a_simiic_delay();
}


static int dl1a_sccb_waitack(DL1A_enum DL1A_n)
{
    DL1A_SCL_LOW(DL1A_n);

	dl1a_simiic_delay();
	
	DL1A_SCL_HIGH(DL1A_n);
    dl1a_simiic_delay();
	
    if(GET_DL1A_SDA(DL1A_n))           //应答为高电平,异常,通信失败
    {

        DL1A_SCL_LOW(DL1A_n);
        return 0;
    }

    DL1A_SCL_LOW(DL1A_n);
	dl1a_simiic_delay();
    return 1;
}

//字节发送程序
//发送c(可以是数据也可是地址),送完后接收从应答
//不考虑从应答位
//内部使用,用户无需调用
static void dl1a_send_ch(DL1A_enum DL1A_n,uint8 c)
{
	uint8 i = 8;
    while(i--)
    {
        if(c & 0x80)	DL1A_SDA_HIGH(DL1A_n);//SDA 输出数据
        else			DL1A_SDA_LOW(DL1A_n);
        c <<= 1;
        dl1a_simiic_delay();
        DL1A_SCL_HIGH(DL1A_n);                //SCL 拉高,采集信号
        dl1a_simiic_delay();
        DL1A_SCL_LOW(DL1A_n);                //SCL 时钟线拉低
    }
	dl1a_sccb_waitack(DL1A_n);
}


//字节接收程序
//接收器件传来的数据,此程序应配合|主应答函数|使用
//内部使用,用户无需调用
static uint8 dl1a_read_ch(DL1A_enum DL1A_n,uint8 ack_x)
{
    uint8 i;
    uint8 c;
    c=0;
    DL1A_SCL_LOW(DL1A_n);
    dl1a_simiic_delay();
    DL1A_SDA_HIGH(DL1A_n);             

    for(i=0;i<8;i++)
    {
        dl1a_simiic_delay();
        DL1A_SCL_LOW(DL1A_n);         //置时钟线为低,准备接收数据位
        dl1a_simiic_delay();
        DL1A_SCL_HIGH(DL1A_n);         //置时钟线为高,使数据线上数据有效
        dl1a_simiic_delay();
        c<<=1;
        if(GET_DL1A_SDA(DL1A_n)) 
        {
            c+=1;   //读数据位,将接收的数据存c
        }
    }

	DL1A_SCL_LOW(DL1A_n);
	dl1a_simiic_delay();
	dl1a_simiic_sendack(DL1A_n,ack_x);
	
    return c;
}


//-------------------------------------------------------------------------------------------------------------------
//  @brief      模拟IIC写数据到设备寄存器函数
//  @param      dev_add			设备地址(低七位地址)
//  @param      reg				寄存器地址
//  @param      dat				写入的数据
//  @return     void						
//  @since      v1.0
//  Sample usage:				
//-------------------------------------------------------------------------------------------------------------------
static void dl1a_simiic_write_dats(DL1A_enum DL1A_n,uint8 dev_add, uint8 *dat, uint32 len)
{
	dl1a_simiic_start(DL1A_n);
    dl1a_send_ch(DL1A_n, (dev_add<<1) | 0x00);   //发送器件地址加写位
	while(len--)
	{
		dl1a_send_ch(DL1A_n, *dat++ );   				 //发送需要写入的数据
	}

	
	dl1a_simiic_stop(DL1A_n);
}


//-------------------------------------------------------------------------------------------------------------------
//  @brief      模拟IIC写数据到设备寄存器函数
//  @param      dev_add			设备地址(低七位地址)
//  @param      reg				寄存器地址
//  @param      dat				写入的数据
//  @return     void						
//  @since      v1.0
//  Sample usage:				
//-------------------------------------------------------------------------------------------------------------------
static void dl1a_simiic_write_reg(DL1A_enum DL1A_n,uint8 dev_add, uint8 reg, uint8 dat)
{
	dl1a_simiic_start(DL1A_n);
    dl1a_send_ch(DL1A_n, (dev_add<<1) | 0x00);   //发送器件地址加写位
	dl1a_send_ch(DL1A_n, reg );   				 //发送从机寄存器地址
	dl1a_send_ch(DL1A_n, dat );   				 //发送需要写入的数据
	dl1a_simiic_stop(DL1A_n);
}

//-------------------------------------------------------------------------------------------------------------------
//  @brief      模拟IIC从设备寄存器读取数据
//  @param      dev_add			设备地址(低七位地址)
//  @param      reg				寄存器地址
//  @param      type			选择通信方式是IIC  还是 SCCB
//  @return     uint8			返回寄存器的数据			
//  @since      v1.0
//  Sample usage:				
//-------------------------------------------------------------------------------------------------------------------
static uint8 dl1a_simiic_read_reg(DL1A_enum DL1A_n,uint8 dev_add, uint8 reg)
{
	uint8 dat;
	dl1a_simiic_start(DL1A_n);
    dl1a_send_ch(DL1A_n, (dev_add<<1) | 0x00);  //发送器件地址加写位
	dl1a_send_ch(DL1A_n, reg );   				//发送从机寄存器地址

	
	dl1a_simiic_start(DL1A_n);
	dl1a_send_ch(DL1A_n,(dev_add<<1) | 0x01);  //发送器件地址加读位
	dat = dl1a_read_ch(DL1A_n,no_ack);   				//读取数据
	dl1a_simiic_stop(DL1A_n);
	
	return dat;
}

//-------------------------------------------------------------------------------------------------------------------
//  @brief      模拟IIC读取多字节数据
//  @param      dev_add			设备地址(低七位地址)
//  @param      reg				寄存器地址
//  @param      dat_add			数据保存的地址指针
//  @param      num				读取字节数量
//  @param      type			选择通信方式是IIC  还是 SCCB
//  @return     uint8			返回寄存器的数据			
//  @since      v1.0
//  Sample usage:				
//-------------------------------------------------------------------------------------------------------------------
static void dl1a_simiic_read_regs(DL1A_enum DL1A_n,uint8 dev_add, uint8 reg, uint8 *dat_add, uint32 num)
{
	dl1a_simiic_start(DL1A_n);
    dl1a_send_ch(DL1A_n, (dev_add<<1) | 0x00);  //发送器件地址加写位
	dl1a_send_ch(DL1A_n, reg );   				//发送从机寄存器地址

	
	dl1a_simiic_start(DL1A_n);
	dl1a_send_ch(DL1A_n, (dev_add<<1) | 0x01);  //发送器件地址加读位
    while(--num)
    {
        *dat_add = dl1a_read_ch(DL1A_n,ack); //读取数据
        dat_add++;
    }
    *dat_add = dl1a_read_ch(DL1A_n,no_ack); //读取数据
	dl1a_simiic_stop(DL1A_n);
}


#define dl1a_write_array(DL1A_n,dat, len)          (dl1a_simiic_write_dats(DL1A_n,DL1A_DEV_ADDR, (dat), (len)))
#define dl1a_write_register(DL1A_n,reg, dat)       (dl1a_simiic_write_reg(DL1A_n,DL1A_DEV_ADDR, (reg), (dat)))
#define dl1a_read_register(DL1A_n,reg)             (dl1a_simiic_read_reg (DL1A_n,DL1A_DEV_ADDR, (reg)))
#define dl1a_read_registers(DL1A_n,reg, dat, len)  (dl1a_simiic_read_regs(DL1A_n,DL1A_DEV_ADDR, (reg), (dat), (len)))

// 这个速率表示从目标反射并被设备检测到的信号的振幅
// 设置此限制可以确定传感器报告有效读数所需的最小测量值
// 设置一个较低的限制可以增加传感器的测量范围
// 但似乎也增加了 <由于来自目标以外的物体的不需要的反射导致> 得到不准确读数的可能性
// 默认为 0.25 MCPS 可预设范围为 0 - 511.99
#define DL1A_DEFAULT_RATE_LIMIT  (0.25)

// 从寄存器数据解码 PCLKs 中 VCSEL (vertical cavity surface emitting laser) 的脉宽周期
#define decode_vcsel_period(reg_val)            (((reg_val) + 1) << 1)

// 从 PCLK 中的 VCSEL 周期计算宏周期 (以 *纳秒为单位)
// PLL_period_ps = 1655
// macro_period_vclks = 2304
#define calc_macro_period(vcsel_period_pclks)   ((((uint32)2304 * (vcsel_period_pclks) * 1655) + 500) / 1000)

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     获取设备 SPAD 信息
// 参数说明     index           索引
// 参数说明     type            类型值
// 返回参数     uint8           是否成功 0-成功 1-失败
// 使用示例     dl1a_get_spad_info(index, type_is_aperture);
// 备注信息     
//-------------------------------------------------------------------------------------------------------------------
static uint8 dl1a_get_spad_info (DL1A_enum DL1A_n,uint8 *index, uint8 *type_is_aperture)
{
    uint8 tmp = 0;
    uint8 return_state = 0;
    volatile uint16 loop_count = 0;

    do
    {
        dl1a_write_register(DL1A_n,0x80, 0x01);
        dl1a_write_register(DL1A_n,0xFF, 0x01);
        dl1a_write_register(DL1A_n,0x00, 0x00);

        dl1a_write_register(DL1A_n,0xFF, 0x06);
        dl1a_read_registers(DL1A_n,0x83, &tmp, 1);
        dl1a_write_register(DL1A_n,0x83, tmp | 0x04);
        dl1a_write_register(DL1A_n,0xFF, 0x07);
        dl1a_write_register(DL1A_n,0x81, 0x01);

        dl1a_write_register(DL1A_n,0x80, 0x01);

        dl1a_write_register(DL1A_n,0x94, 0x6b);
        dl1a_write_register(DL1A_n,0x83, 0x00);

        tmp = 0x00;
        while(tmp != 0x10)
        {
            dl1a_read_registers(DL1A_n,0x83, &tmp, 1);
            loop_count++;
            if(loop_count == DL1A_TIMEOUT_COUNT)
            {
                return_state = 1;
                break;
            }
        }
		
        if(return_state)
        {
            break;
        }
        dl1a_write_register(DL1A_n,0x83, 0x01);
        dl1a_read_registers(DL1A_n,0x92, &tmp, 1);

        *index = tmp & 0x7f;
        *type_is_aperture = (tmp >> 7) & 0x01;

        dl1a_write_register(DL1A_n,0x81, 0x00);
        dl1a_write_register(DL1A_n,0xFF, 0x06);
        dl1a_read_registers(DL1A_n,0x83, &tmp, 1);
        dl1a_write_register(DL1A_n,0x83, tmp);
        dl1a_write_register(DL1A_n,0xFF, 0x01);
        dl1a_write_register(DL1A_n,0x00, 0x01);

        dl1a_write_register(DL1A_n,0xFF, 0x00);
        dl1a_write_register(DL1A_n,0x80, 0x00);
    }while(0);

    return return_state;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     将超时数值从 MCLKs 转换到对应的 ms
// 参数说明     timeout_period_mclks    超时周期 MCLKs
// 参数说明     vcsel_period_pclks      PCLK 值
// 返回参数     uint32                  返回超时数值
// 使用示例     dl1a_timeout_mclks_to_microseconds(timeout_period_mclks, vcsel_period_pclks);
// 备注信息     将序列步骤超时从具有给定 VCSEL 周期的 MCLK (以 PCLK 为单位)转换为微秒
//-------------------------------------------------------------------------------------------------------------------
static uint32 dl1a_timeout_mclks_to_microseconds (uint16 timeout_period_mclks, uint8 vcsel_period_pclks)
{
    uint32 macro_period_ns = calc_macro_period(vcsel_period_pclks);

    return ((timeout_period_mclks * macro_period_ns) + (macro_period_ns / 2)) / 1000;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     将超时数值从 ms 转换到对应的 MCLKs
// 参数说明     timeout_period_us   超时周期 微秒单位
// 参数说明     vcsel_period_pclks  PCLK 值
// 返回参数     uint32              返回超时数值
// 使用示例     dl1a_timeout_microseconds_to_mclks(timeout_period_us, vcsel_period_pclks);
// 备注信息     将序列步骤超时从微秒转换为具有给定 VCSEL 周期的 MCLK (以 PCLK 为单位)
//-------------------------------------------------------------------------------------------------------------------
static uint32 dl1a_timeout_microseconds_to_mclks (uint32 timeout_period_us, uint8 vcsel_period_pclks)
{
    uint32 macro_period_ns = calc_macro_period(vcsel_period_pclks);

    return (((timeout_period_us * 1000) + (macro_period_ns / 2)) / macro_period_ns);
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     对超时数值进行解码
// 参数说明     reg_val         超时时长 寄存器值
// 返回参数     uint16          返回超时数值
// 使用示例     dl1a_decode_timeout(reg_val);
// 备注信息     从寄存器值解码 MCLK 中的序列步骤超时   
//-------------------------------------------------------------------------------------------------------------------
static uint16 dl1a_decode_timeout (uint16 reg_val)
{
  // 格式: (LSByte * 2 ^ MSByte) + 1
    return  (uint16)((reg_val & 0x00FF) <<
            (uint16)((reg_val & 0xFF00) >> 8)) + 1;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     对超时数值进行编码
// 参数说明     timeout_mclks   超时时长 -MCLKs 值
// 返回参数     uint16          返回编码值
// 使用示例     dl1a_encode_timeout(timeout_mclks);
// 备注信息     在 MCLK 中对超时的序列步骤超时寄存器值进行编码
//-------------------------------------------------------------------------------------------------------------------
static uint16 dl1a_encode_timeout (uint16 timeout_mclks)
{
    uint32 ls_byte = 0;
    uint16 ms_byte = 0;
    uint16 return_data = 0;

    if (timeout_mclks > 0)
    {
        // 格式: (LSByte * 2 ^ MSByte) + 1
        ls_byte = timeout_mclks - 1;
        while ((ls_byte & 0xFFFFFF00) > 0)
        {
            ls_byte >>= 1;
            ms_byte++;
        }
        return_data = (ms_byte << 8) | (ls_byte & 0xFF);
    }
    return return_data;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     获取序列步骤使能设置
// 参数说明     enables         序列使能步骤结构体
// 返回参数     void
// 使用示例     dl1a_get_sequence_step_enables(enables);
// 备注信息     
//-------------------------------------------------------------------------------------------------------------------
static void dl1a_get_sequence_step_enables(DL1A_enum DL1A_n,dl1a_sequence_enables_step_struct *enables)
{
    uint8 sequence_config = 0;
    dl1a_read_registers(DL1A_n,DL1A_SYSTEM_SEQUENCE_CONFIG, &sequence_config, 1);

    enables->tcc          = (sequence_config >> 4) & 0x1;
    enables->dss          = (sequence_config >> 3) & 0x1;
    enables->msrc         = (sequence_config >> 2) & 0x1;
    enables->pre_range    = (sequence_config >> 6) & 0x1;
    enables->final_range  = (sequence_config >> 7) & 0x1;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     获取脉冲周期
// 参数说明     type            预量程类型
// 返回参数     uint8           返回的周期值
// 使用示例     dl1a_get_vcsel_pulse_period(DL1A_VCSEL_PERIOD_PER_RANGE);
// 备注信息     在 PCLKs 中获取给定周期类型的 VCSEL 脉冲周期
//-------------------------------------------------------------------------------------------------------------------
static uint8 dl1a_get_vcsel_pulse_period (DL1A_enum DL1A_n,dl1a_vcsel_period_type_enum type)
{
    uint8 data_buffer = 0;
    if (type == DL1A_VCSEL_PERIOD_PER_RANGE)
    {
        dl1a_read_registers(DL1A_n,DL1A_PRE_RANGE_CONFIG_VCSEL_PERIOD, &data_buffer, 1);
        data_buffer = decode_vcsel_period(data_buffer);
    }
    else if (type == DL1A_VCSEL_PERIOD_FINAL_RANGE)
    {
        dl1a_read_registers(DL1A_n,DL1A_FINAL_RANGE_CONFIG_VCSEL_PERIOD, &data_buffer, 1);
        data_buffer = decode_vcsel_period(data_buffer);
    }
    else
    {
        data_buffer = 255;
    }
    return data_buffer;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     获取序列步骤超时设置
// 参数说明     enables         序列使能步骤结构体
// 参数说明     timeouts        序列超时步骤结构体
// 返回参数     void
// 使用示例     dl1a_get_sequence_step_timeouts(enables, timeouts);
// 备注信息     获取所有超时而不仅仅是请求的超时 并且还存储中间值
//-------------------------------------------------------------------------------------------------------------------
static void dl1a_get_sequence_step_timeouts (DL1A_enum DL1A_n,dl1a_sequence_enables_step_struct const *enables, dl1a_sequence_timeout_step_struct *timeouts)
{
    uint8 reg_buffer[2];
    uint16 reg16_buffer = 0;

    timeouts->pre_range_vcsel_period_pclks = dl1a_get_vcsel_pulse_period(DL1A_n,DL1A_VCSEL_PERIOD_PER_RANGE);

    dl1a_read_registers(DL1A_n,DL1A_MSRC_CONFIG_TIMEOUT_MACROP, reg_buffer, 1);
    timeouts->msrc_dss_tcc_mclks = reg_buffer[0] + 1;
    timeouts->msrc_dss_tcc_us = dl1a_timeout_mclks_to_microseconds(timeouts->msrc_dss_tcc_mclks, (uint8)timeouts->pre_range_vcsel_period_pclks);

    dl1a_read_registers(DL1A_n,DL1A_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI, reg_buffer, 2);
    reg16_buffer = ((uint16) reg_buffer[0] << 8) | reg_buffer[1];
    timeouts->pre_range_mclks = dl1a_decode_timeout(reg16_buffer);
    timeouts->pre_range_us = dl1a_timeout_mclks_to_microseconds(timeouts->pre_range_mclks, (uint8)timeouts->pre_range_vcsel_period_pclks);

    timeouts->final_range_vcsel_period_pclks = dl1a_get_vcsel_pulse_period(DL1A_n,DL1A_VCSEL_PERIOD_FINAL_RANGE);

    dl1a_read_registers(DL1A_n,DL1A_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, reg_buffer, 2);
    reg16_buffer = ((uint16) reg_buffer[0] << 8) | reg_buffer[1];
    timeouts->final_range_mclks = dl1a_decode_timeout(reg16_buffer);

    if (enables->pre_range)
    {
        timeouts->final_range_mclks -= timeouts->pre_range_mclks;
    }

    timeouts->final_range_us = dl1a_timeout_mclks_to_microseconds(timeouts->final_range_mclks, (uint8)timeouts->final_range_vcsel_period_pclks);
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     执行单次参考校准
// 参数说明     vhv_init_byte   预设校准值
// 返回参数     uint8           操作是否成功 0-成功 1-失败
// 使用示例     dl1a_get_vcsel_pulse_period(DL1A_VCSEL_PERIOD_PER_RANGE);
// 备注信息     在 PCLKs 中获取给定周期类型的 VCSEL 脉冲周期
//-------------------------------------------------------------------------------------------------------------------
static uint8 dl1a_perform_single_ref_calibration (DL1A_enum DL1A_n,uint8 vhv_init_byte)
{
    uint8 return_state = 0;
    uint8 data_buffer = 0;
    volatile uint16 loop_count = 0;
    do
    {
        dl1a_write_register(DL1A_n,DL1A_SYSRANGE_START, 0x01 | vhv_init_byte);
        dl1a_read_registers(DL1A_n,DL1A_MSRC_CONFIG_TIMEOUT_MACROP, &data_buffer, 1);
        while ((data_buffer & 0x07) == 0)
        {
            if (loop_count > 0x8fe0)
            {
                return_state = 1;
                break;
            }
            if (loop_count++ % 0x10 == 0)
            {
                dl1a_read_registers(DL1A_n,DL1A_MSRC_CONFIG_TIMEOUT_MACROP, &data_buffer, 1);
            }
        }
        if(return_state)
        {
            break;
        }
        dl1a_write_register(DL1A_n,DL1A_SYSTEM_INTERRUPT_CLEAR, 0x01);
        dl1a_write_register(DL1A_n,DL1A_SYSRANGE_START, 0x00);
    }while(0);

    return return_state;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     设置测量定时预算 (以微秒为单位)
// 参数说明     budget_us       设定的测量允许的时间
// 返回参数     uint8           操作结果 0-成功 1-失败
// 使用示例     dl1a_set_measurement_timing_budget(measurement_timing_budget_us);
// 备注信息     这是一次测量允许的时间
//              即在测距序列的子步骤之间分配时间预算
//              更长的时间预算允许更精确的测量
//              增加一个N倍的预算可以减少一个sqrt(N)倍的范围测量标准偏差
//              默认为33毫秒 最小值为20 ms
//-------------------------------------------------------------------------------------------------------------------
static uint8 dl1a_set_measurement_timing_budget (DL1A_enum DL1A_n,uint32 budget_us)
{
    uint8 return_state = 0;
    uint8 data_buffer[3];
    uint16 dat = 0;
	uint32 used_budget_us;
	uint32 final_range_timeout_us;
	uint16 final_range_timeout_mclks;
	
    dl1a_sequence_enables_step_struct enables;
    dl1a_sequence_timeout_step_struct timeouts;

    do
    {
        if (budget_us < DL1A_MIN_TIMING_BUDGET)
        {
            return_state = 1;
            break;
        }

        used_budget_us = DL1A_SET_START_OVERHEAD + DL1A_END_OVERHEAD;
        dl1a_get_sequence_step_enables(DL1A_n,&enables);
        dl1a_get_sequence_step_timeouts(DL1A_n,&enables, &timeouts);

        if (enables.tcc)
        {
            used_budget_us += (timeouts.msrc_dss_tcc_us + DL1A_TCC_OVERHEAD);
        }

        if (enables.dss)
        {
            used_budget_us += 2 * (timeouts.msrc_dss_tcc_us + DL1A_DSS_OVERHEAD);
        }
        else if (enables.msrc)
        {
            used_budget_us += (timeouts.msrc_dss_tcc_us + DL1A_MSRC_OVERHEAD);
        }

        if (enables.pre_range)
        {
            used_budget_us += (timeouts.pre_range_us + DL1A_PRERANGE_OVERHEAD);
        }

        if (enables.final_range)
        {
            // 请注意 最终范围超时由计时预算和序列中所有其他超时的总和决定
            // 如果没有空间用于最终范围超时 则将设置错误
            // 否则 剩余时间将应用于最终范围
            used_budget_us += DL1A_FINALlRANGE_OVERHEAD;
            if (used_budget_us > budget_us)
            {
                // 请求的超时太大
                return_state = 1;
                break;
            }

            // 对于最终超时范围 必须添加预量程范围超时
            // 为此 最终超时和预量程超时必须以宏周期 MClks 表示
            // 因为它们具有不同的 VCSEL 周期
            final_range_timeout_us = budget_us - used_budget_us;
            final_range_timeout_mclks =
            dl1a_timeout_microseconds_to_mclks(final_range_timeout_us,
                     (uint8)timeouts.final_range_vcsel_period_pclks);

            if (enables.pre_range)
            {
                final_range_timeout_mclks += timeouts.pre_range_mclks;
            }

            dat = dl1a_encode_timeout(final_range_timeout_mclks);
            data_buffer[0] = DL1A_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI;
            data_buffer[1] = ((dat >> 8) & 0xFF);
            data_buffer[2] = (dat & 0xFF);
            dl1a_write_array(DL1A_n,data_buffer, 3);
        }
    }while(0);
    return return_state;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     获取测量定时预算 (以微秒为单位)
// 参数说明     void
// 返回参数     uint32          已设定的测量允许的时间
// 使用示例     dl1a_get_measurement_timing_budget();
// 备注信息     
//-------------------------------------------------------------------------------------------------------------------
static uint32 dl1a_get_measurement_timing_budget (DL1A_enum DL1A_n)
{
    dl1a_sequence_enables_step_struct enables;
    dl1a_sequence_timeout_step_struct timeouts;

    // 开始和结束开销时间始终存在
    uint32 budget_us = DL1A_GET_START_OVERHEAD + DL1A_END_OVERHEAD;

    dl1a_get_sequence_step_enables(DL1A_n,&enables);
    dl1a_get_sequence_step_timeouts(DL1A_n,&enables, &timeouts);

    if (enables.tcc)
    {
        budget_us += (timeouts.msrc_dss_tcc_us + DL1A_TCC_OVERHEAD);
    }

    if (enables.dss)
    {
        budget_us += 2 * (timeouts.msrc_dss_tcc_us + DL1A_DSS_OVERHEAD);
    }
    else if (enables.msrc)
    {
        budget_us += (timeouts.msrc_dss_tcc_us + DL1A_MSRC_OVERHEAD);
    }

    if (enables.pre_range)
    {
        budget_us += (timeouts.pre_range_us + DL1A_PRERANGE_OVERHEAD);
    }

    if (enables.final_range)
    {
        budget_us += (timeouts.final_range_us + DL1A_FINALlRANGE_OVERHEAD);
    }

    return budget_us;
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     设置返回信号速率限制 该值单位为 MCPS (百万次每秒)
// 参数说明     limit_mcps      设置的最小速率
// 返回参数     void
// 使用示例     dl1a_set_signal_rate_limit(0.25);
// 备注信息     这个速率表示从目标反射并被设备检测到的信号的振幅
//              设置此限制可以确定传感器报告有效读数所需的最小测量值
//              设置一个较低的限制可以增加传感器的测量范围
//              但似乎也增加了 <由于来自目标以外的物体的不需要的反射导致> 得到不准确读数的可能性
//              默认为 0.25 MCPS 可预设范围为 0 - 511.99
//-------------------------------------------------------------------------------------------------------------------
static void dl1a_set_signal_rate_limit (DL1A_enum DL1A_n,float limit_mcps)
{
	uint8 data_buffer[3];
    uint16 limit_mcps_16bit = (limit_mcps * (1 << 7));
    //zf_assert(limit_mcps >= 0 || limit_mcps <= 511.99);


    data_buffer[0] = DL1A_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT;
    data_buffer[1] = ((limit_mcps_16bit >> 8) & 0xFF);
    data_buffer[2] = (limit_mcps_16bit & 0xFF);

    dl1a_write_array(DL1A_n,data_buffer, 3);
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     返回以毫米为单位的范围读数
// 参数说明     void
// 返回参数     uint8           0-数据无效 1-数据有效
// 使用示例     dl1a_get_distance();
// 备注信息     在开始单次射程测量后也调用此函数
//-------------------------------------------------------------------------------------------------------------------
void dl1a_get_distance (DL1A_enum DL1A_n)
{
    uint8 reg_databuffer[3];

    dl1a_read_registers(DL1A_n,DL1A_RESULT_INTERRUPT_STATUS, reg_databuffer, 1);
    if((reg_databuffer[0] & 0x07) == 0)
    {
        dl1a_finsh_flag[DL1A_n] = 0;
    }
    else
    {
        // 假设线性度校正增益为默认值 1000 且未启用分数范围
        dl1a_read_registers(DL1A_n,DL1A_RESULT_RANGE_STATUS + 10, reg_databuffer, 2);
        dl1a_distance_mm[DL1A_n] = ((uint16)reg_databuffer[0] << 8);
        dl1a_distance_mm[DL1A_n] |= reg_databuffer[1];

        dl1a_write_register(DL1A_n,DL1A_SYSTEM_INTERRUPT_CLEAR, 0x01);
        dl1a_finsh_flag[DL1A_n] = 1;
    }
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     初始化 DL1A
// 参数说明     void
// 返回参数     uint8           1-初始化失败 0-初始化成功
// 使用示例     dl1a_init();
// 备注信息     
//-------------------------------------------------------------------------------------------------------------------
uint8 dl1a_init (DL1A_enum DL1A_n)
{
    uint32 measurement_timing_budget_us = 0;
    uint8 stop_variable = 0;
    uint8 return_state = 0;
    uint8 reg_data_buffer = 0;
    uint8 ref_spad_map[6];
    uint8 data_buffer[7];
	uint8 i = 0;
	
    memset(ref_spad_map, 0, 6);
    memset(data_buffer, 0, 7);


    do
    {
        delay_ms(100);
        DL1A1_XS_LOW(DL1A_n);
        delay_ms(50);
        DL1A1_XS_HIGH(DL1A_n); 
        delay_ms(100);

        // -------------------------------- DL1A 启动初始化 --------------------------------
        reg_data_buffer = dl1a_read_register(DL1A_n,DL1A_IO_VOLTAGE_CONFIG);         // 传感器默认 IO 为 1.8V 模式
        dl1a_write_register(DL1A_n,DL1A_IO_VOLTAGE_CONFIG, reg_data_buffer | 0x01);  // 配置 IO 为 2.8V 模式

        dl1a_write_register(DL1A_n,0x88, 0x00);                                         // 设置为标准 IIC 模式

        dl1a_write_register(DL1A_n,0x80, 0x01);
        dl1a_write_register(DL1A_n,0xFF, 0x01);
        dl1a_write_register(DL1A_n,0x00, 0x00);

        dl1a_read_registers(DL1A_n,0x91, &stop_variable , 1);

        dl1a_write_register(DL1A_n,0x00, 0x01);
        dl1a_write_register(DL1A_n,0xFF, 0x00);
        dl1a_write_register(DL1A_n,0x80, 0x00);

        // 禁用 SIGNAL_RATE_MSRC(bit1) 和 SIGNAL_RATE_PRE_RANGE(bit4) 限制检查
        reg_data_buffer = dl1a_read_register(DL1A_n,DL1A_MSRC_CONFIG);
        dl1a_write_register(DL1A_n,DL1A_MSRC_CONFIG, reg_data_buffer | 0x12);

        dl1a_set_signal_rate_limit(DL1A_n,DL1A_DEFAULT_RATE_LIMIT);                  // 设置信号速率限制
        dl1a_write_register(DL1A_n,DL1A_SYSTEM_SEQUENCE_CONFIG, 0xFF);
        // -------------------------------- DL1A 启动初始化 --------------------------------

        // -------------------------------- DL1A 配置初始化 --------------------------------
        if (dl1a_get_spad_info(DL1A_n,&data_buffer[0], &data_buffer[1]))
        {
			return_state = 1;
            // 如果程序在输出了断言信息 并且提示出错位置在这里
            // 那么就是 dl1a 自检出错并超时退出了
            // 检查一下接线有没有问题 如果没问题可能就是坏了

			printf("dl1a init error.\r\n");
			break;
        }

        // 从 GLOBAL_CONFIG_SPAD_ENABLES_REF_[0-6] 获取 SPAD map (RefGoodSpadMap) 数据
        dl1a_read_registers(DL1A_n,DL1A_GLOBAL_CONFIG_SPAD_ENABLES_REF_0, ref_spad_map, 6);

        dl1a_write_register(DL1A_n,0xFF, 0x01);
        dl1a_write_register(DL1A_n,DL1A_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
        dl1a_write_register(DL1A_n,DL1A_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
        dl1a_write_register(DL1A_n,0xFF, 0x00);
        dl1a_write_register(DL1A_n,DL1A_GLOBAL_CONFIG_REF_EN_START_SELECT, 0xB4);

        data_buffer[2] = data_buffer[1] ? 12 : 0; // 12 is the first aperture spad
        for (i = 0; i < 48; i++)
        {
            if (i < data_buffer[2] || data_buffer[3] == data_buffer[0])
            {
                // 此位低于应启用的第一个位
                // 或者 (eference_spad_count) 位已启用
                // 因此此位为零
                ref_spad_map[i / 8] &= ~(1 << (i % 8));
            }
            else if ((ref_spad_map[i / 8] >> (i % 8)) & 0x1)
            {
                data_buffer[3]++;
            }
        }

        data_buffer[0] = DL1A_GLOBAL_CONFIG_SPAD_ENABLES_REF_0;
        for(i = 1; i < 7; i++)
        {
            data_buffer[1] = ref_spad_map[i-1];
        }
        dl1a_write_array(DL1A_n,data_buffer, 7);

        // 默认转换设置 version 02/11/2015_v36
        dl1a_write_register(DL1A_n,0xFF, 0x01);
        dl1a_write_register(DL1A_n,0x00, 0x00);
        dl1a_write_register(DL1A_n,0xFF, 0x00);
        dl1a_write_register(DL1A_n,0x09, 0x00);
        dl1a_write_register(DL1A_n,0x10, 0x00);
        dl1a_write_register(DL1A_n,0x11, 0x00);
        dl1a_write_register(DL1A_n,0x24, 0x01);
        dl1a_write_register(DL1A_n,0x25, 0xFF);
        dl1a_write_register(DL1A_n,0x75, 0x00);
        dl1a_write_register(DL1A_n,0xFF, 0x01);
        dl1a_write_register(DL1A_n,0x4E, 0x2C);
        dl1a_write_register(DL1A_n,0x48, 0x00);
        dl1a_write_register(DL1A_n,0x30, 0x20);
        dl1a_write_register(DL1A_n,0xFF, 0x00);
        dl1a_write_register(DL1A_n,0x30, 0x09);
        dl1a_write_register(DL1A_n,0x54, 0x00);
        dl1a_write_register(DL1A_n,0x31, 0x04);
        dl1a_write_register(DL1A_n,0x32, 0x03);
        dl1a_write_register(DL1A_n,0x40, 0x83);
        dl1a_write_register(DL1A_n,0x46, 0x25);
        dl1a_write_register(DL1A_n,0x60, 0x00);
        dl1a_write_register(DL1A_n,0x27, 0x00);
        dl1a_write_register(DL1A_n,0x50, 0x06);
        dl1a_write_register(DL1A_n,0x51, 0x00);
        dl1a_write_register(DL1A_n,0x52, 0x96);
        dl1a_write_register(DL1A_n,0x56, 0x08);
        dl1a_write_register(DL1A_n,0x57, 0x30);
        dl1a_write_register(DL1A_n,0x61, 0x00);
        dl1a_write_register(DL1A_n,0x62, 0x00);
        dl1a_write_register(DL1A_n,0x64, 0x00);
        dl1a_write_register(DL1A_n,0x65, 0x00);
        dl1a_write_register(DL1A_n,0x66, 0xA0);
        dl1a_write_register(DL1A_n,0xFF, 0x01);
        dl1a_write_register(DL1A_n,0x22, 0x32);
        dl1a_write_register(DL1A_n,0x47, 0x14);
        dl1a_write_register(DL1A_n,0x49, 0xFF);
        dl1a_write_register(DL1A_n,0x4A, 0x00);
        dl1a_write_register(DL1A_n,0xFF, 0x00);
        dl1a_write_register(DL1A_n,0x7A, 0x0A);
        dl1a_write_register(DL1A_n,0x7B, 0x00);
        dl1a_write_register(DL1A_n,0x78, 0x21);
        dl1a_write_register(DL1A_n,0xFF, 0x01);
        dl1a_write_register(DL1A_n,0x23, 0x34);
        dl1a_write_register(DL1A_n,0x42, 0x00);
        dl1a_write_register(DL1A_n,0x44, 0xFF);
        dl1a_write_register(DL1A_n,0x45, 0x26);
        dl1a_write_register(DL1A_n,0x46, 0x05);
        dl1a_write_register(DL1A_n,0x40, 0x40);
        dl1a_write_register(DL1A_n,0x0E, 0x06);
        dl1a_write_register(DL1A_n,0x20, 0x1A);
        dl1a_write_register(DL1A_n,0x43, 0x40);
        dl1a_write_register(DL1A_n,0xFF, 0x00);
        dl1a_write_register(DL1A_n,0x34, 0x03);
        dl1a_write_register(DL1A_n,0x35, 0x44);
        dl1a_write_register(DL1A_n,0xFF, 0x01);
        dl1a_write_register(DL1A_n,0x31, 0x04);
        dl1a_write_register(DL1A_n,0x4B, 0x09);
        dl1a_write_register(DL1A_n,0x4C, 0x05);
        dl1a_write_register(DL1A_n,0x4D, 0x04);
        dl1a_write_register(DL1A_n,0xFF, 0x00);
        dl1a_write_register(DL1A_n,0x44, 0x00);
        dl1a_write_register(DL1A_n,0x45, 0x20);
        dl1a_write_register(DL1A_n,0x47, 0x08);
        dl1a_write_register(DL1A_n,0x48, 0x28);
        dl1a_write_register(DL1A_n,0x67, 0x00);
        dl1a_write_register(DL1A_n,0x70, 0x04);
        dl1a_write_register(DL1A_n,0x71, 0x01);
        dl1a_write_register(DL1A_n,0x72, 0xFE);
        dl1a_write_register(DL1A_n,0x76, 0x00);
        dl1a_write_register(DL1A_n,0x77, 0x00);
        dl1a_write_register(DL1A_n,0xFF, 0x01);
        dl1a_write_register(DL1A_n,0x0D, 0x01);
        dl1a_write_register(DL1A_n,0xFF, 0x00);
        dl1a_write_register(DL1A_n,0x80, 0x01);
        dl1a_write_register(DL1A_n,0x01, 0xF8);
        dl1a_write_register(DL1A_n,0xFF, 0x01);
        dl1a_write_register(DL1A_n,0x8E, 0x01);
        dl1a_write_register(DL1A_n,0x00, 0x01);
        dl1a_write_register(DL1A_n,0xFF, 0x00);
        dl1a_write_register(DL1A_n,0x80, 0x00);

        // 将中断配置设置为新样品就绪
        dl1a_write_register(DL1A_n,DL1A_SYSTEM_INTERRUPT_GPIO_CONFIG, 0x04);
        reg_data_buffer = dl1a_read_register(DL1A_n,DL1A_GPIO_HV_MUX_ACTIVE_HIGH);
        dl1a_write_register(DL1A_n,DL1A_GPIO_HV_MUX_ACTIVE_HIGH, reg_data_buffer & ~0x10);
        dl1a_write_register(DL1A_n,DL1A_SYSTEM_INTERRUPT_CLEAR, 0x01);

        measurement_timing_budget_us  = dl1a_get_measurement_timing_budget(DL1A_n);

        // 默认情况下禁用 MSRC 和 TCC
        // MSRC = Minimum Signal Rate Check
        // TCC = Target CentreCheck
        dl1a_write_register(DL1A_n,DL1A_SYSTEM_SEQUENCE_CONFIG, 0xE8);
        dl1a_set_measurement_timing_budget(DL1A_n,measurement_timing_budget_us);    // 重新计算时序预算
        // -------------------------------- DL1A 配置初始化 --------------------------------

        dl1a_write_register(DL1A_n,DL1A_SYSTEM_SEQUENCE_CONFIG, 0x01);
        if (dl1a_perform_single_ref_calibration(DL1A_n,0x40))
        {
            return_state = 1;
            break;
        }
        dl1a_write_register(DL1A_n,DL1A_SYSTEM_SEQUENCE_CONFIG, 0x02);
        if (dl1a_perform_single_ref_calibration(DL1A_n,0x00))
        {
            return_state = 1;
            break;
        }
        dl1a_write_register(DL1A_n,DL1A_SYSTEM_SEQUENCE_CONFIG, 0xE8);           // 恢复以前的序列配置

        delay_ms(100);

        dl1a_write_register(DL1A_n,0x80, 0x01);
        dl1a_write_register(DL1A_n,0xFF, 0x01);
        dl1a_write_register(DL1A_n,0x00, 0x00);
        dl1a_write_register(DL1A_n,0x91, stop_variable);
        dl1a_write_register(DL1A_n,0x00, 0x01);
        dl1a_write_register(DL1A_n,0xFF, 0x00);
        dl1a_write_register(DL1A_n,0x80, 0x00);

        dl1a_write_register(DL1A_n,DL1A_SYSRANGE_START, 0x02);
    }while(0);

    return return_state;
}

下一篇,将介绍关于UI的程序编写。

十八届智能车负压电磁组(五):UI设计

  • 7
    点赞
  • 133
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值