Salidas analógicas PWM en Arduino


arduino-salida-analogica

En tutoriales anteriores hemos visto cómo usar las entradas digitales y las entradas analógicas para recibir señales del mundo. También hemos visto como interactuar con el entorno mediante las salidas digitales.

Sin embargo, en ocasiones no será suficiente con una señal digital (ON/OFF), si no que necesitaremos proporcionar un valor analógico de tensión, por ejemplo, para regular la intensidad de iluminación de un LED, o variar la velocidad de un motor DC.

En esta entrada vamos a ver cómo utilizar una salida PWM para emular una señal analógica de tensión desde Arduino.

¿Cómo funciona una salida analógica?

Las salidas analógicas son algo más complicadas que las digitales (como ya pasaba con las entradas analógicas y digitales).

Lo primero que tenemos que entender es que la mayoría de automatismos (y Arduino no es una excepción) no son capaces de proporcionar una auténtica salida analógica. Ni siquiera pueden suministrar una salida analógica discretizada (es decir, a saltos) de tensión. Lo único que pueden proporcionar es una salida digital de -Vcc o Vcc. (por ejemplo, 0V y 5V)

PUBLICIDAD: Encarga tus propias PCBs a media en PCBWAY

Para salvar esta limitación y simular una salida analógica la mayoría de los automatismos emplean un “truco”, que consiste en activar una salida digital durante un tiempo y mantenerla apagada durante el resto. El promedio de la tensión de salida, a lo largo del tiempo, será igual al valor analógico deseado.

Existe más de una forma de hacer esta aproximación. Una de las más sencillas, y por ello muy empleada en automatización, es la modulación de ancho de pulso (PWM). En esta modulación se mantiene constante la frecuencia (es decir, el tiempo entre disparo de pulsos), mientras que se hace variar la anchura del pulso.

PWM

La proporción de tiempo que está encendida la señal, respecto al total del ciclo, se denomina “Duty cycle”, y generalmente se expresa en tanto por ciento.

Es inmediato deducir que la señal promedio es el producto de la tensión máxima y el DutyCycle, según la siguiente expresión.

V_{medio}= \left ( V_{cc+} - V_{cc-} \right )\cdot \frac{DutyCycle}{100}


De forma similar, tenemos que

DutyCycle= 100 \cdot \frac{V_{medio}}{\left ( V_{cc+} - V_{cc-} \right )}


PWM no es una señal analógica

Es importante recordar en todo momento que en una salida PWM el valor de tensión realmente es Vcc. Por ejemplo, si estamos alimentando un dispositivo que necesita 3V, y usamos una pulsada, en realidad estaremos suministrando 5V durante un 60% del tiempo y 0V durante el 40%. Pero si el dispositivo, por ejemplo, soporta como máximo 3V, podemos dañarlo si lo alimentamos mediante un PWM.

Una señal pulsada es suficiente para emular una señal analógica en muchas aplicaciones. Por ejemplo, podemos variar la intensidad luminosa en un LED mediante un PWM. El LED realmente se enciende y apaga varias veces por segundo, pero este parpadeo es tan rápido que el ojo no lo aprecia. El efecto global percibido es que el LED brilla con menor intensidad.

Otro ejemplo, al variar la velocidad de un motor DC con un PWM, en la mayoría de los casos la inercia del motor se encargará de que el efecto del PWM sea despreciable. No obstante, en función de la frecuencia podemos notar vibraciones o ruidos, en cuyo caso deberemos variar la frecuencia del PWM.

Por otro lado, debemos tener en cuenta los efectos que supone la rápida conexión y desconexión de la señal pulsada puede suponer en el dispositivo alimentado. Por ejemplo, en el caso de cargas inductivas (motores, relés, o electroimanes) la desconexión supondrá la generación de voltaje inducido que puede dañar la salida digital o el propio dispositivo, por lo que será necesario disponer de las protecciones oportunas.

