Temporizadores
Pulsos y captura
Un pulso de duración exacta y medir frecuencia, ciclo de trabajo y ancho con la captura
Idea clave. Hasta aquí el Timer sacaba señales por los pines MAT. Ahora va al revés: con la captura, un flanco en un pin de entrada copia el valor del TC en un registro. Así se mide frecuencia, ciclo de trabajo o ancho de un pulso con la precisión del reloj, no con la de la ISR. Antes, un caso intermedio: sacar un solo pulso de duración exacta.
Un pulso de duración T
Para un único pulso de T segundos en MATn.1 (por ejemplo, MAT0.1 en P1.29):
- MR1 con Stop y Reset en MCR: al llegar, el timer se para y vuelve a 0, listo para el siguiente pulso.
- EMC1 = 01: el Match pone MATn.1 a 0.
- La subida se hace a mano: se escribe EM1 = 1 en EMR y se arranca el timer.
void set_pulso_alto(float duracion) { // duración en segundos
LPC_TIM0->MR1 = Ftick * duracion - 1;
LPC_TIM0->EMR = (1 << 1) | (1 << 6); // EM1 = 1 (pin a 1), EMC1 = 01 (bajar en MR1)
LPC_TIM0->TCR = 0x01; // arrancar
}
La subida es software (empieza cuando se ejecuta la función) y la bajada es hardware (exacta). El pulso dura justo T aunque la CPU tarde en llegar, porque el Timer empieza a contar en el mismo momento en que se sube el pin. Con F_tick = 25 MHz, la resolución es de 40 ns: un pulso de 1 µs son 25 cuentas.
El modo captura
Cada Timer tiene dos entradas de captura, CAPn.0 y CAPn.1, y dos registros CR0 y CR1. Cuando llega el flanco elegido, el hardware copia el TC en CRx y, si se pide, interrumpe. El TC sigue contando: la captura no lo para ni lo reinicia.
| Bits | Campo | Qué hace |
|---|---|---|
| 0 | CAP0RE | 1 = capturar en CR0 con flanco de subida en CAPn.0 |
| 1 | CAP0FE | 1 = capturar en CR0 con flanco de bajada (los dos a 1: ambos flancos) |
| 2 | CAP0I | 1 = interrumpir con cada captura en CR0 |
| 3–5 | CAP1RE, CAP1FE, CAP1I | Lo mismo para CAPn.1 y CR1 |
Los flags están en IR: los bits 0–3 son de MR0–MR3 y los bits 4 y 5 de CR0 y CR1. Como siempre, se borran escribiendo un 1.
Algunos pines de captura: CAP0.0 en P1.26, CAP0.1 en P1.27, CAP1.0 en P1.18, CAP2.0 en P0.4 y CAP3.0 en P0.23. Hay que ponerlos en su función con PINSEL, como los MAT.
a) Medir la frecuencia
El TC corre libre (sin reset) y se captura en cada flanco de subida. Entre dos capturas hay un periodo:
void TIMER0_IRQHandler(void) {
static uint32_t anterior;
uint32_t n;
LPC_TIM0->IR = (1 << 4); // flag de CR0
n = LPC_TIM0->CR0 - anterior; // cuentas de un periodo
frecuencia = Ftick / n;
anterior = LPC_TIM0->CR0;
}
El valor de CR0 es exacto aunque la ISR llegue tarde (la latencia solo retrasa cuándo se lee). Y con uint32_t, la resta da bien aunque el TC haya pasado de 2³² − 1 a 0 entre dos capturas.
Los límites: a frecuencia muy baja, N se sale de 32 bits (con 25 MHz, por debajo de 0,006 Hz); a frecuencia muy alta, las capturas llegan más rápido de lo que la ISR las atiende. Con F_tick alto, N es grande y la medida más fina.
b) Medir el ciclo de trabajo
Se capturan los dos flancos (CAP0RE y CAP0FE a 1). La ISR entra dos veces por periodo y tiene que saber cuál ha llegado: se guarda en una variable (o se lee el pin).
- En la subida: el tiempo desde la subida anterior es el periodo T.
- En la bajada: el tiempo desde la última subida es T_H.
c) Medir el ancho de un pulso
Es lo mismo pero solo hace falta T_H: más sencillo.
void TIMER0_IRQHandler(void) {
static uint32_t flanco_subida;
static int esperando_subida = 1;
LPC_TIM0->IR = (1 << 4);
if (esperando_subida) {
flanco_subida = LPC_TIM0->CR0;
esperando_subida = 0; // el siguiente será de bajada
} else {
ancho = LPC_TIM0->CR0 - flanco_subida;
esperando_subida = 1;
}
}
En vez de capturar en ambos flancos, se puede capturar solo en uno y cambiar el flanco en CCR dentro de la ISR (subida → bajada → subida…). Así no hay duda de qué flanco ha llegado.
Preguntas de examen
Configura TIMER1 para medir la frecuencia de una señal en CAP1.0 (F_PCLK = 25 MHz). ¿Qué registros tocas y qué hace la ISR?
PINSEL para CAP1.0 (P1.18), PR = 0, MCR sin ningún reset (el TC corre libre), TCR = 1 para arrancar, CCR = CAP0RE | CAP0I (bits 0 y 2) y NVIC_EnableIRQ(TIMER1_IRQn). En la ISR: borrar IR bit 4, N = CR0 − anterior (uint32_t), f = 25·10⁶/N, anterior = CR0. (Respuesta redactada a partir de los apuntes.)
¿Por qué el pulso de set_pulso_alto dura exactamente T aunque la CPU sea lenta?
Porque la bajada no la hace la CPU: la hace el Match (EMC1 = 01) cuando el TC llega a MR1, contando desde el arranque. La subida y el arranque se hacen juntos en software, así que el ancho solo depende de MR1 y F_tick. (Respuesta redactada a partir de los apuntes.)
Una señal tiene T = 1 ms y T_H = 250 µs. Con F_tick = 25 MHz, ¿qué diferencias de CR0 lees y qué D sale?
Periodo: 25 000 cuentas. Alto: 6 250 cuentas. D = 6 250/25 000 = 0,25. (Respuesta redactada a partir de los apuntes.)
Material del curso usado: Apuntes de Miguel · Temporizadores del LPC17xx (diapositivas de clase) · UM10360 (manual del LPC17xx), cap. 8 y 21.