A diferencia de los timers comunes que pertenecen a STMicroelectronics, el SysTick (System Tick) es un timer de 24 bits integrado directamente en el núcleo del procesador por la empresa ARM. Es el "latido del corazón" del sistema operativo y todos los microcontroladores Cortex-M del mundo lo tienen.
El SysTick funciona como una cuenta regresiva. Le cargamos un valor matemático, y el hardware resta uno por cada ciclo de reloj. Cuando llega a cero, levanta una Interrupción (detiene el código principal, ejecuta una función especial, y vuelve a donde estaba). Lo usaremos para contar exactamente milisegundos reales, independientemente de la velocidad del procesador.
Un Delay Bloqueante congela al procesador. Nadie lee botones, nadie actualiza pantallas. Una Base de Tiempo No Bloqueante revisa el reloj continuamente pero sigue avanzando; permite que el procesador ejecute miles de otras tareas mientras espera que se cumpla el tiempo deseado. A esto se le conoce como programación concurrente mediante Máquinas de Estado.
Ejercicio 1: Configurar el SysTick. Sabiendo que en el Día 93 subimos nuestro reloj principal (SYSCLK) a 84MHz, la fórmula matemática para lograr una interrupción de exactamente 1 milisegundo es: $\text{Reload} = (84,000,000 \text{ Hz} / 1000) - 1 = 83999$.
Escribe el código Bare-Metal para configurar este timer y diseña tu propia función obtener_milisegundos(). Luego, utilízala para crear una válvula que abra 2 segundos y cierre 2 segundos, sin bloquear el CPU.
/**
* @file main.c
* @brief Base de tiempo SysTick y Código No Bloqueante
*/
#include "stm32f401xe.h"
#include "valve_driver.h" // Del Día 96
// --- 1. VARIABLE GLOBAL DE TIEMPO (El Latido) ---
// 'volatile' indica al compilador que esta variable cambia mágicamente
// en segundo plano (por el hardware), para que no la optimice ni la borre.
volatile uint32_t milisegundos_globales = 0;
// --- 2. CONFIGURACIÓN DEL SYSTICK BARE-METAL ---
void SysTick_Init(void) {
// 1. Apagamos el timer antes de configurarlo
SysTick->CTRL = 0;
// 2. Cargamos el valor de recarga para 1ms exacto a 84MHz
SysTick->LOAD = 83999;
// 3. Limpiamos el valor actual
SysTick->VAL = 0;
// 4. Encendemos usando el reloj del procesador (84MHz) y habilitamos la interrupción
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
}
// --- 3. VECTOR DE INTERRUPCIÓN FÍSICO (ISR) ---
// El núcleo Cortex-M salta automáticamente a esta función cada 1ms
void SysTick_Handler(void) {
milisegundos_globales++;
}
// Función limpia para que el usuario consulte el tiempo
uint32_t obtener_milisegundos(void) {
return milisegundos_globales;
}
// --- 4. APLICACIÓN NO BLOQUEANTE ---
int main(void) {
// Configurar pines (Válvula) y activar el tiempo
Valvula_Init();
SysTick_Init();
// Variables de control de la Máquina de Estados
uint32_t tiempo_previo = 0;
uint8_t estado_valvula = 0; // 0 = Cerrada, 1 = Abierta
while (1) {
// CÓDIGO NO BLOQUEANTE (Concurrente)
// Revisamos el reloj. ¿Han pasado 2000 milisegundos (2 segundos)?
if (obtener_milisegundos() - tiempo_previo >= 2000) {
// Actualizamos la marca de tiempo para la próxima vez
tiempo_previo = obtener_milisegundos();
// Cambiamos de estado
if (estado_valvula == 0) {
VALVULA_ON();
estado_valvula = 1;
} else {
VALVULA_OFF();
estado_valvula = 0;
}
}
// ¡MAGIA BARE-METAL!
// Al no usar "for", el procesador cruza este bucle millones de veces
// por segundo. Aquí abajo tienes todo el tiempo del mundo para leer
// el teclado, la botonera, o el sensor de flujo, sin perder un solo pulso.
// leer_sensores();
// actualizar_pantalla();
}
return 0;
}
Objetivo del día: Multitarea Real mediante Programación Concurrente.
Un despachador de gas debe hacer muchas cosas a la vez: la pantalla LCD debe parpadear anunciando "DESPACHANDO...", el sensor de Efecto Hall debe leer cientos de pulsos del flujo de gas por segundo, y el procesador debe vigilar constantemente el Botón de Paro de Emergencia.
Si la pantalla LCD usara un delay(1000) para mostrar un mensaje, durante ese segundo entero tu microcontrolador estaría ciego. Los pulsos de gas seguirían pasando y tú no los sumarías a la cuenta final (pérdida económica masiva). Al construir la variable milisegundos_globales nutrida directamente por el hardware de ARM (SysTick), acabas de dotar a tu software del poder de la asincronía. La válvula se abre y se cierra con una precisión atómica, y el procesador jamás se detiene a descansar.
83999.SysTick_Handler(void) es una interrupción por hardware (ISR). El procesador abandona el main, la ejecuta, y regresa, de forma completamente invisible para tu programa.tiempo_actual - tiempo_previo >= intervalo es la única forma aceptable de crear retardos en software industrial metrológico.