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

2. Timers (Temporizadores)

Bienvenidos a este tutorial donde utilizaremos uno de los 14 Timers con los que cuenta el microcontrolador de Ophyra. Estos Timers están divididos en 12 Timers de 16 bits y 2 Timers de 32 bits.

Proyecto a realizar: Manejando las interrupciones del timer, un LED se encenderá y se apagará cada medio segundo.

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. En las categorías del lado izquierdo, abriremos la de Timers. En ello podremos ver los 14 que tiene disponibles. Al pulsar sobre uno de los timers, se mostrarán las opciones de su modo de operación.

Imagen 1. Modos de operación de un Timer.

NOTA INFORMATIVA

Algunos Timers cuentan con canales que permiten tener múltiples señales generadas por un solo Timer. Como observamos en la Imagen 4, dentro del Timer 3 (TIM 3) contamos con cuatro canales con la capacidad de ser utilizados como comparadores, breitling replica watches modos de captura o como PWM (Modulación por Ancho de Pulso).

Imagen 2. Modos de operación del Timer 3.

Para nuestra aplicación, basta con solo indicar la fuente de reloj interna. Una vez que se le ha seleccionado, el nombre del Timer cambiará a color verde y tendrá una paloma, indicando que ya está activo.

Imagen 3. Activando el Timer 3.

Paso 2. Es necesario calcular unos parámetros que necesitará el Timer para que genere la interrupción cada medio segundo. Son dos valores los que necesitaremos calcular: el Prescaler (Preescalador) y el Counter Period (Periodo del Contador).

Las fórmulas que utilizaremos son las siguientes:

Donde:

Ft = Frecuencia del Timer

Fc = Frecuencia del reloj

P = Prescaler

Cp = Counter Period

T = Tiempo

La frecuencia de nuestros relojes que se aplican en los Timer lo podemos encontrar en la pestaña de Clock Configuration, tal como se muestra en la Imagen 4. En nuestro ejemplo, tenemos una Frecuencia de reloj (Ft) de 84MHz

Imagen 4. Verificando la frecuencia del reloj.

Ahora, proponiendo una frecuencia deseada de 100KHz y un tiempo de medio segundo para su desborde, tenemos:

P = 839

Cp = 49,999

Paso 3. Una vez que ya tenemos los valores calculados, solo resta colocarlos en la configuración del Timer. Además del Prescaler y del Counter Period, hay otras configuraciones que se pueden modificar en el Timer 3, tales como:

  • Counter Mode: Nos permite elegir si queremos que el contador del timer sea de modo ascendente o descendente. Nosotros lo dejaremos en ascendente.
  • Internal Clock Division (CDK): Nos permite dividir la frecuencia del reloj. Nosotros lo dejaremos sin división.
  • Master/Slave Mode: Indica si el Timer trabajará en modo de Maestro o Esclavo. Nosotros lo dejaremos deshabilitado.
  • Trigger Event Selection: Indica el evento que ejecuta cuando termina su cuenta. Nosotros indicaremos que haya una actualización de evento cada vez que haya un desborde.
Imagen 5. Configurando el Timer 3.

Paso 4. Para terminar con las configuraciones del timer, necesitamos habilitar su interrupción. Esto nos permitirá tener una forma de darnos cuenta de que el Timer ha terminado de contar, y en ese momento podremos tomar acciones.

En esa misma sección donde configuramos el Prescaler y Counter Preiod, podemos observar que hay más pestañas de configuración. Abrimos la pestaña NVIC Settings y habilitamos su interrupción.

Imagen 6. Activando la interrupción del Timer 3.

Paso 5. Ahora que tenemos configurado el Timer con el que deseamos trabajar, debemos activar también el pin con el que estaremos interactuando y escogeremos uno de los tres colores del LED RGB con el que cuenta Ophyra, ubicados en los pines PE0, PE1 y PE2 (En este ejemplo se eligió el LED Verde, ubicado en el pin PE1).

Imagen 7. Activando el LED Verde como salida.

Paso 6. Ahora pasaremos a configurar nuestro pin de salida del LED. Se utilizan los mismos pasos como en el tutorial 1 – Puertos GPIO.

Paso 7. 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 8. Generando código.

Realizando el Programa

Dentro de la sección main, podemos encontrar el siguiente fragmento de código:

