wiringPi 模拟iic 读取vl53的测距数据

用于机器人神经网络避障的输入,使用3路或者5路测距传感器作为神经网络的输入数据。

使用orangepi zero2 的板带gpio 没有使用自带的I2C,所以需要编写访问vl53底层iic协议。微信截图_20230423164833.png

根据以前单片机模拟iic的调试经验,使用wiringPi 的GPIO模拟iic时序,只要把握好延迟时间一般不会出问题。

初步调试时可以先判断 硬件是否  ACK ,然后接着往下调试。

maic.c   部分如下


/*
orangepi@orangepizero2:~/wiringOP-master$ gpio readall
 +------+-----+----------+------+---+   H616   +---+------+----------+-----+------+
 | GPIO | wPi |   Name   | Mode | V | Physical | V | Mode | Name     | wPi | GPIO |
 +------+-----+----------+------+---+----++----+---+------+----------+-----+------+
 |      |     |     3.3V |      |   |  1 || 2  |   |      | 5V       |     |      |
 |  229 |   0 |    SDA.3 |  OFF | 0 |  3 || 4  |   |      | 5V       |     |      |
 |  228 |   1 |    SCL.3 |  OFF | 0 |  5 || 6  |   |      | GND      |     |      |
 |   73 |   2 |      PC9 |  OFF | 0 |  7 || 8  | 0 | ALT2 | TXD.5    | 3   | 226  |
 |      |     |      GND |      |   |  9 || 10 | 0 | ALT2 | RXD.5    | 4   | 227  |
 |   70 |   5 |      PC6 | ALT5 | 0 | 11 || 12 | 0 | OFF  | PC11     | 6   | 75   |
 |   69 |   7 |      PC5 | ALT5 | 0 | 13 || 14 |   |      | GND      |     |      |
 |   72 |   8 |      PC8 |  OFF | 0 | 15 || 16 | 0 | OFF  | PC15     | 9   | 79   |
 |      |     |     3.3V |      |   | 17 || 18 | 0 | OFF  | PC14     | 10  | 78   |
 |  231 |  11 |   MOSI.1 | ALT4 | 0 | 19 || 20 |   |      | GND      |     |      |
 |  232 |  12 |   MISO.1 | ALT4 | 0 | 21 || 22 | 0 | OFF  | PC7      | 13  | 71   |
 |  230 |  14 |   SCLK.1 | ALT4 | 0 | 23 || 24 | 0 | ALT4 | CE.1     | 15  | 233  |
 |      |     |      GND |      |   | 25 || 26 | 0 | OFF  | PC10     | 16  | 74   |
 |   65 |  17 |      PC1 |  OFF | 0 | 27 || 28 |   |      |          |     |      |
 |  272 |  18 |     PI16 |  OFF | 0 | 29 || 30 |   |      |          |     |      |
 |  262 |  19 |      PI6 |  OFF | 0 | 31 || 32 |   |      |          |     |      |
 |  234 |  20 |     PH10 | ALT3 | 0 | 33 || 34 |   |      |          |     |      |
 +------+-----+----------+------+---+----++----+---+------+----------+-----+------+
 | GPIO | wPi |   Name   | Mode | V | Physical | V | Mode | Name     | wPi | GPIO |
 +------+-----+----------+------+---+   H616   +---+------+----------+-----+------+
orangepi@orangepizero2:~/wiringOP-master$ ls

-lwiringPi -lpthread

*/
typedef unsigned char u8;
typedef unsigned short u16;

#define  BTN_INTERRUPT 0 // 按钮中断
#define  PIN_SDA 5  //PC6
#define  PIN_SCL 7 //PC5
#define  PIN_RST 7

#define        VL53_SCL_SET        {digitalWrite(PIN_SCL, HIGH);}
#define        VL53_SCL_CLR        {digitalWrite(PIN_SCL, LOW);}

#define        VL53_SDA_SET        {digitalWrite(PIN_SDA, HIGH);}
#define        VL53_SDA_CLR        {digitalWrite(PIN_SDA, LOW);}
#define        VL53_SDA_IN         (digitalRead(PIN_SDA))
#define        VL53_SDA_D_OUT      {pinMode(PIN_SDA, OUTPUT);}
#define        VL53_SDA_D_IN       {pinMode(PIN_SDA, INPUT);}

// 2线接口VL53

