Dimmer digital (control digital de cargas de AC) con el Arduino UNO

Dimmer digital (control digital de cargas de AC) con el Arduino UNO

Introducción

Un dimmer es un dispositivo analógico que controla la cantidad de potencia que le llega a una carga de corriente alterna (AC de aquí en adelante). El control es a través de un potenciómetro que, junto con otros componentes pasivos, retarda la activación de un semiconductor de potencia conocido como TRIAC; entre más se tarde la activación, menos potencia le estará llegando a la carga.

Dimmer analógico de fabricación propia. Observa su simplicidad. Utiliza al TRIAC BTA16-600B.

Un TRIAC es un semiconductor utilizado en aplicaciones de AC que una vez que es activado, permite el paso de la corriente eléctrica hacia la carga. Un punto importante a tener en cuenta es que una vez que el TRIAC ha sido activado, no se puede desactivar de forma sencilla (esto aplica fundamentalmente para aplicaciones de DC). Sin embargo, tiene la propiedad de que cuando la AC vuelve a cero en cada ciclo, entonces es desactivado de forma automática. 

TRIAC montado en un dispador de calor. A su derecha se aprecia un optotriac.

El potenciómetro, junto con una resistencia de 1K, un capacitor de 100n (y un DIAC), forman un circuito de tiempo (timer) que, como mencioné, retardan la llegada de la potencia a la carga. El proyecto que propongo conserva al TRIAC, pero el control de éste lo hará a través de un timer del microcontrolador, de ahí el nombre de “dimmer digital”. Sin embargo, dependiendo de la aplicación final que uno le quiera dar al proyecto, el potenciómetro podría ser necesario también.

Circuito eléctrico del dimmer analógico. El circuito está dimensionado para 127VAC con frecuencia de 60Hz. El TRIAC requiere un disipador de calor.

Hablando del potenciómetro, éste es una de varias posibilidades de control, ya que también podrías utilizar dos botones (inclusive del tipo touch): uno para aumentar la potencia y otro para disminuirla; o quizás quieras utilizar un control tipo palanca analógica. 

Para el control manual podrías usar un potenciómetro o un par de botones.

Antes de continuar es pertinente que sepas que comencé este mini proyecto porque estoy trabajando en un proyecto personal más grande que utilizará control difuso (fuzzy control) para una plancha caliente para soldar componentes SMD (smd hot plate reflow): el controlador difuso, a partir de los algoritmos de la lógica difusa, será quien determine el retardo que el timer de un microcontrolador aplicará para activar el TRIAC en cada medio ciclo de la AC, y en consecuencia la potencia que la carga recibirá.

Para implementar este proyecto vamos a necesitar varios elementos:

  1. Un circuito de cruce por cero para sincronización con la AC.
  2. Un temporizador del microcontrolador.
  3. Un potenciómetro o botones (dependiendo de la aplicación final de este dimmer digital).
  4. Una etapa de potencia que le haga llegar la energía a la carga AC.

Circuito de sincronía

Siempre que quieras controlar cargas de AC necesitarás un circuito que auxilie a tu controlador en la sincronización con la propia señal de AC. En el caso del dimmer analógico, sus componentes lo hacen de forma automática y natural; sin embargo, para el caso del dimmer digital necesitaremos componentes extra para construir un detector de cruce por cero. Para este subcircuito tenemos dos posibilidades: tomar la señal directamente de los 127VAC de la línea, o utilizar un transformador que nos provea de aislamiento galvánico. POR SEGURIDAD voy a utilizar este último.

Para este detector de cruce por cero, además del transformador, vamos a requerir un optoacoplador para “cuadrar” la señal senoidal de AC disminuída. Esta señal cuadrada y eléctricamente dentro de los límites de nuestro microcontrolador será la señal de sincronía que inyectaremos como una interrupción en el pin D2 del Arduino UNO. Como lo detallaré más adelante, dentro de esta interrupción arrancaremos al temporizador por software en cada semiciclo de la AC.