En cuanto a transistores, en general, los de tipo BJT resultan apropiados para funcionar como amplificación de señales PWM. Esto no suele ser así en los transistores MOS, donde los efectos capacitivos del mismo, unidos a la limitación de corriente de las salidas digitales, frecuentemente harán que necesitemos un driver de amplificación previo para evitar que el transistor trabaje en zona activa.

Usar de forma inadecuada una señal PWM puede dañar al dispositivo alimentado, si no soporta la tensión Vcc aplicada.

Salidas analógicas en Arduino

Arduino implementa por hardware salidas PWM en varios de sus pines, que aparecen identificados en la placa con el símbolo “~” junto al número del pin. También podemos emular por software señales PWM, pero con la carga de trabajo adicional que ello supone para el procesador.

En Arduino Uno, Mini y Nano, disponemos de 6 salidas PWM de 8bits en los pines 3, 5, 6, 9, 10 y 11.

En Arduino Mega disponemos de 15 salidas PWM de 8bis en los pines 2 a 13 y 44 a 46

Arduino Due cuenta con 13 salidas PWM de 8bits en los pins 2 a 13. Además, esta placa incorpora dos salidas analogicas discretizadas (DAC) con resolución de 12bits (4096 niveles)

Una resolución de 8bits en una salida PWM significa que tenemos 256 niveles. Es decir, indicamos el Duty cycle mediante un número de 0 a 255.

Los Timer en PWM por hardware

Las funciones PWM por hardware emplean los Timer para generar la onda de salida. Cada Timer da servicio a 2 o 3 salidas PWM. Para ello dispone de un registro de comparación por cada salida. Cuando el tiempo alcanza el valor del registro de comparación, la salida invierte su valor.

Cada salida conectada a un mismo temporizador comparte la misma frecuencia, aunque pueden tener distintos Duty cycles, dependiendo del valor de su registro de comparación.

Asociación de timers y PWM

En el caso de Arduino Uno, Mini y Nano

  • El Timer0 controla las salidas PWM 5 y 6.
  • El Timer1 controla las salidas PWM 9 y 10.
  • El Timer2 controla las salidas PWM 3 y 11.

Mientras que en Arduino Mega

  • El Timer0 controla las salidas PWM 4 y 13.
  • El Timer1 controla las salidas PWM 11 y 12.
  • El Timer2 controla las salidas PWM 9 y 10.
  • El Timer3 controla las salidas PWM 2, 3 y 5.
  • El Timer4 controla las salidas PWM 6, 7 y 8.
  • El Timer5 controla las salidas PWM 44, 45 y 46.

Frecuencia del PWM

La frecuencia de cada PWM depende de las características del temporizador al que está conectado, y de un registro de preescalado, que divide el tiempo por un número entero.

La frecuencia de los PWM se puede modificar cambiando el preescalado de los Timer correspondientes.

Arduino Uno, Mini y Nano disponen de tres temporizadoras.

  • Timer0, con una frecuencia de 62500Hz, y preescalados de 1, 8, 64, 256 y 1024.
  • Timer1, con una frecuencia de 31250Hz, y preescalados de 1, 8, 64, 256, y 1024.
  • Timer2, con una frecuencia de 31250Hz, y preescalados de 1, 8, 32, 64, 128, 256, y 1024.

Arduino Mega añade tres temporizadores más

  • Timer3, 4 y 5, con una frecuencia de 31250Hz, y preescalados de 1, 8, 64, 256, and 1024.

Por tan, la frecuencia estándar para las salidas PWM en Arduino Uno, Mini y Nano es de 490Hz para todos los pines, excepto para el 5 y 6 cuya frecuencia es de 980Hz

En cuanto a Arduino Mega, la frecuencia estándar es de 490Hz para todos los pines, excepto para el 4 y 13 cuya frecuencia es de 980Hz

Incompatibilidades

El uso de los Timer no es exclusivo de las salidas PWM, si no que es compartido con otras funciones. Emplear funciones que requieren el uso de estos Timer supondrá que no podremos emplear de forma simultánea alguno de los pines PWM.