#define VL53L0X_REG_IDENTIFICATION_MODEL_ID         0xc0
#define VL53L0X_REG_C1_ID                           0xc1
#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 address 0x52  //0x29

void VL53_I2c_Start(void)
{
    VL53_SDA_D_OUT;
    VL53_SDA_SET;
    VL53_SCL_SET;
    delayMicroseconds(4);   //是否需要延迟
    VL53_SDA_CLR;
    delayMicroseconds(4);
    VL53_SCL_CLR;

}
void VL53_I2c_Stop(void)
{
    VL53_SDA_D_OUT;   // 设置SDA为输出方向
    VL53_SCL_CLR;  
    VL53_SDA_CLR;
    delayMicroseconds(4);//是否需要延迟
    VL53_SCL_SET;
    VL53_SDA_SET;        // 发送结束信号
    delayMicroseconds(4);
    //VL53_SDA_D_IN;       //设置SDA为输RU方向
}
u8 VL_IIC_Wait_Ack(void)
{
    int ucErrTime=0;
    VL53_SDA_D_IN;  //SDA设置为输入  
    //VL53_SDA_SET;
    delayMicroseconds(1);      
    VL53_SCL_SET;
    delayMicroseconds(1);    
    while(VL53_SDA_IN)
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            VL53_I2c_Stop();

            printf("time up \n");
            return 1;
        }
    }
    VL53_SCL_CLR;//时钟输出0       
    return 0;  
}

//产生ACK应答
void VL_IIC_Ack(void)
{
    VL53_SCL_CLR;
     VL53_SDA_D_OUT;
    VL53_SDA_CLR;
    delayMicroseconds(2);
    VL53_SCL_SET;
    delayMicroseconds(2);
    VL53_SCL_CLR;
}

//不产生ACK应答          
void VL_IIC_NAck(void)
{
    VL53_SCL_CLR;
     VL53_SDA_D_OUT;
    VL53_SDA_SET;
    delayMicroseconds(2);
    VL53_SCL_SET;
    delayMicroseconds(2);
    VL53_SCL_CLR;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答           
void VL_IIC_Send_Byte(unsigned char txd)
{                        
    unsigned char t;   
    VL53_SDA_D_OUT;         
    VL53_SCL_CLR; //拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        if((txd&0x80)>>7){
            VL53_SDA_SET;
        }

        else{
                VL53_SDA_CLR;
        }

        txd<<=1;    
        delayMicroseconds(2);  
        VL53_SCL_SET;
        delayMicroseconds(2); 
        VL53_SCL_CLR;   
        delayMicroseconds(2);
    }    
}
unsigned char VL_IIC_Read_Byte(void)
{
    unsigned char i,receive=0;
    VL53_SDA_D_IN;//
    VL53_SDA_SET;
    delayMicroseconds(4);;
    for(i=0;i<8;i++ )
    {
        receive<<=1;
        VL53_SCL_CLR; 
        delayMicroseconds(4);
        VL53_SCL_SET;
        delayMicroseconds(4);
        if(VL53_SDA_IN)
            receive |= 0x01;   
      delayMicroseconds(4); //1
    }   
    VL53_SCL_CLR;   
    return receive;
}

//IIC写一个字节数据
unsigned char VL_IIC_Write_1Byte(unsigned char SlaveAddress, unsigned char REG_Address,unsigned char REG_data)
{
    VL53_I2c_Start();
    VL_IIC_Send_Byte(SlaveAddress);
    if(VL_IIC_Wait_Ack())
    {
        VL53_I2c_Stop();//释放总线
        return 1;//没应答则退出

    }
    VL_IIC_Send_Byte(REG_Address);
    VL_IIC_Wait_Ack();  
    delayMicroseconds(5);
    VL_IIC_Send_Byte(REG_data);
    VL_IIC_Wait_Ack();  
    VL53_I2c_Stop();

    return 0;
}

//IIC读一个字节数据
u8 VL_IIC_Read_1Byte(u8 SlaveAddress, u8 REG_Address,u8 *REG_data)
{
    VL53_I2c_Start();
    VL_IIC_Send_Byte(SlaveAddress);//发写命令
    if(VL_IIC_Wait_Ack())
    {
         VL53_I2c_Stop();//释放总线
         return 1;//没应答则退出
    }       
    VL_IIC_Send_Byte(REG_Address);
    VL_IIC_Wait_Ack();
     delayMicroseconds(5);
    VL53_I2c_Start(); 
    VL_IIC_Send_Byte(SlaveAddress|0x01);//发读命令
    VL_IIC_Wait_Ack();
    *REG_data = VL_IIC_Read_Byte();
    VL53_I2c_Stop();

    return 0;
}

