miércoles, 22 de marzo de 2017

Tutorial ZYBO-Linux (VI): Ejemplo de I2C con el sensor luminosidad TSL2561 de Adrafruit

 Esta es una continuación de la serie de tutoriales para ZYBO usando Linux.

En este ejemplo se muestra como leer un sensor I2C conectado a ZYBO (de Digilent) desde Linux. El sensor es en este caso el sensor de luminosidad TSL2561de Adrafruit.
Sensor de luminosidad I2C TSL2561

Los detalles de uso de este sensor se pueden leer en el datasheet, aunque resumiendo se han de seguir los siguientes pasos:

  1. Mandar comando de encender 0x80, 0x03
  2. Configurar el tiempo de integración a 13.7ms 0x81, 0x00
  3. Mandar los comandos de lectura para ambos canales. ch0 (0x8c,0x8d) y ch1(0x8d,0x8f)
  4. Convertir a Lux usando la función dada en el datasheet.
Los pines para el I2C son los del PS i2c0: JF1 scl, sca JF2

Una vez conectada la ZYBO por el terminal (ver tutorial (III)) únicamente tendremos que cambiar el software. Para esto abrimos un nuevo archivo de texto e introducimos el siguiente código:


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include "lux-calculation.c"

/* TODO addapt the i2c slave address to your sensor */
#define I2C_ADDRESS 0x39

/* TODO driver path to the i2c */
static char *i2c = "/dev/i2c-0";
static int i2c_handler;

int i2c_write(int file, char *buf, size_t len)
{
    if (write(file, buf, len) < 0) {
        /* ERROR HANDLING: i2c transaction failed */
        printf("Failed to write from the i2c bus: %s\n", strerror(errno));
        return errno;
    } else {
        return 0;
    }
}

int i2c_read(int file, char *buf, size_t len)
{
    if (read(file,buf,len) < 0) {
        /* ERROR HANDLING: i2c transaction failed */
        printf("Failed to read from the i2c bus: %s\n", strerror(errno));
        return errno;
    } else {
        return 0;
    }
}

double ReadTCusingADC(void)
{
 unsigned char NullCmd = 0x00;
 double ADCoutput = 0;
    char buffer[7] = "";

     
   

    char read_channel[] = {0x8c, 0x8d};
    i2c_write(i2c_handler, read_channel, 2);
    memset(buffer, sizeof(buffer), '\0');
    usleep(2000);

    if (i2c_read(i2c_handler, buffer, 3) < 0) {
        /* ERROR HANDLING: you can check errno to see what went wrong */
        perror("Failed to read");
        exit(1);
    }

 int Ch0 = buffer[0] + 0xFF*buffer[1];
 //printf ("channel0 %d   ", Ch0); //For debugging


 i2c_write(i2c_handler, power_sequence, 2);

    char read_channel2[] = {0x8e, 0x8f};
    i2c_write(i2c_handler, read_channel2, 2);
    memset(buffer, sizeof(buffer), '\0');
    usleep(2000);

    if (i2c_read(i2c_handler, buffer, 3) < 0) {
        /* ERROR HANDLING: you can check errno to see what went wrong */
        perror("Failed to read");
        exit(1);
    }

 int Ch1 = buffer[0] + 0xFF*buffer[1];
   //printf("channel0 %d \n",Ch1); //For debugging

 ADCoutput = CalculateLux(0, 0,Ch0, Ch1, 0 );

 return ADCoutput;
}


int sensor_powerOn(){
 char power_sequence[] = {0x80, 0x03};
 i2c_write(i2c_handler, power_sequence, 2);
 char time_sequence[] = {0x81, 0x00};
 i2c_write(i2c_handler, time_sequence, 2);
 
return 0;
}

int main (void)
{
    /* open device on /dev/i2c-x */
    i2c_handler = open(i2c, O_RDWR);

    if ((i2c_handler = open(i2c, O_RDWR)) < 0) {
        /* ERROR HANDLING: you can check errno to see what went wrong */
        perror("Failed to open the i2c bus");
        exit(1);
    }
    
if (ioctl(i2c_handler, I2C_SLAVE, I2C_ADDRESS) < 0) {
        printf("Failed to acquire bus access and/or talk to slave.\n");
        /* ERROR HANDLING; you can check errno to see what went wrong */
        exit(1);
    }
sensor_powerOn();
printf("sensor_init\n");
 /* TODO: addapt the ReadTCusingADC function to the Lux sensor */
    int i;
    double result;
 
    for (i = 0; i < 150; i++) {
        result = ReadTCusingADC();
        printf("%f\n", result);
        sleep(1);
    }

    /* close connection and return */
    close(i2c_handler);
    return 0;
} 
Para compilar este código se necesita el archivo lux-calculation.c dado por el fabricante en el datasheet, que puede descargarse aquí

No hay comentarios:

Publicar un comentario