Detector de cruce por cero (ZCD, zero cross detector). GND debe ser la misma que el circuito que recibe la señal de sincronía. R3 deberá ajustarse dependiendo de la tensión del secundario del transformador. R6 puede hacerse más grande. El esquemático lo realicé en KiCAD.

Debo mencionar que existen diferentes formas de detectar el cruce por cero; usando al optoacoplador es una de ellas y siempre me ha funcionado. Sin embargo, podrías encontrar configuraciones que usan un transistor. Inclusive, y con los debidos cuidados, podrías utilizar al ADC o comparador interno al microcontrolador para realizar la detección (más tarde intentaré ésta).

IMPORTANTE: sin importar la técnica que escojas, SIEMPRE usa un transformador que te aisle galvánicamente de la tensión de la red de AC.

¿Porqué necesitamos la sincronía? Porque si activas al TRIAC en forma arbitraria obtendrás tres efectos indeseables:

  • Tu carga va a parpadear (flicker). Este efecto es visualmente más notorio cuando controlas lámparas y es muy malo para el control de motores.
  • Vas a introducir ruido a la red de AC que se manifestará como interferencias electromagnéticas.
  • Difícilmente podrás controlar a la carga en el estricto sentido de la palabra (esto es, al sistema le costará mucho trabajo llegar a un estado estable o de equilibrio; por ejemplo, que tu plancha alcance y se estabilice en los 100 grados que tu proceso requiere, ya que la temperatura real obtenida siempre estará oscilando alrededor, y quizás muy lejos, del valor deseado).

Quizás ya hayas visto muchos circuitos en Internet donde “utilizan” PWM para el control de cargas de AC; esta técnica no funciona a menos que el PWM provenga de un inversor ( o en inglés, inverter). Si el PWM proviene directamente de tu Arduino UNO al TRIAC de salida, entonces tendrás los 3 problemas que acabo de comentar.

Por esa razón tuve que buscar la forma de generar un pulso único en cada semiciclo de la AC en lugar de usar el PWM directo del UNO.

Temporizador

Este es el subsistema más importante de este proyecto, y a la vez es el más simple: el temporizador empezará a contar desde cero y de forma ascendente cada vez que llegue una señal de sincronía. Luego, cuando la cuenta llegue al valor preestablecido, mandará una señal de activación al circuito que controla al TRIAC.

Diagrama de tiempos. Nota que entre menor sea la cuenta del timer, más potencia le llegará a la carga.

Esta tarea es muy fácil de lograr para los temporizadores de cualquier microcontrolador, y la configuración de cada uno dependerá, por supuesto, del chip específico que estemos utilizando. Para este proyecto utilizaré al timer 2 del ATMEGA328, que como ya sabrás, es el corazón del Arduino UNO, pero la teoría es la misma para cualquier otro, como los chips de LPC de NXP, los STM32 de ST, o los SAM de Microchip.

void setup()
{
   TCCR2A = 
        (3<<4)         // COM2B1:0=0x3 -- Set OC2B on compare match, clear OC2B at BOTTOM
      | (3<<0);        // WGM21:0 =0x3 -- Fast PWM (along with WGM22 on TCCR2B)

   TCCR2B = (1<<3);    // WGM22   =0x1 -- Fast PWM (along with WGM21:0 on TCCR2A)

   // Start / stop is performed in another rutine. For start counting we would do:
   // TCCR2B = (1<<3) 
   //        | (7<<0); // CS22:CS2:0   -- Choose CLK / 1024

   TCNT2 = 0;          // Counter.
   
   OCR2A = 128;        // Period. There will be 128 counts on one AC's semicycle
   
   OCR2B = 127;        // Duty cycle. 1 -> 100% power, 127 -> 0% power
   
   TIMSK2 = 0;         // Don't use any interrupt from the timer
   TIFR2 = 0;

   pinMode( TRIAC_PIN, OUTPUT );
   digitalWrite( TRIAC_PIN, LOW );

   pinMode( SYNC_PIN, INPUT_PULLUP );
   attachInterrupt( digitalPinToInterrupt( SYNC_PIN ), Sync_ISR, RISING );

   // ... more initialization here that doesn't interact with the timer ...
}