//I2C读多个字节数据
uint8_t VL_I2C_Read_nByte(uint8_t SlaveAddress, uint8_t REG_Address, uint8_t *buf, uint16_t len)
{
    VL53_I2c_Start();
    VL_IIC_Send_Byte(SlaveAddress);//发写命令
    if(VL_IIC_Wait_Ack()) 
    {
        VL53_I2c_Stop();//释放总线
        return 1;//没应答则退出
    }
    VL_IIC_Send_Byte(REG_Address);
    VL_IIC_Wait_Ack();
     delayMicroseconds(5);
    VL53_I2c_Start(); 
    VL_IIC_Send_Byte(SlaveAddress|0x01);//发读命令
    VL_IIC_Wait_Ack();
    while(len)
    {
        *buf = VL_IIC_Read_Byte();
        if(1 == len)
        {
            VL_IIC_NAck();
        }
        else
        {
            VL_IIC_Ack();
        }
        buf++;
        len--;
    }
    VL53_I2c_Stop();

    return 0;
}

//I2C写多个字节数据
uint8_t VL_I2C_Write_nByte(uint8_t SlaveAddress, uint8_t REG_Address, uint8_t *buf, uint16_t len)
{
    VL53_I2c_Start();
    VL_IIC_Send_Byte(SlaveAddress);//发写命令
    if(VL_IIC_Wait_Ack()) 
    {
        VL53_I2c_Stop();//释放总线
        return 1;//没应答则退出
    }
    VL_IIC_Send_Byte(REG_Address);
    VL_IIC_Wait_Ack();
    while(len--)
    {
        VL_IIC_Send_Byte(*buf++);
        VL_IIC_Wait_Ack();
    }
    VL53_I2c_Stop();

    return  0;
}
// 写一个字节
void VL53_I2c_WrByte(unsigned char dat)
{
    unsigned char i;
    VL53_SDA_D_OUT;   // 输出
    for(i=0;i!=8;i++)
    {
        if(dat&0x80) {VL53_SDA_SET;}
        else {VL53_SDA_CLR;}
        delayMicroseconds(1);;
        VL53_SCL_SET;
        dat<<=1;
        delayMicroseconds(2);
        VL53_SCL_CLR;
        delayMicroseconds(1);;
    }
    VL53_SDA_D_IN;  /*SDA输入方向 */
    VL53_SDA_SET;
    delayMicroseconds(1);
    VL53_SCL_SET;  // 等待应答
    delayMicroseconds(2);
    VL53_SCL_CLR;
    delayMicroseconds(1);
}