/* Configure the system clock */
 SystemClock_Config();

 /* USER CODE BEGIN SysInit */

 /* USER CODE END SysInit */

 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_TIM3_Init();
 /* USER CODE BEGIN 2 */

 /* USER CODE END 2 */

En el tutorial pasado (1 – Puertos GPIO) ya se había mencionado de manera general lo que las funciones SystemClock_Config(); y MX_GPIO_Init(); hacían. Sin embargo, ahora podemos notar que hay una nueva funcion que se está llamando.

La función MX_TIM3_Init(); es la que se encarga de cargar todos los parámetros de configuración que hicimos en los pasos anteriores, pero aún no está activa la interrupción del Timer.

Paso 8. Para activar la interrupción de nuestro Timer 3, necesitamos la función:

HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);

Como parámetro nos pide un apuntador a una variable que controla nuestro Timer. Esa variable la podemos encontrar más arriba en el código  (en la línea 43 de nuestro ejemplo).

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim3;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM3_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

Ya que la función que necesitamos incluir en nuestro código nos pide un apuntador a la variable, necesitaremos ponerle el símbolo ‘&‘ justo antes de la variable. Así, nuestro código queda de la siguiente manera:

SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim3);
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */

Nótese que no tenemos escrito nada dentro del while infinito. Esto es debido a que con la instrucción que acabamos de colocar, no hay necesidad de estar preguntando si ya ha terminado de contar el Timer o si existe algún desborde, ya que de esta tarea se encargará la rutina de interrupción.

Paso 9. Ahora debemos acceder a nuestra rutina de interrupción. Uno de los archivos generados además del main.c y el main.h es el stm32f4xx_it.c que contiene las interrupciones de todos los diferentes recursos del ARM. Ese archivo se encuentra en la carpeta Core → Src, justo donde está también el main.c.

Imagen 9. Ubicación del archivo de interrupciones.

Dentro del archivo podemos encontrar el siguiente fragmento del código:

/**
  * @brief This function handles TIM3 global interrupt.
  */
void TIM3_IRQHandler(void)
{
  /* USER CODE BEGIN TIM3_IRQn 0 */

  /* USER CODE END TIM3_IRQn 0 */
  HAL_TIM_IRQHandler(&htim3);
  /* USER CODE BEGIN TIM3_IRQn 1 */

  /* USER CODE END TIM3_IRQn 1 */
}

Esta función es llamada cada vez que termina de contar el Timer 3 y no es necesario volver a iniciar el conteo ya que existe la instrucción HAL_TIM_IRQHandler(&htim3); que está escrita automáticamente y una de sus funciones es la de reiniciar la variable de conteo del Timer.

Ahora, debemos construir nuestra aplicación de encendido y apagado del LED, y para ello podemos utilizar la función:

HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

Cada que se llame esa función, cambiará el estado del pin indicado. Si el pin se encontraba en “RESET” se cambiará a “SET” y viceversa. De esta manera no nos tendremos que preocupar de revisar el estado del pin y tener que indicarle que se apague o prenda con instrucciones por separado. Así, nuestro código quedará de la siguiente manera:

/**
  * @brief This function handles TIM3 global interrupt.
  */
void TIM3_IRQHandler(void)
{
  /* USER CODE BEGIN TIM3_IRQn 0 */

  /* USER CODE END TIM3_IRQn 0 */
  HAL_TIM_IRQHandler(&htim3);
  /* USER CODE BEGIN TIM3_IRQn 1 */
  HAL_GPIO_TogglePin(Led_Verde_GPIO_Port, Led_Verde_Pin);
  /* USER CODE END TIM3_IRQn 1 */
}

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

En el siguiente GIF, podrás observar que apenas comienza a trabajar la Ophyra (se presiona el botón de Reset para sacarlo del modo Bootloader), el color verde del LED RGB está constantemente apagándose y prendiéndose cada medio segundo.

Conclusiones

Hemos configurado y programado dos nuevos recursos de la Ophyra: los Timer y las Interrupciones, y hemos desarrollado una aplicación básica para hacer las pruebas con ambos. Ahora podrías continuar haciendo otros proyectos como contadores de 8-bit, generadores de onda cuadrada, o hasta un semáforo con el mismo LED RGB de la Ophyra.

Te sugerimos continuar con el siguiente ejercicio: 3. ADC (Convertidor Analógico-Digital) para seguir adquiriendo experiencia manejando los recursos básicos de la Ophyra.