El temporizador está asociado al pin D3 del Arduino UNO y está configurado de tal manera que mientras el contador no llegue a la cuenta máxima, entonces el pin se mantendrá en bajo. Una vez que el contador alcanzó la cuenta máxima, el pin cambia al estado alto y el contador deja de contar (en el datasheet leemos: “Set OC2B on compare match, clear OC2B on BOTTOM”, mode: Fast PWM, table: 17-6, pp. 129). Este cambio de bajo a alto en el pin es la señal que activará a la etapa de potencia (claro que sin tu intervención ya que esto se lleva a cabo por hardware). En cada nueva señal de sincronía el pin es puesto en bajo y el contador en cero para comenzar el ciclo de nuevo.

El código de la rutina de interrupción es la siguiente. Al final de este artículo encontrarás el código completo.

// Sync ISR codeL
void Sync_ISR()
{
   timer_ctrl( STOP );
   // Don't update the timer registers while it's counting

   power.apply();
   // Update the timer registers with a new value (if any)

   digitalWrite( 13, (led_state=led_state?false:true) );
   // System is alive! (kind of)

   timer_ctrl( START );
   // Start the timer again
}

Para terminar esta sección te comento que con la configuración actual del timer 2 del UNO somos capaces de obtener hasta 130 pasos por semiciclo (aunque sólo usé 128). A continuación te voy a presentar un resumen de los cálculos (y también a mi yo del futuro, cuando en 3 semanas se me haya olvidado porqué hice lo que hice) y después te platicaré sobre el posible aumento de la resolución (más pasos en cada semiciclo) en el sistema.

Resolución

¿Podemos lograr más resolución, es decir, más pasos en cada ciclo? Sí y no. La respuesta exacta depende del número de bits de los registros del temporizador. En el caso que nos ocupa (el timer 2 del ATMEGA328) los registros, y en especial el registro contador TCNT2, son de 8 bits y los prescalers (divisores de frecuencia) no ayudan mucho ya que son pocos y son fijos: 1024, 256, 128, etc, por lo cual la máxima cantidad de pasos que podemos obtener es 130. Para evitar divisiones raras y para prueba de concepto, reduje el número a 128 (0-100% en pasos de aproximadamente 1; 100/128 para ser exactos). 

Divisores de frecuencia (prescalers) del ATMEGA328.

Como pudiste ver en el código anterior, utilicé un divisor con valor 1024, cuya cuenta máxima para un semiciclo de la AC de 60 Hz es de 130 (130 * 64 us = 8.33 ms; 1 / 120Hz = 8.33 ms) y 130 cabe perfectamente en los 8 bits del registro TCNT2. No puedo escoger el prescaler inmediato anterior (cuyo valor es 256), ya que la división de un semiciclo completo constaría de 520 pasos (mayor resolución), pero este valor ya no cabe en los 8 bits del registro TCNT2.

Una alternativa es utilizar al timer 1, el cual es de 16 bits; sin embargo, éste está ocupado por el subsistema de Arduino para servo-motores. Si lo crees conveniente podrías utilizar este timer en lugar del 2 que yo ocupé, en el entendido que ya no podrías controlar servos directamente con las terminales predeterminadas. NO TOQUES AL TIMER 0, es más, ni lo mires.

No obstante, por otro lado tenemos que los microcontroladores de 32 bits ARM (LPC(NXP), STM32(ST), SAM(Atmel), entre muchos otros) todos incluyen temporizadores de 32 bits y prescalers más poderosos, por lo cual podríamos obtener centenas o millares de pasos en cada ciclo. (En un ejercicio previo con un LPC812 logré fácilmente 1000 pasos; esto es, 0-100% en pasos de 0.1.) Pero hay un pero.

