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

8. Lectura del sensor MPU6050 (Acelerómetro y Giroscopio)

Bienvenidos al octavo tutorial para aprender a manejar los recursos básicos de nuestra tarjeta de desarrollo Ophyra. En este segmento aprenderemos a configurar la tarjeta para leer el sensor MPU6050. Este sensor es un Acelerómetro y Giroscopio integrado con comunicación I2C.

Proyecto a realizar: Se leerán los datos que entrega el sensor y los enviaremos hacia el puerto RS232 para visualizarlos en la terminal del compilador.

 

Configurando el Hardware

Una vez ya creado nuestro proyecto (véase el tutorial preliminar de Crear un Proyecto para Ophyra), el siguiente paso es activar los recursos a utilizar.

Paso 1. Ya que necesitamos utilizar la comunicación RS232 para desplegar la información proveniente del snesor MPU6050, necesitamos activar nuestro USART. Para activarlo, se hará lo mismo que en el tutorial pasado (7. Comunicación RS232):

  • Activar el USART3 en modo asíncrono
  • Configurar los parámetros del USART3 (el baudaje, largo de palabra, etc).
  • Verificar que los pines activados sean el PB10 (USART3_TX) y PB11 (USART3_RX)
Imagen 1. Parámetros de configuración del USART3.

 

Paso 2. Ahora debemos habilitar nuestro puerto I2C para establecer la comunicación con el sensor MPU6050. Al referirnos al Manual de Ophyra en la sección “10. Bus de datos I2C”, podremos observar que el sensor está conectado en el primer puerto del I2c y utiliza los pines PB6, PB7 y PB8 para la comunicación. En las secciones de la izquierda, entonces entraremos a Connectivity → I2C1 y en el modo de activación seleccionaremos I2C.

Imagen 2. Activación del I2C1.

 

Una vez activo podemos verificar que nuestros pines a utilizar sean los correctos (PB7 para el canal SDA y PB6 par el canal SCL).

Imagen 3. Pines activos para el I2C.

 


Nota

En nuestro puerto I2C1 también está conectado un dispositivo adicional (una memoria EEPROM). Ambos dispositivos tienen configurados por hardware sus ID o dirección de identificación esclavo. En el Manual de Ophyra, en la sección “10. Bus de datos I2C”, se establecen la dirección “0x68” para el sensor MPU6050 y la dirección “0x50” para la memoria EEPROM

En el protocolo I2C, la ID siempre se envía al inicio de una comunicación entre dispositivos maestro-esclavo. Mediante estas direcciones se controla con cuál dispositivo esclavo se comunica el dispositivo maestro. Cuando un dispositivo esclavo reconoce su ID, este responde al dispositivo maestro mediante una señal de reconocimiento (acknowledgement en inglés). En ese momento, se habrá entablado una comunicación entre ambos dispositivos.

Si desearamos utilizar otro dispositivo con protocolo I2C, no nos será posible utilizar el bus I2C1, ya que no se encuentra mapeado hacia algún pin físico de los puertos de expansión CN1, CN2 o CN3; sin embargo el microcontrolador de Ophyra tiene otros dos puertos adicionales para habilitar (I2C2 o el I2C3). Recomendamos revisar el manual en la sección “18. Puertos de Expansión” para identificar los pines que se tienen disponibles para un puerto adicional I2C.


 

Paso 3. Ahora pasaremos a la configuración de nuestro I2C. Los parámetros de configuración se muestran a continuación:

Imagen 4. Parámetros de configuración del I2C.

 

Los únicos parámetros que se harán mención en este tutorial son:

  • I2C Speed Mode: Indica el módo de velocidad de comunicación (El microcontrolador de Ophyra soporta el modo estándar y rápido).
  • I2C Clock Speed (Hz): Se establece la frecuencia de comunicación. El valor típido en el modo estándar es 100KHz.

 

Paso 4. Ahora es momento de generar nuestro código.


ADVERTENCIA

Si durante la creación de tu proyecto no llegaste a configurar el reloj de la tarjeta o a configurar los detalles del proyecto respecto a la generación del código, aún estás a tiempo.

Para sabér cómo hacer esas configuraciones, dirígase al tutorial preliminar de Crear un Proyecto para Ophyra y siga los pasos en Anexo 1: Configurar el reloj de la OphyraAnexo 2: Configurar los detalles el proyecto.


 

Para generar el código, basta con hacer clic en el botón de Guardar que se encuentra en la barra de herramientas en la parte superior. La interfaz cambiará y comenzará a cargar el código, así como se muestra en la siguiente imagen.

Imagen 5. Generando código.

 

Realizando el programa

Paso 6. Ya que volveremos a utilizar la comunicación RS232 y manejaremos cadenas de caracteres, necesitamos volver a incluir nuestras librerías.

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
/* USER CODE END Includes */

 

