Analógico
ADC y DAC
Convertir tensiones a números con el ADC de 12 bits y números a tensión con el DAC de 10 bits
Idea clave. El ADC convierte una tensión del pin en un número de 12 bits (0–4095) y el DAC hace lo contrario con 10 bits (0–1023). Los dos van referidos a , que en la Mini-DK2 es 3,3 V. Con el ADC se leen sensores (una LDR, un potenciómetro, un micrófono); con el DAC se sacan señales analógicas, como audio.
El ADC
El LPC1768 tiene un convertidor de 12 bits por aproximaciones sucesivas y un multiplexor de 8 entradas (AD0.0–AD0.7) delante. Solo convierte un canal cada vez.
Algunos pines: AD0.0 en P0.23, AD0.1 en P0.24, AD0.2 en P0.25, AD0.3 en P0.26 (compartido con la salida del DAC), AD0.4 en P1.30 y AD0.5 en P1.31.
El reloj. Sale del PCLK del ADC (PCLKSEL0, bits 25:24) dividido entre CLKDIV + 1, y no puede pasar de 13 MHz. Cada conversión tarda 65 ciclos:
Con MHz, CLKDIV = 1 da 12,5 MHz y 5,2 µs por conversión (unas 190 000 por segundo). Cuanto más rápido el reloj, antes acaba.
| Bits | Campo | Qué hace |
|---|---|---|
| 7:0 | SEL | Un 1 en el canal que se convierte (en modo software, solo uno) |
| 15:8 | CLKDIV | Divisor del reloj: F_PCLK/(CLKDIV + 1) ≤ 13 MHz |
| 16 | BURST | 1 = convierte sin parar todos los canales de SEL, uno tras otro |
| 21 | PDN | 1 = ADC encendido (0 = apagado) |
| 26:24 | START | 000 = no empezar; 001 = empezar ya; 010 = flanco en EINT0 (P2.10); 011 = en CAP0.1 (P1.27); 100 = MAT0.1; 101 = MAT0.3; 110 = MAT1.0; 111 = MAT1.1 |
| 27 | EDGE | Con START ≥ 010: 0 = flanco de subida, 1 = de bajada |
Disparar con un Match es la forma limpia de muestrear a ritmo fijo: el Timer marca la frecuencia de muestreo y cada conversión empieza en el instante exacto, sin depender de la latencia de ninguna ISR.
| Bits | Campo | Qué hace |
|---|---|---|
| 15:4 | RESULT | El resultado de 12 bits |
| 26:24 | CHN | Canal convertido (solo en ADGDR) |
| 30 | OVERRUN | 1 = se ha pisado un resultado sin leerlo (modo ráfaga) |
| 31 | DONE | 1 = conversión terminada. Se borra al leer el registro |
| Bits | Campo | Qué hace |
|---|---|---|
| 7:0 | ADINTEN0–7 | 1 = interrumpir al terminar ese canal |
| 8 | ADGINTEN | 1 = interrumpir con DONE de ADGDR (cualquier canal). Vale 1 tras el reset |
Por eso AD0INTEN se escribe con = (y no con |=): así se pone el canal deseado y se borra ADGINTEN de paso.
void adc_init(void) {
LPC_SC->PCONP |= (1 << 12); // alimentar el ADC (apagado tras el reset)
LPC_PINCON->PINSEL1 |= (1 << 14); // P0.23 = AD0.0
LPC_PINCON->PINMODE1 |= (2 << 14); // sin pull-up ni pull-down
LPC_ADC->ADCR = (1 << 0) // canal 0
| (1 << 8) // CLKDIV = 1: 12,5 MHz
| (1 << 21); // PDN: encendido
LPC_ADC->ADINTEN = (1 << 0); // con =, para borrar ADGINTEN
NVIC_EnableIRQ(ADC_IRQn);
}
void ADC_IRQHandler(void) {
uint32_t r = LPC_ADC->ADDR0; // leer ADDR0 borra su DONE, el que pide la interrupción
muestra = (r >> 4) & 0xFFF;
}
Para convertir: LPC_ADC->ADCR |= (1 << 24); (START = 001). Si la entrada no tiene pull-up ni pull-down, la resistencia interna no altera la tensión que se mide.
Práctica 6 (Medida de señales analógicas) · conviene dominarlo
El DAC
Un convertidor de 10 bits con la salida AOUT en P0.26 (función 10 de PINSEL1, bits 21:20). No necesita PCONP: basta con llevar el pin a su función.
| Bits | Campo | Qué hace |
|---|---|---|
| 15:6 | VALUE | El valor de 10 bits |
| 16 | BIAS | 0 = se estabiliza en 1 µs (hasta 1 MHz, 700 µA); 1 = 2,5 µs (hasta 400 kHz, 350 µA) |
LPC_PINCON->PINSEL1 |= (2 << 20); // P0.26 = AOUT
LPC_DAC->DACR = (valor & 0x3FF) << 6; // valor de 0 a 1023
Generar una señal. Se guarda un periodo en una tabla de N muestras y un Timer interrumpe a ; en cada interrupción se escribe la siguiente muestra en DACR. La frecuencia de salida es . Lo mismo vale para reproducir audio grabado con el ADC: se muestrea y se reproduce a la misma (al menos 8 kHz para voz). Para no gastar CPU en cada muestra, se usa el DMA.
Práctica 7 (Grabación y reproducción de audio) · conviene dominarlo
Preguntas de examen
Un potenciómetro en AD0.0 debe leerse cada 10 ms sin tocar el ADC desde el programa principal. ¿Cómo lo montas?
Que el propio Timer dispare las conversiones. TIMER0 con MR1 = 5 ms·F_tick − 1, reset en MR1 y EMC1 = 11 (conmutar): MAT0.1 sube cada 10 ms. En AD0CR, START = 100 (MAT0.1) y EDGE = 0 (subida). AD0INTEN = (1 << 0) y en la ISR del ADC se guarda (ADDR0 >> 4) & 0xFFF. El conmutar es lo que crea el flanco: por eso el Match va a la mitad del periodo de muestreo. (Respuesta redactada a partir de los apuntes y del UM10360.)
¿Qué tensión mínima distinguen el ADC y el DAC con V_REF = 3,3 V?
ADC: 3,3/4096 ≈ 0,81 mV. DAC: 3,3/1024 ≈ 3,2 mV. (Respuesta redactada a partir de los apuntes.)
Con una tabla de 32 muestras de un seno, ¿a qué frecuencia debe interrumpir el Timer para sacar 500 Hz por el DAC? ¿Qué MR0?
kHz. Con F_PCLK = 25 MHz y reset en MR0: MR0 = 25·10⁶/16 000 − 1 = 1561,5, que no es entero: con 1561 o 1562 el error es de un 0,03 % (unos 500,2 o 499,8 Hz). (Respuesta redactada a partir de los apuntes.)
Material del curso usado: Apuntes de Miguel · Periféricos del LPC1768 (diapositivas de clase) · UM10360 (manual del LPC17xx), cap. 29 y 30.