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