Paso 7. Para no tener que estar escribiendo la dirección de nuestro sensor MPU6050, le haremos una definición, tal como se muestra a continuación:

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define MPU6050_AD 0x68 << 1
/* USER CODE END PD */

Se le ha escrito la dirección como 0x68 << 1 pues se necesita recorrer un bit a la izquierda (pasando de 0x68 pasa a 0xD0). Esto es necesario debido a que en el protocolo I2C, el bit menos significativo del ID se utiliza como un comando de escritura y lectura. Este bit es manipulado por el dispositivo maestro, poniéndolo en 1 cuando se desea leer información y en 0 cuando se desea escribir en el dispositivo esclavo. Cabe notar que esta gestión se realiza de manera automática por las instrucciones en C que comanda el compotamiento del puerto I2C.

 

Paso 8. Declaramos nuestras variables a utilizar

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART3_UART_Init();
/* USER CODE BEGIN 2 */
uint8_t DatoRecibido[15];
uint8_t DatoEnviado[2];
char bufer[100];
float Ax, Ay, Az, Gx, Gy, Gz, T;
/* USER CODE END 2 */

 

Paso 9. En la sección previa al while, realizaremos la inicialización de nuestro sensor MPU6050. Para ello escribiremos lo siguiente:

/* Infinite loop */
/* USER CODE BEGIN WHILE */
DatoEnviado[0] = 0x6B;
DatoEnviado[1] = 0x00;
HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)MPU6050_AD, DatoEnviado, 2, 100);

DatoEnviado[0] = 0x19;
DatoEnviado[1] = 0x07;
HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)MPU6050_AD, DatoEnviado, 2, 100);

while (1)
{

Esta parte de código está dividido en dos partes muy parecidas. Al inicio de cada parte se le asignan valores en hexadecimales a los dos campos del arreglo DatoEnviado. El primero de ellos (aquel con índice 0) corresponde a la dirección del registro de configuración del sensor. El segundo dato corresponde al dato a escribir en el sensor. Finalmente, se realiza una transmisión de los datos hacia el sensor. Para ello se utiliza la función:

HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)

Como se puede observar, la instrucción cuenta con cinco parámetros:

  1. Puntero al puerto I2C con el que se trabajará.
  2. Se indica la ID o dirección del dispositivo esclavo.
  3. Búfer o arreglo de datos a enviar al dispositivo esclavo.
  4. Cantidad de datos a enviar.
  5. Tiempo de espera máximo (en milisegundos).

 

 

Ya teniendo en mente cómo funciona el código se explicará el por qué de esos números en hexadecimal:

Según la hoja de especificaciones del snesor, cuando al registro 0x6B se le escribe un 0, el sensor sale del estado Standby o estado de espera y comienza a realizar las mediciones de aceleración y rotación. Así mismo, al registro 0x19 se le escribe el dato 0x07 para configurar la frecuencia de muestreo del snesor a 1KHz.

 

Paso 10. Ahora escribiremos el código dentro de nuestro bucle infinito. Esa sección de código en general lee los datos provenientes del acelerómetro, giroscopio y temperatura y los envía al puerto USB-Serial para su visualización en cualquier terminal serial. Para este proyecto, volveremos a utilizar la terminal serial incluida en el STM32Cube IDE.

while (1)
{
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
    DatoEnviado[0] = 0x3B;   // Registo del Acelerómetro X
    DatoEnviado[1] = 0x00;
    HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)MPU6050_AD, &DatoEnviado[0], 1, 100);

    HAL_I2C_Master_Receive(&hi2c1, (uint16_t)MPU6050_AD, DatoRecibido, 14, 100);

    Ax = (float)(((int16_t)(DatoRecibido[0] << 8 | DatoRecibido[1])) / (float)16384);
    Ay = (float)(((int16_t)(DatoRecibido[2] << 8 | DatoRecibido[3])) / (float)16384);
    Az = (float)(((int16_t)(DatoRecibido[4] << 8 | DatoRecibido[5])) / (float)16384);
     T = (float)(((int16_t)(DatoRecibido[6] << 8 | DatoRecibido[7])) / (float)340 + (float)36.53);
    Gx = (float)(((int16_t)(DatoRecibido[8] << 8 | DatoRecibido[9])) / (float)131);
    Gy = (float)(((int16_t)(DatoRecibido[10] << 8 | DatoRecibido[11])) / (float)131);
    Gz = (float)(((int16_t)(DatoRecibido[12] << 8 | DatoRecibido[13])) / (float)131);

    sprintf(bufer, "Ax=%3.2f  Ay=%.2f  Az=%.2f  Gx=%.2f  Gy=%.2f  Gz=%.2f  T=%.2f\n\r", Ax, Ay, Az, Gx, Gy, Gz, T);
    HAL_UART_Transmit(&huart3, (uint8_t*)bufer, (uint16_t)strlen(bufer), (uint32_t)100);
    HAL_Delay(100);
}
/* USER CODE END 3 */

 

