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