A continuación alguna de las incompatibilidades más frecuentes

Servo

La librería servo hace un uso intensivo de temporizadores por lo que, mientras la estemos usando, no podremos usar algunas de las salidas PWM.

En el caso de Arduino Uno, Mini y Nano, la librería servo usa el Timer 1, por lo que no podremos usar los pines 9 y 10 mientras usemos un servo.

En el caso de Arduino Mega, dependerá de la cantidad de servos que empleemos.

  • Si usamos menos de 12 servos, usa el Timer 5, por lo que perderemos los pin 44, 45 y 46.
  • Para 24 servos, usa los Timer 1 y 5, por lo que perderemos los pin 11, 12, 44, 45 y 45.
  • Para 36 servos, usa los Timer 1,3 y 5, perdiendo los pin 2, 3, 5, 11, 12, 44, 45, 46.
  • Para 48 servos, usa los Timer 1, 3, 4 y 5, perdiendo todos los pin PWM.

Comunicación SPI

En Arduino Uno, Mini y Nano, el pin 11 se emplea también para la función MOSI de la comunicación SPI. Por lo tanto, no podremos usar ambas funciones de forma simultánea en este pin. Arduino Mega no tiene este problema, ya que figuran en pines distintos.

Función Tone

La función Tone emplea el Timer 2, por lo que no podremos usar los pines 3 y 11, y en Arduino mega los pines 9 y 10.

Esquema de montaje

Para este tutorial no es necesario ningún montaje. Sin embargo, podemos verificar el correcto funcionamiento de las salidas analógicas simplemente midiendo con un polímetro la tensión entre la salida digital y GND.

arduino-salida-analógica-esquema

Ejemplo de código

El código necesario para encender una salida PWM es muy sencillo gracias a las bibliotecas de Arduino, que configuran por defecto las salidas de PWM en la función Setup, ocultando la dificultad de manipulación de los Timer.

Así, en en el ejemplo mas básico, simplemente definimos el pin PWM que queremos emplear, y usamos la función analogWrite para escribir el valor del Duty Cycle, medido de 0 a 255.

El siguiente código incrementa progresivamente el valor de una señal analógica desde 0 a 255. Al alcanzar el valor máximo el contador pasará a 0, por lo que el ciclo volverá a iniciarse.

Para visualizar el código anterior podemos emplear un voltímetro o un LED colocado en el pin 11. Sin embargo, podemos modificar el código anterior con un pequeño truco, para traspasar el valor del PWM a otra señal, y así visualizarlo en el LED integrado en la placa en el pin 13.

No os centréis en la parte de interrupciones, si no sólo en la función Loop(). El resto del código es un poco complejo para esta entrada. Simplemente quedaros con que es un truco para mostrar un PWM en el LED integrado, y así hacer más fácil nuestras pruebas.

Finalmente, si juntamos el código anterior con lo que vimos en comunicación por puerto serie podemos hacer un programa que reciba un dígito de 0 a 9, y varíe la intensidad del LED integrado en la placa.

Si te ha gustado esta entrada y quieres leer más sobre Arduino puedes consultar la sección Tutoriales de Arduino
Previous Usar el emulador de Android de Visual Studio en Android Studio
Next Cumplimos 4 años

¡Deja un comentario!...

1000
newest oldest

Me estoy haciendo fan de tu blog. Me parece increiblemente bien detallado. Gracias por estos aportes.

Opino lo mismo que Luis Miguel!

Hola…Tengo una pregunta acerca de este tema; Lo que pasa es que estoy intentando controlar un servomotor con un arduino uno. He leido que la frecuencia del PWM que genera arduino es de aprox. 490 Hz pero las specs de mi servo dice que necesita que la frecuancia de 90-100 Hz. He leido acerca de como modificar este parametro por medio de los prescaler pero no he encontrado nada concreto ni codigo ejemplo etc. Espero que me puedas ayudar con esto 🙂