Así como en el paso anterior, separamos el código en secciones separadas por un renglón vacío, para poder explicar cada sección.

La sección 1 envía un dato “0x3B” al sensor. Esto hace que el snesor posicione su puntero en el registro 0x3B. Este registro corresponde al byte más significativo del eje X del acelerómetro. La hoja de datos del sensor especifica que todas las lecutras realizadas por el sensor las guarda en registros apilados en su memoria interna. Además cada lectura es de 16 bits de longitud, de esta forma utiliza dos bytres por cada eje sensado. Por lo tanto, se tienen 6 bytes para los datos del Acelerómetro (2 bytes por cada eje cartesiano: X, Y, Z), 6 bytes para los datos del Giroscopio y 2 bytes para los datos del sensor de temperatura. En total son 14 bytes los que se tienen que leer para obtener la información completa del sensor.

La sección 2 lee los 14 bytes de información mediante la función:

HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)

Como se puede observar, la instrucción cuenta con cinco parámetros:

  1. Puntero al puerto I2C con el que se trabajará.
  2. Se indica la ID o dirección del dispositivo esclavo.
  3. Búfer o arreglo de datos donde se guarda la información proveniente del dispositivo esclavo..
  4. Cantidad de datos a recibir.
  5. Tiempo de espera máximo (en milisegundos).

 

La sección 3 se encarga de ensamblar los datos en palabras de 32 bits flotantes. Lo primero que realiza es una concatenación a 16 bits del byte más significativo con el byte menos significativo de cada uno de los 7 parámetros. Seguidamente divide cada concatenación por un factor de sensibilidad o conversión, según como lo especifica la hoja de datos del sensor.

La sección 4 se encarga de enviar los datos obtenidos hacia el puerto USB-Serial de Ophyra, para su despliegue en la terminal serial.


ADVERTENCIA

Al haber escrito el renglón 133 de nuestro código (en el que escribimos el texto en nuestro búfer), marcará un error. Al ponerle el mouse encima del renglón nos desplegará un pequeño recuadro con la leyenda:

The float formatting support is not enabled, check your MCU Settings from “Project Properties > C/C++ Build > Settings > Tool Settings”, or add manually “-u _printf_float” in linker flags.

Lo que nos está indicando es que aún no hemos activado el uso del punto flotante en nuestra aplicación (esto no está activado por defecto para ahorrar memoria en los proyectos que no se utilice el punto flotante). Entonces, tendremos que proceder a activarlo.

Paso 11. Procedemos a abrir las propiedades de nuestro proyecto al hacerle clic derecho sobre la carpeta principal de nuestro proyecto en nuestro Explorador de Proyectos y luego seleccionar Properties (se encuentra hasta abajo).

Otra alternativa es utilizar el atajo de “Alt + Enter” para abrir la misma ventana.

Paso 12. Entramos a las categorías C/C++ Build → Settings → Tool Settings → MCU Settings y activaremos la casilla de la opción Use float with printf from newlib-nano (-u _printf_float).

Imagen 6. Activación del uso del punto flotante en la instrucción printf.

 

Una vez activado, y presionado en el botón Apply and Close, podremos ver que el error habrá desaparecido.


 

Paso final – Cargar el programa a la Ophyra

Ahora, falta programar nuestro código a la tarjeta Ophyra. Las instrucciones se encuentran en el tutorial del Paso final – Cargar el programa a la Ophyra.

 

Resultados

Necesitamos abrir la terminal del puerto serial en el STM32Cube IDE. Para ello, seguimos los mismos pasos que en el tutorial 7. Comunicación RS232 en la sección “Abriendo la terminal del puerto serial”.

Una vez abierta la terminal, podremos observar que constantemente se están escribiendo los datos del sensor, indicando las aceleraciones y rotaciones de los tres ejes, así como la temperatura. Al mover o rotar la tarjeta podrá observar que los valores cambian. Durante el movimiento, los valores de aceleración subirán y volverán a un valor cercano a cero una vez la tarjeta se ha dejado de mover. Al dejar volteada la tarjeta en otra posición, podrá observar que los valores de la rotación del giroscopio son diferentes al de la posición normal de la tarjeta. En cuanto a la temperatura, debería estar muy aproximada a la temperatura ambiente del lugar.

 

Conclusiones

Hemos configurado y programado en Ophyra el sensor MPU6050 mediante el puerto serial I2C. Así mismo, utilizamos el puerto serial RS232 para visualizar la información proveniente del sensor en la terminal del STM32Cube IDE. Te sugerimos hacer ejercicios más complicados, como la configuración del sensor a otra velocidad de muestreo, rango de medición del Accelerómetro y sensibilidad del Giroscopio.

Para seguir aprendiendo más sobre los recursos básicos de la Ophyra, te recomendamos seguir con el siguiente tutorial: 9. Lectura de la memoria M24C32-EEPROM.