Debido a que el temporizador no está trabajando en aislamiento, cientos o miles de pasos por ciclo no siempre significarán un mejor rendimiento del sistema debido a algunas circunstancias fuera de nuestro control:

  • El detector de cruce por cero no es perfecto.
  • El ADC es de 10 bits, tiene errores intrínsecos y con un mal diseño del circuito impreso podría captar ruido ambiental. (El ADC lo usé como control para mis pruebas de concepto, como lo describiré más adelante.)
  • Errores de redondeo y truncamiento por utilizar números decimales.
  • El controlador difuso (en mi proyecto) no requiere tanta precisión ya que los algoritmos absorberán la falta de ésta.

¿Porqué no usar el PWM del Arduino UNO?

Quizás ya hayas visto muchos circuitos en Internet donde “utilizan” PWM para el control de cargas de AC; esta técnica no funciona a menos que el PWM provenga de un inversor ( o en inglés, inverter) y la carga esté conectado a éste. Si el TRIAC es controlado directamente (a través del optotriac, por supuesto) por el PWM proveniente de tu Arduino UNO, entonces vas a enfrentar los 3 problemas que te comenté en la sección anterior.

Esa es la razón por la cual tuve que buscar la forma de generar un pulso único en cada semiciclo de la AC en lugar de usar el PWM directo del UNO.

Control analógico (para efectos de prueba de concepto y de este artículo)

Para probar si lo que hemos hecho funciona debemos manipular la señal de control, y lo más fácil es a través de un potenciómetro conectado a un canal del ADC. Hazlo igual, y cuando tengas la certeza de que todo trabaja a la perfección, entonces podrías realizar el control con dos botones, o con una palanca analógica, o con luz IR (a través de un control remoto), o por WiFi o Bluetooth, o con la voz a través de Alexa, etc.

Recuerden que hemos dividido al semiciclo de la AC en 130 pasos, pero el ADC es de 10 bits y nos entrega 1024 pasos, por lo cual no podemos hacer un mapeo 1 a 1 entre el potenciómetro y el número de pasos del timer. Lo que hice fue dividir el valor entregado por el ADC entre 8, obteniendo 128 pasos (1024/8); esto es, cada 8 pasos del ADC corresponden a 1 paso del timer, o dicho de otro modo, mapeamos 8:1.

Repito que el objetivo de este subproyecto es el control físico de una carga AC, lo que en control le llamamos “la planta” (o “sistema”), y la cantidad de potencia que estará llegando a la carga va a depender de lo que el algoritmo de control difuso haya calculado. Y una característica de los controladore difusos es que no necesitan mucha precisión; de hecho, son intrínsecamente imprecisos: “cerca”, “lejos”, “tibio”, “caliente”, “muy caliente”, “error pequeño”, “error grande”, etc. Así que no nos volvamos locos con la precisión.

Más adelante les estaré platicando este proyecto de “cama caliente” (o smd hot plate reflow), nada más ténganme paciencia, una cosa a la vez.

Etapa de potencia

Esta etapa es la interfaz que se encarga de hacerle llegar al TRIAC la señal de disparo que sale del pin D3 del Arduino UNO (esta terminal está asociada al timer 2).

Recuerda que nuestros microcontroladores trabajan a 3.3VDC o 5VDC, pero las cargas AC operan con 127VAC (en México) o 220VAC (en otros países), y debemos evitar en lo posible que nuestros chips de baja tensión entren en contacto directo con la alta tensión, por seguridad de ellos y DE NOSOTROS, principalmente.

Circuito eléctrico de la etapa de potencia: básicamente es un relevador de estado sólido (SSR). Si sabes lo que haces, entonces puedes eliminar D1 y Q1, y colocar un puente en lugar de R2. R7 y C1 forman una red snubber y su colocación es opcional; con cargas resistivas no son necesarios.
¡LA PARTE DERECHA ES ALTA TENSIÓN! Ten mucho cuidado.