Hola, ¿Qué modelo de Servo estás usando? La mayoría de los servos funcionan a 50 Hz. Échale un ojo a la entrada “Controlar un servo con Arduino” https://www.luisllamas.es/controlar-un-servo-con-arduino/ Un saludo.

Buenas. Necesito controlar mediante un arduino un voltaje de entrada a un circuito rangos de 0v a 5v, ya que en función del voltaje de entrad actúa de una manera u otra. Con el PWM no sirve. ¿Qué me recomiendas ya que el arduino no tiene salida analógica?
Gracias

Te aconsejaría usar un DAC.
Mira la entrada “SALIDA ANALÓGICA REAL CON ARDUINO Y DAC DE 12BITS MCP4725” https://www.luisllamas.es/salida-analogica-real-con-arduino-y-dac-de-12bits-mcp4725/

Hola, Luis.

En un principio entendía la salida PWM como una salida analógica; pero, viendo con una SD la posibilidad de sonidos wav o mp3, suenan de pena; no es cierto? Lo estoy intentando con la TMRpcm.h.

La mejor posibilidad sería un DAC, que interprete la PWM pseudo-analógica (TTL?) a algo entendible para la salida audio; qué sería lo más sencillo, como circuito, para ver si merece la pena?

Es que, si no, una MP3 shield lo SD sería posiblemente mas rentable…

Muchas gracias

Arduino no es un procesador adecuado para reproducir sonido (ni mp3, ni siquiera wav). Aunque puedas conseguir algo a base de hacer virguerías y metiéndolo “con calzador”, al final se reduce a… no es el procesador adecuado.
Es mucho mejor meterle un reproductor como DFPlayer mini, barato, más fácil, y dejas a Arduino que haga “sus cosas” de autómata
https://www.luisllamas.es/arduino-mp3-dfplayer-mini/

Gracias por quitarme el trauma, oye; como músico, me motivó el cajón-e para entrar a este mundo, y algo va la pareja UNO + musical instrument shield (Sparkfun, cara), con el VS1053 (Banco de sonidos MIDI) y sensores piezo… Pero empecé con la Leonardo (Incompatible con la MIS, trauma inicial) y la intento aprovechar ahora junto al HC-SR04 + SD Catalex para hacer un Theremin, YA tenía fichada la DFPlayer; pero como hay muchos ejemplos Wav + PWM en la red, en los que simplemente añaden un filtro R+C al altavoz, casi que te crees que tiene que funcionar… Aún… Read more »
Juan Carlos Peña Garcia

Hola Luis: Por ahora no tengo preguntas, raro no? pero aprovecho para felicitarte de nuevo. Cada vez que entro aquì salgo muy satisfecho con los tutoriales y las explicaciones.
Sigue asì. Muchas gracias por ayudarnos.

Gracias por tu explicación Luis. ¿Acá también aplicaría lo de siempre conectar una resistencia de 300 ohmios a la salida (del PWM)? Gracias.

El valor de la resistencia dependerá de la carga que conectes, pero sí, nunca debes poner una carga una fuente de tensión sin una resistencia.

Bueno, en primer lugar, no tengo ni idea de que es un SLD :D. En cualquier caso 1) Si tu dispositivo tiene como máximo 1.4V, no debes alimentarlo con un PWM 2) La resistencia no limita la tensión, limita la corriente 3) 1.4V es un voltaje bastante bajo. 4) 0.9-1A es una intensidad muy alta. En resumen, que lo que quieres no es tan fácil como pueda parecer. En un caso normal, te recomendaría una solución con un opAmp o una etapa de transistores, pero requiere que te diseñes tu propio circuito. Si no te apetece, una solución “sencilla” es… Read more »

Has escrito Si usamos menos de 12 servos, usa el Timer 5, por lo que no perderemos los pin 44, 45 y 46. será que SI perderemos, hay que quitar el NO como el resto de frases.

El primer ejemplo utilizando solo analogWrite hablas que varia de o a 255 y vuelve a 0 cuando se desborda el contador… pero en el programa la variable outputValue++; siempre está creciendo…