El módulo de acelerómetro de Intesc incluye un sensor MMA8452Q de 12 bits digital, el cual tiene diferentes funciones embebidas como la detección de orientación y la detección de pulsos.
Con esta librería se podrá hacer uso de algunas de las funciones principales del sensor.
Definición de pines
El primer paso es definir los pines donde estará conectado el sensor en nuestra tarjeta, para ello tendremos que editar el archivo MMA8452.h.
INT1_PIN: Pin donde estarán asociadas las interrupciones 1 de las diferentes funciones del sensor.
INT2_PIN: Pin donde estarán asociadas las interrupciones 2 de las diferentes funciones del sensor.
SCL_PIN: Pin de señal de reloj para comunicación I2C.
SDA_PIN: Pin de datos para comunicación I2C.
Definición de constantes
Será importante definir diferentes constantes dependiendo de las características con las que estemos trabajando.
DR_DEFAULT: Data Rate usado para las diferentes funciones embebidas. Este puede ser seleccionado entre:
- DR_800: Para 800 Hz
- DR_400: Para 400 Hz
- DR_200: Para 200 Hz
- DR_100: Para 100 Hz
- DR_50: Para 50 Hz
- DR_12_5: Para 12.5 Hz
- DR_6_25: Para 6.25 Hz
- DR_1_56: Para 1.56 Hz
En caso de utilizar la función de detección de pulsos, se tendrán que configurar los siguientes parámetros:
Rangos de valor de escala
- X_G
- Y_G
- Z_G
Conteo para cada registro, esto es para lograr los tiempos adeucados para los registros de Time Limit, Latency y Window, estos conteos dependen de el DR seleccionado, el modo de trabajo con el que estemos operando (Normal, Baja potencia, Alta resolución o Bajo ruido Baja energía) y el filtro pasa bajas. La información de cada modo se puede encontrar en la hoja de datos del sensor, en el capítulo 6.5.
Por ejemplo, utilizando los valores por default de la librería (ODR = 800HZ, Modo normal, Filtro pasa bajas desactivado). Encontraremos en la sección correspondiente de la hoja de datos la siguiente información para Time Limit:
Por lo tanto si queremos un tiempo de 60ms, tendremos [60ms] / [0.625ms] = 96
Para el caso de Latency y Window, tenemos la siguiente tabla:
Por lo tanto si quieremos un tiempo de 200ms, tendremos [200ms] / [1.25ms] = 160
Funciones
Las funciones declaradas en librería son las siguientes:
Inicialización
void MMA8452_init(int32 mask)
Esta debe ser la primer función utilizada para poder obtener información del sensor, inicializa el mismo configurando los registros de control.
Parámetros de entrada:
- int32 mask: Información para la configuración adecuada.
La variable mask contendrá toda la información necesaria para esta inicialización, los valores tendrán que estar separados por un “OR” ( | ) y estos pueden ser:
//Frecuencia de muestreo de Auto wake up cuando el dispositivo está dormido #define ASLP_RATE_50 0x00000000 // 50Hz #define ASLP_RATE_12_5 0x00000040 // 12.5 Hz #define ASLP_RATE_6_25 0x00000080 // 6.25 Hz #define ASLP_RATE_1_56 0x000000C0 // 1.56 Hz //Seleccion de data rate #define DR_800 0x00000000 // 800 Hz #define DR_400 0x00000008 // 400 Hz #define DR_200 0x00000010 // 200 Hz #define DR_100 0x00000018 // 100 Hz #define DR_50 0x00000020 // 50 Hz #define DR_12_5 0x00000028 // 12.5 Hz #define DR_6_25 0x00000030 // 6.25 Hz #define DR_1_56 0x00000038 // 1.56 Hz #define NOISE_NORMAL 0x00000000 // Ruido normal #define NOISE_RED 0x00000004 // Ruido reducido #define NO_FAST_READ 0x00000000 // Modo normal #define FAST_READ 0x00000002 // Modo de lectura rápida //Power mode #define NORMAL_MODE 0x00000000 // Normal #define LOW_NOISEPOWER 0x00000100 // Bajo ruido baja energía #define HIGH_RES 0x00000200 // Alta resolución #define LOW_POWER 0x00000300 // Baja potencia #define NO_AUTOSLEEP 0x00000000 // Autosleep no habilitado #define AUTOSLEEP 0x00000400 // Autosleep habilitado #define SW_RST 0x00000800 // Reset por software habilitado #define NO_SWR 0x00000000 // Reset por software no habilitado #define SELFTEST 0x00001000 // Self test habilitado #define NO_SELFTEST 0x00000000 // Self test deshabilitado #define PUSH_PULL 0x00000000 // Push pull #define OPEN_DRAIN 0x00002000 // Open drain //Polaridad en la señal de interrupción #define IPOL_LOW 0x00000000 // Activa bajo #define IPOL_HIGH 0x00004000 // Activa alto //Funciones que pueden despertar al sistema o no en modo DORMIDO #define WAKE_FFMT 0x00008000 // Caída libre / Movimiento #define WAKE_FFMT_OFF 0x00000000 // Caída libre / Movimiento apagado #define WAKE_PULSE 0x00010000 // Pulso #define WAKE_PULSE_OFF 0x00000000 // Pulso apagado #define WAKE_LNDPRT 0x00020000 // Paisaje / Portaretrato #define WAKE_LNDPRT_OFF 0x00000000 // Paisaje / Portaretrato apagado #define WAKE_TRANS 0x00080000 // Transient #define WAKE_TRANS_OFF 0x00000000 // Transient apagado #define INT1_DATAREADY 0x04100000 // Interrupción de DATOS LISTOS conectada a INT1 #define INT2_DATAREADY 0x00100000 // Interrupción de DATOS LISTOS conectada a INT2 #define INT1_FFMT 0x08200000 // Interrupción de Caída libre / Movimiento conectada a INT1 #define INT2_FFMT 0x00200000 // Interrupción de Caída libre / Movimiento conectada a INT2 #define INT1_PULSE 0x10400000 // Interrupción de pulso conectada a INT1 #define INT2_PULSE 0x00400000 // Interrupción de pulso conectada a INT1 #define INT1_LNDPRT 0x20800000 // Interrupción de Paisaje / Portaretrato conectada a INT1 #define INT2_LNDPRT 0x00800000 // Interrupción de Paisaje / Portaretrato conectada a INT2 #define INT1_TRANS 0x41000000 // Interrupción de Transient conectada a INT1 #define INT2_TRANS 0x01000000 // Interrupción de Transient conectada a INT2 #define INT1_ASLP 0x82000000 // Interrupción Auto dormir/despertar conectada a INT1 #define INT2_ASLP 0x02000000 // Interrupción Auto dormir/despertar conectada a INT2
Los valores por defecto son los siguientes:
- ASLP Rate: 50 Hz
- ODR: 800 Hz
- Ruido: Normal
- Lectura rápida desactivada
- Modo Normal
- Sin Autosleep
- Sin reset por software
- Auto prueba deshabilitada
- Push Pull
- Polaridad de las interrupciones en bajo
- Sin interrupciones
Parámetros de salida:
- Sin parámetros
Ejemplo de uso:
MMA8452_init(IPOL_HIGH|INT1_DATAREADY|INT2_LNDPRT|INT2_PULSE); //Polaridad de las interrupciones en alto //Interrupciones por datos listos en INT1 //Interrupciones por cambio de orientación (Landscape/Portrait) en INT2 //Interrupciones por pulso en INT2
Registros
Existe una función para leer y otra para escribir en los registros del sensor directamente, esto se puede utilizar en caso de que se requiera alguna configuración diferente a la de la librería, entonces podrás escribir mediante I2C en cualquier registro del sensor.
void writeReg(unsigned int reg, unsigned int data)
Escribe información en un registro.
Parámetros de entrada:
- unsigned int reg: Registro en el que se escribe
- unsigned int data: Información que se escribe en el registro indicado
Parámetros de salida
- Sin parámetros
Ejemplo de uso:
// Colocar en modo standby temp = readReg(0x2A); //Almaceno el valor del registro de control 1 writeReg(0x2A, temp & 0xFE); //Descativo el bit 0 del registro de control 1
int readReg(unsigned int reg)
Lee información de un registro.
Parámetros de entrada:
- int reg: Registro que se va a leer
Parámetros de salida:
- int: Valor del registro leído
Ejemplo de uso:
readReg(0x01); //Leo la parte más significativo del Eje X
¿Conectado?
Con esta función podremos saber si el sensor se encuentra conectado y se pudo establecer comunicación entre él y nuestra tarjeta, o si por otro lado, está desconectado o no fue posible realizar esta comunicación.
int MMA8452_is_connected()
Lee la información del registro Who Am I, y la compara con la información que se tendría que haber recibido.
Parámetros de entrada:
- Sin parámetros
Parámetros de salida:
- int: Información sobre el estado del sensor, esta puede ser:
- MMA8452_CONNECTED = 1
- MMA8452_NOT_CONNECTED = 0
Ejemplo de uso:
if (MMA8452_is_connected() == MMA8452_CONNECTED){ printf(lcd_putc, "\fCONNECTED"); } else{ printf(lcd_putc, "\fNOT CONNECTED); }
EJE X / EJE-Y / EJE-Z
Podremos configurar cada uno de los ejes así como obtener la información del valor de la posición de cada uno.
void MMA8452_xyz_conf(int mask)
Con esta función se configura el rango de escala y el filtro pasa altas.
Parámetros de entrada:
- int mask: Información necesaria para la configuración.
La variable mask contendrá toda la información necesaria para esta inicialización, los valores tendrán que estar separados por un “OR” ( | ) y estos pueden ser:
#define HIGH_PASS_ON 0b00010000 //Activar pasa altas en datos de salida #define HIGH_PASS_OFF 0b00000000 //Filtrar los datos de salida //Rangos de valores de escala #define SET_2G 0b00000000 //2g #define SET_4G 0b00000001 //4g #define SET_8G 0b00000010 //8g
Los valores por defecto son:
- Filtro passa altas desactivado
- Seleccionado 2G
Parámetros de salida:
- Sin parámetros
Ejemplo de uso:
MMA8452_xyz_conf(HIGH_PASS_OFF|SET_4G); //Activa el filtro pasa altas //Selecciona 4g
signed long int MMA8452_x_read()
signed long int MMA8452_y_read()
signed long int MMA8452_z_read()
Recibe la información del valor de cada posición de los ejes.
Parámetros de entrada:
- Sin parámetros
Parámetros de salida:
- signed long int: Valor del eje correspondiente
Ejemplo de uso:
ejex = MMA8452_x_read(); // Leemos el eje X ejey = MMA8452_y_read(); // Leemos el eje Y ejez = MMA8452_z_read(); // Leemos el eje Z printf(lcd_putc, "\fX=%4ld", ejex); lcd_gotoxy(1,2); printf(lcd_putc, "Y=%4ld Z=%4ld", ejey,ejez);
Orientación
Con estas funciones podremos obtener información de la orientación del sensor, esta puede ser en modo portaretrato o en modo paisaje, así como saber si está boca arriba o boca abajo.
void MMA8452_enPortLand()
Esta función debe ser utilizada para activar la detección de orientación.
Parámetros de entrada:
- Sin parámetros
Parámetros de salida:
- Sin parámetros
Ejemplo de uso:
MMA8452_enPortLand(); //Activa detección de orientación
int MMA8452_newOrientation()
Esta función nos hará saber si la orientación cambió o se ha mantenido igual.
Parámetros de entrada:
- Sin parámetros
Parámetros de salida:
- int: Información sobre si cambió o no:
- MMA8452_ORIEN_CHANGED = 1
- MMA8452_ORIEN_NOT_CHANGED = 0
Ejemplo de uso:
if (MMA8452_newOrientation() == MMA8452_ORIEN_CHANGED){ printf(lcd_putc, "New Orientation"); } else{ printf(lcd_putc, "No New Orient"); }
int MMA8452_LaPo()
Nos indica la orientación actual.
Parámetros de entrada:
- Sin parámetros
Parámetros de salida:
- int: Devuelve información de la orientación.
- MMA8452_PORTRAIT_UP = 0
- MMA8452_PORTRAIT_DOWN = 1
- MMA8452_LANDSCAPE_RIGHT = 2
- MMA8452_LANDSCAPE_LEFT = 3
Ejemplo de uso:
lapo = MMA8452_LaPo(); // ¿Portland o Landscape? if (lapo == MMA8452_PORTRAIT_UP){ printf(lcd_putc, "\fPortrait Up"); } else if (lapo == MMA8452_PORTRAIT_DOWN){ printf(lcd_putc, "\fPortrait Down"); } else if (lapo == MMA8452_LANDSCAPE_RIGHT){ printf(lcd_putc, "\fLandscape Right"); } else{ printf(lcd_putc, "\fLandscape Left"); }
int MMA8452_BaFro()
Nos indica la orientación entre arriba o abajo.
Parámetros de entrada:
- Sin parámetros
Parámetros de salida:
- int: Información de la orientación.
- MMA8452_FRONT_FACE = 0
- MMA8452_BACK_FACE = 1
Ejemplo de uso:
bafro = MMA8452_BaFro(); // ¿Back o Front? if (bafro == MMA8452_FRONT_FACE){ printf(lcd_putc, "\nFront"); } else{ printf(lcd_putc, "\nBack"); }
Detección de pulsos
Podremos saber si nuestro sensor ha detectado un pulso sencillo o un pulso doble. Es importante ajustar los valores de los conteos en la sección de constantes para hacer que coincidan con la configuración de la tarjeta.
void MMA8452_enTapDet(int mask)
Es necesario habilitar primero la detección de los pulsos e indicar la configuración de la misma.
Parámetros de entrada:
- int mask: Información de la configuración.
La variable mask contendrá toda la información necesaria para esta inicialización, puede ser:
//Detección de pulso #define SINGLE_TAP 0b00000000 //Detección sencilla activada #define DOUBLE_TAP 0b00000001 //Detección doble activada #define SINGLE_DOUBLE 0b00000010 //Detección sencilla y doble activada
Parámetros de salida:
- Sin parámetros
Ejemplo de uso:
MMA8452_enTapDet(SINGLE_DOUBLE); //Habilitamos la detección de pulsos
int MMA8452_getTap()
Nos dará información de el tipo de pulso recibido.
Parámetros de entrada:
- Sin parámetros
Parámetros de salida:
- int: Información sobre el pulso recibido.
- MMA8452_NO_PULSE = 0
- MMA8452_DOUBLE_PULSE = 1
- MMA8452_SINGLE_PULSE = 2
Ejemplo de uso:
pulso = MMA8452_getTap(); // Verificamos si fue sencillo o doble if (pulso == MMA8452_DOUBLE_PULSE){ // Si fue doble output_toggle(PIN_E2); // Encendemos un led } else if (pulso == MMA8452_SINGLE_PULSE){ // Si fue sencillo output_toggle(PIN_E1); // Encendemos un led }
Código de ejemplo
El siguiente código hace uso de la librería del sensor para leer la información de los 3 ejex y mostrarla en una LCD, al presionar el pulsador ubicado en el pin C0 se cambiará la información de la LCD por la información de la orientación del sensor. Y alternaremos el valor de dos leds cada que se reciban pulsaciones pudiendo ser sencillas par aun led o dobles para el otro.
#include<18f4550.h> #fuses HSPLL, NOWDT, NOPROTECT, NOLVP, NODEBUG, USBDIV, PLL2, CPUDIV1, VREGEN #use delay (clock=48M) #include <MLCD.c> #include "MMA8452Q.c" #use standard_io(e) #use standard_io(c) void main(){ //Definición de variables signed long int ejex = 0, ejey = 0, ejez = 0; int lapo = 0, bafro = 0; int pulso = 0; int pantalla = 0; set_tris_c(0xFF); //Habilitamos el puerto C como entrada set_tris_e(0x00); //Habilitamos el puerto E como salida output_e(0x07); //Apagamos el led RGB lcd_init(); //Inicializamos la LCD MMA8452_init(IPOL_HIGH|INT1_DATAREADY|INT2_LNDPRT|INT2_PULSE); //Inicializamos el sensor MMA8452_enPortLand(); // Habilitamos la detección de orientación MMA8452_enTapDet(SINGLE_DOUBLE); //Habilitamos la detección de pulsos while(TRUE){ //Detección de pulsador para modificar la información de la pantalla if (input_state(PIN_C0)){ // ¿Se presionó el pulsador? delay_ms(200); pantalla++; // Aumentamos el valor de pantalla if (pantalla >= 2){ // Si pantalla es mayor o igual a 2 pantalla = 0; // la reiniciamos a 0 } } //LECTURA DE LOS 3 EJES if (input_state(INT1_PIN)){ // ¿Hubo interrupción del PIN 1 del sensor? ejex = MMA8452_x_read(); // Leemos el eje X ejey = MMA8452_y_read(); // Leemos el eje Y ejez = MMA8452_z_read(); // Leemos el eje Z } // TAP DETECTION if (input_state(INT2_PIN)){ // ¿Hubo interrupción del PIN 2 del sensor? pulso = MMA8452_getTap(); // Verificamos si fue sencillo o doble if (pulso == MMA8452_DOUBLE_PULSE){ // Si fue doble output_toggle(PIN_E2); // Encendemos el led AZUL } else if (pulso == MMA8452_SINGLE_PULSE){ // Si fue sencillo output_toggle(PIN_E1); // Encendemos el led ROJO } } // LECTURA DE LA ORIENTACION if (input_state(INT2_PIN)){ // ¿Hubo interrupción del PIN 2 del sensor? lapo = MMA8452_LaPo(); // ¿Portland o Landscape? bafro = MMA8452_BaFro(); // ¿Back o Front? } // MOSTRAMOS LA INFORMACIÓN EN LA LCD if (pantalla == 0){ printf(lcd_putc, "\fX=%4ld", ejex); lcd_gotoxy(1,2); printf(lcd_putc, "Y=%4ld Z=%4ld", ejey,ejez); delay_ms(200); } else{ if (lapo == MMA8452_PORTRAIT_UP){ printf(lcd_putc, "\fPortrait Up"); } else if (lapo == MMA8452_PORTRAIT_DOWN){ printf(lcd_putc, "\fPortrait Down"); } else if (lapo == MMA8452_LANDSCAPE_RIGHT){ printf(lcd_putc, "\fLandscape Right"); } else{ printf(lcd_putc, "\fLandscape Left"); } if (bafro == MMA8452_FRONT_FACE){ printf(lcd_putc, "\nFront"); } else{ printf(lcd_putc, "\nBack"); } delay_ms(200); } } }