Envío Gratis en compras mínimas de $1200 mxn Enviamos a toda la Republica Mexicana
Buscar

Práctica 9 con Miuva. Mod ACEL: Acelerómetro I2C con PIC C

En esta práctica aprenderemos a utilizar el protocolo I2C para obtener información de un acelerómetro y encender los leds de la barra de leds correspondientes a la inclinación del mismo.

Para usar este protocolo es necesario que definamos lo siguiente:

#use I2C(MASTER, SCL=PIN_A1, SDA=PIN_A2)  //Configuración del I2C

En la parte de configuración tenemos que definir en que pines estará conectado nuestro dispositivo, en este caso el pin SCL está en el pin A1 y el pin SDA en el A2.

Para poder comunicarnos con los dispositivos I2C haremos uso de las siguientes funciones:

i2c_start();       //Envía la condición de inicio
i2c_write(0x3A);   //Envía información
y = i2c_read(0);   //Recibe información y la almacena en y
i2c_stop();        //Envía la condición de paro

Los pasos necesarios para establecer comunicación por medio de este protocolo son los siguientes:

Envío de información

1. Enviar condición de inicio

2. Enviar dirección esclava de escritura

3. Enviar registro al que se va a escribir

4. Enviar el dato que se va a escribir

5. Enviar condición de paro

i2c_start();
i2c_write(DIR_ESCLAVO_W);
i2c_write(registro);
i2c_write(dato);
i2c_stop();

Recepción de información

1. Enviar condición de incio

2. Enviar dirección esclava de escritura

3. Registro que se va a leer

4. Condición de inicio

5. Enviar dirección esclava de lectura

6. Recibe información del registro

7. Condición de paro

i2c_start();
i2c_write(DIR_ESCLAVO_W);
i2c_write(registro);
i2c_start();
i2c_write(DIR_ESCLAVO_R);
y = i2c_read(0);
i2c_stop();

Es conveniente que definamos una función para escritura que realice todo el proceso para no repetir tantas líneas y lo mismo para la lectura. Quedando de la siguiente forma:

void escritura(unsigned int registro, unsigned int dato){
   i2c_start();
   i2c_write(DIR_ESCLAVO_W);
   i2c_write(registro);
   i2c_write(dato);
   i2c_stop();
}
int lectura(unsigned int registro){
   int y;
   i2c_start();
   i2c_write(DIR_ESCLAVO_W);
   i2c_write(registro);
   i2c_start();
   i2c_write(DIR_ESCLAVO_R);
   y = i2c_read(0);
   i2c_stop();
   return y;
}

De esta forma podremos crear otra función que sirva para inicializar el módulo del acelerómetro, enviando la información correspondiente a cada registro del mismo, de la siguiente forma:

void acel_init(){
//Inicialización del módulo del acelerómetro
   escritura_acel(0x0B, 0x01); 
   escritura_acel(0x2A, 0x20);
   escritura_acel(0x2B, 0x19);
   escritura_acel(0x2C, 0x02);
   escritura_acel(0x2D, 0x01);
   escritura_acel(0x2E, 0x01);
   escritura_acel(0x2A, 0x21);
}

En el datasheet del acelerómetro podemos encontrar por que se pusieron esos valores en los registros.

Para esta práctica vamos a estar leyendo continuamente el registro 0x03 el cual contiene el valor del eje y del acelerómetro, después de leer ese registro lo compararemos con valores entre -20 y 20 para definir cual led se tendrá que encender, según la siguiente imagen:

Imagen 1. Intervalos de encendido de cada led

De esta forma podemos crear el siguiente código:

Código para PIC C:

#include<18f4550.h>
#fuses HSPLL, NOWDT, NOPROTECT, NOLVP, NODEBUG, USBDIV, PLL2, CPUDIV1, VREGEN
#use delay (clock=48M)
#use standard_io(b)
#use standard_io(c)
#use I2C(MASTER, SCL=PIN_A1, SDA=PIN_A2)  //Configuración del I2C
signed int eje_y = 0;
//Prototipo de funciones para iniciar, escribir y leer en el 
//Mod-Acel
void acel_init();
void escritura_acel(unsigned int registro, unsigned int dato);
int leer_y();
void main(){
   set_tris_b(0b00000000); //Configurar como salidas
   acel_init();            //Inicializar acelerómetro
   while(TRUE){
      if (input_state(PIN_A0)){
         eje_y = leer_y();    //Leer el valor del eje y
                              //Comparar los valores obtenidos del registro para
                              //encender los leds correspondientes a la 
                              //inclinación del acelerómetro
         if (eje_y < -20){
            output_b(0x01);
         }
         else if (eje_y < -15){
            output_b(0x02);
         }
         else if(eje_y < -10){
            output_b(0x04);
         }
         else if (eje_y < -5){   
         output_b(0x08);
         }
         else if (eje_y > 20){
            output_b(0x80);
         }
         else if (eje_y > 15){
            output_b(0x40);
         }
         else if (eje_y > 10){
            output_b(0x20);
         }
         else if (eje_y > 5){
            output_b(0x10);
         }
      }
         else{
            output_b(0xAA);
      }
   }
}
void acel_init(){
//Inicialización del módulo del acelerómetro
   escritura_acel(0x0B, 0x01); 
   escritura_acel(0x2A, 0x20);
   escritura_acel(0x2B, 0x19);
   escritura_acel(0x2C, 0x02);
   escritura_acel(0x2D, 0x01);
   escritura_acel(0x2E, 0x01);
   escritura_acel(0x2A, 0x21);
}
void escritura_acel(unsigned int registro, unsigned int dato){
   i2c_start();
   i2c_write(0x3A);
   i2c_write(registro);
   i2c_write(dato);
   i2c_stop();
}
int leer_y(){
   int y;
   i2c_start();
   i2c_write(0x3A);
   i2c_write(0x03);  //Registro del eje y del acelerómetro
   i2c_start();
   i2c_write(0x3B);
   y = i2c_read(0);
   i2c_stop();
   return y;
}

Conexiones

Observa el video demostrativo