int initI2c()
{
    //初始化所用到的IO引脚
    //pinMode(BTN_INTERRUPT, INPUT);
    // INT_EDGE_FALLING:下降沿
    // INT_EDGE_RISING:上升沿
    // INT_EDGE_BOTH: 可上升沿也可以下降沿
    // INT_EDGE_SETUP:保持原有的GPIO初始方式
    //int wiringPiI2CSetup(int devId);
    //wiringPiISR(BTN_INTERRUPT, INT_EDGE_FALLING, &irqHandler);
    pinMode(PIN_SDA, OUTPUT);
    pinMode(PIN_SCL, OUTPUT);

    digitalWrite(PIN_SCL, HIGH);
    digitalWrite(PIN_SDA, HIGH);
    return 0;
}
uint16_t makeuint16(int lsb, int msb) {
    return ((msb & 0xFF) << 8) | (lsb & 0xFF);
}
int main()
{
    u8 data[10];
    u8 i=0;
    u8 beginData = 0;
    //初始化wiringPI的库函数
    if(wiringPiSetup()<0) {
        printf("init wiringPi error\n");
    }
    printf("init wiringPi over\n");
    initI2c();          //spi的初始化

    u8 val1;
    int ret;
      ret= VL_IIC_Read_1Byte(address,VL53L0X_REG_IDENTIFICATION_MODEL_ID,&val1);
   if(ret) printf("read failed \n");
    printf("Device ID: \n"); 
    printf("0x%x \n",val1);

    ret= VL_IIC_Read_1Byte(address,VL53L0X_REG_C1_ID,&val1);
   if(ret) printf("read failed \n");

   printf("C1 ID: \n"); 
   printf("0x%x \n",val1);  
    ret= VL_IIC_Read_1Byte(address,VL53L0X_REG_IDENTIFICATION_REVISION_ID,&val1);
   if(ret) printf("read failed \n");

   printf("Revision ID: \n"); 
   printf("0x%x \n",val1);   

    ret= VL_IIC_Read_1Byte(address,VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,&val1);
   if(ret) printf("read failed \n");
    printf("PRE_RANGE_CONFIG_VCSEL_PERIOD : \n"); 
    printf("%d \n",val1);
    ret= VL_IIC_Read_1Byte(address,VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,&val1);
    if(ret) printf("read failed \n");
    printf("FINAL_RANGE_CONFIG_VCSEL_PERIOD : \n"); 
    printf("%d \n",val1);
    while(1)
     {
        VL_IIC_Write_1Byte(address,0x80, 0x01);
        VL_IIC_Write_1Byte(address,0xFF, 0x01);
        VL_IIC_Write_1Byte(address,0x00, 0x00);
        //VL_IIC_Write_1Byte(address,0x91, stop_variable);
        VL_IIC_Write_1Byte(address,0x00, 0x01);
        VL_IIC_Write_1Byte(address,0xFF, 0x00);
        VL_IIC_Write_1Byte(address,0x80, 0x00);

        VL_IIC_Write_1Byte(address, VL53L0X_REG_SYSRANGE_START,0x01);
        int val = 0;
        int cnt = 0;
        while (cnt < 100) { // 1 second waiting time max
            delay(10);
                ret= VL_IIC_Read_1Byte(address,VL53L0X_REG_RESULT_RANGE_STATUS,&val1);
            if(ret) printf("read failed \n");        
            if (val1 & 0x01) break;
            cnt++;
        }
        //if (val1 & 0x01) printf("ready \n"); else printf("not ready \n");
        char gbuf[16];

        VL_I2C_Read_nByte(address, 0x14,gbuf, 12);
        uint16_t acnt = makeuint16(gbuf[7], gbuf[6]);
        uint16_t scnt = makeuint16(gbuf[9], gbuf[8]);
        uint16_t dist = makeuint16(gbuf[11], gbuf[10]);
        char DeviceRangeStatusInternal = ((gbuf[0] & 0x78) >> 3);

        //printf("ambient count: %d \n",acnt);
        //printf("signal count:  %d \n",scnt);
        if(dist>20 && dist< 1200)printf("distance  %d \n",dist);
       // printf("status: %d \n ",DeviceRangeStatusInternal);

  }

    return 0;
}

编译


gcc main.c -o main  -lwiringPi 


测试


orangepi@orangepizero2:~/vl53$ sudo ./main 
[sudo] password for orangepi: 
init wiringPi over
Device ID: 
0xee 
C1 ID: 
0xaa 
Revision ID: 
0x10 
PRE_RANGE_CONFIG_VCSEL_PERIOD : 
7 
FINAL_RANGE_CONFIG_VCSEL_PERIOD : 
5 
distance  306 
distance  313 
distance  308 
distance  290 
distance  302 
distance  277 
distance  270 
distance  267 
distance  266 
distance  274 
distance  297 
distance  290 
distance  304 
distance  305 
distance  280 
distance  277 
distance  278 
distance  298 
distance  293 
distance  297 
distance  276 
distance  291 
distance  272 
distance  284 
distance  284 
distance  321 
distance  282 
distance  296 
distance  304 
distance  307 
distance  280 
distance  293 
distance  340 
distance  252 
distance  260 
distance  299 
distance  290 
distance  322 
distance  305 
distance  284 
distance  237 
distance  368 
distance  289 
distance  368 
distance  248 
distance  309 
distance  289 


总结

实际测距中会出现最小值20mm和最大值8190 ,这两个值出现应该是错误的,目前采取直接滤掉。

位置放好后,在正常情况下测距还是较准确的,满足机器人的避障需求。

没有用到xshut ,仅连接4根线即可。vcc  gnd scl  sda .

完整代码

https://github.com/horo2016/vl53_wiringPI


sitemap