Para prueba de concepto utilicé un prototipo de SSR que diseñé hace un tiempo a partir del esquemático anterior:

(En esta entrada de mi blog alterno te muestro una variante del SSR para construirlo con técnicas caseras.)

Como interfaz utilicé un dispositivo conocido como OPTOTRIAC (MOC3022) para que provea aislamiento óptico entre la baja y la alta tensión, lo cual es suficiente en la mayoría de aplicaciones. Si necesitas aislamiento galvánico, entonces deberás utilizar transformadores de señal. (No uses relevadores; estos son demasiado lentos y en unos cuantos minutos podrías terminar con su vida útil.)

MOC3022. Imagen tomada del datasheet de Fairchild.

El optotriac recibe la señal de activación del pin D3 y ópticamente la transfiere a su triac interno (de ahí el nombre optotriac), el cual generará la señal que el TRIAC externo necesita para activarse. El TRIAC se desactivará (dejará de conducir) cuando la señal de AC vuelva a cero en cada semiciclo.

Nota interesante: El triac en AC funciona como una especie de memoria temporal de un bit: el timer (o control externo) aplica un “set” (1) en la terminal THR, lo cual hace que a la salida se presente un (1). Este estado se va a mantener así hasta que llegue el “reset” (0), el cual es aplicado cuando la AC vuelve a cero, lo que hace que la salida pase a (0).

Red snubber

En aplicaciones donde las cargas son resistivas (resistencias calentadoras de alu-cromel, cerámicas o silicón) no es necesario agregarle al TRIAC un circuito llamado “red snubber”, la cual consta, en su forma más básica, de una resistencia y un capacitor (R7 y C1 en el esquemático). Sin embargo, si las cargas van a ser reactivas (motores), entonces dicha red sí es necesaria. Afortunadamente el proyecto que nos ocupa tendrá cargas resistivas, así que no nos metamos en más problemas. (Pero si te interesa saber más, ST tiene esta nota de aplicación muy interesante sobre redes snubber para TRIACs.)

Proyecto completo

A continuación podrás ver el circuito electrónico completo del proyecto y el código asociado.

No he diseñado aún un circuito impreso para este proyecto dado que primero necesito terminar mi aplicación de control difuso; ahora mismo probé el concepto con una tarjeta clon mía del Arduino UNO, un protoboard, un relevador de estado sólido también mío, y muchos jumpers.

Te presento el código completo. En caso de que no puedas visualizarlo, entonces por favor visita GitHub para que lo obtengas:

El esquemático del prototipo funcional completo es este:

Esquemático completo del prototipo. Lo realicé con el mejor software del mundo: KiCAD.

Me permito insistir en que puedes construir este proyecto con cualquier otro microcontrolador. En caso de que necesites un control con mucha precisión o de ajuste muy fino, entonces deberías optar por uno de 32 bits o sacrificar el subsistema de control de servos del Arduino UNO.

Me gustaría saber si utilizas este circuito con un control diferente al potenciómetro, y también para qué aplicación lo usaste. ¡Házmelo saber en los comentarios!



¿Ya conoces mi curso gratuito de Arduino en tiempo real, utilizando el Arduino UNO o el Arduino Due y FreeRTOS?


¿Te gustaría ser de los primeros en recibir las actualizaciones a mi blog? ¡Suscríbete, es gratis!


Fco. Javier Rodríguez
Escrito por:

Fco. Javier Rodríguez

Soy Ingeniero Electrónico con 20+ años de experiencia en el diseño y desarrollo de productos electrónicos de consumo y a medida, y 12+ años como profesor. Egresado de la UNAM, también tengo el grado de Maestro en Ingeniería por la misma universidad. Mi perfil completo lo puede encontrar en: https://www.linkedin.com/in/fjrg76-dot-com/

Ver todas las entradas