Tutorial para generar señales PWM con Arduino

Gracias por leer este Tutorial para generar señales PWM con Arduino, una señal PWM o Pulso con modulación puede ser implementado en arduino de diferentes maneras. En este artículo se explicará una simple técnica para generar un PWM directamente desde los registros, de esta manera se obtiene un mayor control de la frecuencia y el Duty cicle.

con modulación (PWM) puede ser implementado en arduino de diferentes maneras. En este artículo se explicará una simple técnica para generar un PWM directamente desde los registros, de esta manera se obtiene un mayor control de la frecuencia y el Duty cicle.

Pulso con modulación (PWM) puede ser implementado en arduino de diferentes maneras. En este artículo se explicará una simple técnica para generar un PWM directamente desde los registros, de esta manera se obtiene un mayor control de la frecuencia y el Duty cicle.

Para este ejemplo nos vamos a centrar en la placa de desarrollo Arduino nano, la cual incorpora un microcontrolador ATmega328

Que es un señal PWM?

Antes de continuar, vamos a ver que es una señal PWM y algunos posibles use cases.  Una señal PWM consta de dos parámetros fundamentales, que son: la frecuencia PWM y el ciclo de trabajo o duty cycle. Es posible generar señales PWM modificando cualquiera de estos parámetros, podemos mantener un Duty cicle fijo y variar la frecuencia entre en una frecuencia PWM mínima y una frecuencia PWM máxima o bien mantener una frecuencia fija e ir variando el Duty cicle de esta frecuencia.

PWM Duty Cicle

En este Tutorial generar señales PWM con Arduino, vamos a mantener una frecuencia fija e iremos variando el Duty cicle según nuestra necesidad,  con esta técnica de generación de señales PWM podemos dimear un simple LED, variar la velocidad de un motor, general señales de audio, etc… El objetivo final de esta técnica es aplicar una frecuencia de trabajo al elemento a controlar (por ejemplo un LED) y variando el ciclo de trabajo conseguimos variar el voltaje que se le suministra al LED en este caso. Consiguiendo un efecto dimmer en el LED.

Generación simple de señales PWM en Arduino

Arduino dispone de una función para la generación de una señal PWM de manera muy simple, esta funcion nos puede ser muy util si no necesitamos grandes requisitos, para ello se puede utilizar la función analogWrite (pin, dutuCycle).  En el parámetro pin le pasaremos el pin de arduino donde queremos generar la señal y el parámetro dutyCycle le pasaremos un valor entre 0 y 255 el cual corresponde con el porcentaje del duty cicle.

Los pines disponibles para generar una señal PWM en arduino nano son  (3, 5, 6, 9,10 y 11).

Definicion pines Arduino PWM Pinout

Siguiendo con el ejemplo del LED, vamos a hacer un dimmer, para ello conectamos un potenciómetro en el pin A0 y conectamos un led en el pin D3, mediante el potenciómetro podremos variar la intensidad del led.

Esquematico Arduino Led Dimmer

Como es habitual, se definen los pines de entrada y salida, y utilizamos la función analogRead () para generar nuestra señal PWM

int potenciometerPin = A0;    // select the input pin for the potentiometer
int ledPin = 3;               // select the pin for the LED
int potenciometerValue = 0;   // variable to store the value coming from the potenciometer

void setup() {
  
  pinMode(ledPin, OUTPUT);    // declare the ledPin as an OUTPUT:
}

void loop() {
 
  potenciometerValue = analogRead(potenciometerPin);   // read the value from the sensor
  analogWrite(ledPin, potenciometerValue / 4);          // Set PWM dutyCicle acording Potenciometer

}

Puedes descargar el codigo de este tutorial para generar señales PWM con Arduino desde mi repositorio

Con esta función es forma muy simple de generar una señal PWM, hay remarcar que no podemos variar la frecuencia PWM que ya viene pre-configurada en Arduino, en la tabla están las frecuencias PWM por defecto, si estas frecuencias no son adecuadas para nuestro propósito, existe una manera de variar la frecuencia a nuestra necesidad, se trata de manipular directamente los registros de configuración de Arduino para obtener la frecuencia y modo de funcionamiento que nos interese.

TimerDefault PWM Freq
Timer0490.20 Hz
Timer1976.56 Hz
Timer2490.20 Hz

Generar señales PWM mediante los registros de ATmega328  – ArduinoNano

Sigue leyendo este Tutorial para generar señales PWM con Arduino, para generar señales PWM, lo primero que se necesitan son los Timers, el Atmega328P dispone de 3 timers para generar hasta 6 salidas PWM. Cada uno de los 3 timers está asociado a dos pines de salida

TimerPinBitsUtilizacion
Timer06 y 58micros()
milis()
delay()
...
Timer19 y 1016Servos
Timer211 y 3 8Tone()

Cada Timer dispone de dos registros Output Compare, estos registros son los encargados de controlar las salidas PWM. Cuando el valor del Timer alcanza el valor del registro Output compare, su pin asociado cambiará de estado. Las dos salidas asociadas a cada Timer tendrán la misma frecuencia, pero el duty cicle podrá ser diferente.

Los timers utilizan la señal de reloj (Clock) de arduino y esta señal se pasa por un prescaler (1, 8, 64,256 o 1024) para los timers 0 y 1, y (1, 8, 32, 64, 128,256 o 1024) para el Timer 2.

La tabla siguiente muestra las salidas y pines asociados a los 6 registros Output Compare

TimerTimer OutputArduino Pin
Timer0OC0A6
OC0B5
Timer1OC1A9
OC1B10
Timer2OC2A11
OC2B3

Timer 2,  Registros asociados a la generación de señales PWM

Aunque los 3 timers que dispone el Atmega328 tienen algunas diferencias, el funcionamiento es prácticamente el mismo, en este apartado entraré en detalle en el timer2 y haremos el mismo ejemplo pero modificando los registros directamente, para los timer0 y timer1 mirar el datasheet para ver sus particularidades.

Una de los principales motivos por los cuales necesitaríamos modificar los registros es para poder ajuntar la frecuencia PWM. De manera predeterminada, Arduino ya la trae prefijada según el Timer o salida PWM que utilicemos.

Para poder generar una señal PWM, primero debemos configurar el modulo, en este caso el Timer 0,  la configuración de este Timer se realiza mediante los registros TCCR2A y TCCR2B.

Es este articulo no trataremos la gestion de las interrupciones, si quieres saber mas, mira esta entrada, para generar señales PWM, bajo mi punto de vista no es necesario añadir interrupciones, aunque cada uno es libre de hacer lo que crea oportuno.

TCCR2ACOM2A1COM2A0COM2B1COM2B0--WGM21WGM20
TCCR2BFOC2AFOC2B--WGM22CS22CS21CS20

COMA2:1  –> Configura la salida A (pin 11), invertida o no invertida

COMB2:1  –> Configura la salida B (Pin 3), invertida o no invertida

WGM20:2 –> Selecciona el modo de funcionamiento (Waveform Generation mode bit)

CS20:1 –> Selección del prescaler para la señal Timer Clock

FOC2A: B –> No utilizado en modo PWM, poner a 0

 Una vez configurado, se deben cargar los valores correspondientes a los duty cicle para que empiece la fiesta… los registros  son:

OCR2A y OCR2B.

Configuración de las salidas – Registros COM2A0:1 – COM2B0:1

La configuración de las salidas, depende del modo de funcionamiento que seleccionemos, básicamente podemos diferenciar entre 2 modos, Fast PWM y Phase Correct PWM, lo que hace esta configuración es seleccionar la polaridad de las salidas es decir, poner 0 o 1 cuando se alcanzan los valores de duty cicle, o dicho de otra manera, seleccionar el modo no invertido o modo invertido.

TCCR0A- Compare Output Mode, Fast PWM Mode
COM0A1COM0A0
00Normal port operation, OC0A disconnected.
01WGM02 = 0: Normal port operation, OC0A disconnected.
WGM02 = 1: Toggle OC0A on compare match.
10Clear OC0A on compare match (non-inverting mode).
11Set OC0A on compare match (inverting mode).
COM0B1COM0B0
00Normal port operation, OC0B disconnected.
01Reserved
10Clear OC0B on compare match, set OC0B at BOTTOM, (non-inverting mode).
11Set OC0B on compare match, clear OC0B at BOTTOM, (inverting mode).
TCCR0A- Compare Output Mode, Phase Correct PWM Mode
COM0A1COM0A0
00Normal port operation, OC0A disconnected.
01WGM02 = 0: Normal port operation, OC0A disconnected.
WGM02 = 1: Toggle OC0A on compare match.
10Clear OC0A on compare match when up-counting. Set OC0A on compare match when down-counting.
11Set OC0A on compare match when up-counting. Clear OC0A on compare match when down-counting.
COM0B1COM0B0
00Normal port operation, OC0B disconnected.
01Reserved
10Clear OC0B on compare match when up-counting. Set OC0B on compare match when down-counting.
11Set OC0B on compare match when up-counting. Clear OC0B on compare match when down-counting.

Modos de funcionamiento – Registros WGM20:2

Normal Mode – Non PWM:

                Este modo de funcionamiento requiere de interrupciones para un mejor control de la señal, el funcionamiento básico de este modo es que el registro contador de Timer  (TCNT2) se incrementa con cada Timer Clock, cuando el valor de TCNT2 alcanza 0xFF se genera una interrupción por overflow (TOV2), esta interrupción se ha de tratar por SW en su rutina correspondiente.  El contador del Timer TCNT2 vuelve a iniciar la cuenta desde 0x00.

Este modo de funcionamiento no se considera una operación PWM, ya que el Timer se utiliza como un mero contador

Clear Timer on Compare Mach (CTC) – Non PWM

Este modo es una evolución del normal mode, en el registro OCR2A se carga un valor de 8 bits que corresponde al porcentaje del duty cicle de la señal, el Contador del Timer (TCNT2) se incrementa con cada Timer Clock, una vez que TCNT2 alcanza el valor cargado en OCR2A, TCNT2 se resetea y comienza a contar de nuevo desde 0x00.

Este modo de funcionamiento no se considera una operación PWM, ya que este modo es un Timer o temporizador.

Fast PWM mode

Es el modo más simple de generar una señal PWM, el contador del Timer TCNT2 cuenta repetidamente desde 0x00  hasta 0xFF,  en el registro OCR2x se cargan los valores correspondientes al porcentaje del duty cicle, cuando el contador TCNT2 alcanza el valor cargado en OCR2x su salida cambia de estado en función si tenemos configurado el modulo como una salida no invertida o una salida invertida. Una vez el contador TCNT2 alcanza el valor 0xFF, este se resetea a 0x00 y la salida vuelve a cambiar de estado.

La fórmula para calcular la Frecuencia PWM  para el mode 3 es la siguiente:

                FPWM = Fosc / (N x (TOP +1))

                Fosc –> Frecuencia de oscilación (16Mhz en Arduino)

                N –> Valor prescaler

                TOP –> 0xFF

La fórmula para calcular la Frecuencia PWM  para el mode 7 es la siguiente:

                FPWM = (Fosc / (N x (TOP +1)))/2

                Fosc –> Frecuencia de oscilación (16Mhz en Arduino)

                N –> Valor prescaler

                TOP –> Valor del duty cicle (OCR2A)

Phase Correct PWM Mode

En este modo PWM, el contador TCNT2 se incrementa desde 0x00 hasta 0xFF con cada Timer Clock, una vez ha alcanzado 0xFF, el contador se decrementa hasta alcanzar 0x00 y vuelve a empezar repetidamente.

Durante la cuenta ascendente, la salida cambiará de estado cuando TCNT2 sea igual al valor de OCR2x y volverá a cambiar el estado de la salida cuando en la cuenta atrás los valores de TCNT2 y OCR2x vuelvan a coincidir.

La fórmula para calcular la Frecuencia PWM  para el mode 1 es la siguiente:

                FPWM = Fosc / (N x TOP)

                Fosc –> Frecuencia de oscilación (16Mhz en Arduino)

                N –> Valor prescaler

                TOP –> (0xFF * 2) –> 0x1FE –> 510 dec.

La fórmula para calcular la Frecuencia PWM  para el mode 5 es la siguiente:

                FPWM = (Fosc / (N x (TOP*2)))/2

                Fosc –> Frecuencia de oscilación (16Mhz en Arduino)

                N –> Valor prescaler

                TOP –> Valor del duty cicle (OCR2A)

Los modos de funcionamiento se pueden ver resumidos en la siguiente tabla:

ModeWGM22WGM21WGM20Modo de OperaciónValor TOP
0000Normal (Contador)0xFF
1001PWM Fase correct0XFF
2010CTC (Timer)OCRA
3011FAST PWMOxFF
4100Reserved-
5101PWM Fase correctOCRA
6110Reserved-
711FAST PWMOCRA

Selección del prescaler – CS20:1

En la siguiente tabla se muestra los posibles valores de prescaler para generar la señal Timer Clock, recordar que el Timer 2 tiene valores de prescaler diferentes.

CS22CS21CS20Descripcion
000Sin fuente de reloj - Timer stop
001Clk sin prescaler
010Clk prescaler 8
011Clk prescaler 32
100Clk prescaler 64
101Clk prescaler 128
110Clk prescaler 256
111Clk prescaler 1024

Manos a la obra!!!

Manteniendo el circuito con el potenciómetro y el led, vamos a modificar los registros de TMR2 para configurarlo de tal manera que genere una señal PWM y con el potenciómetro podamos dimear el Led.

Vamos a seleccionar el modo FAST PWM Mode 3, seleccionamos un valor de preescaler N=8 y configuramos las salidas como no invertidas.  Para esto se deben modificar los registros  TCCR2A y TCCR2B con los siguientes Valores:

TCCR2ACOM2A1COM2A0COM2B1COM2B0--WGM21WGM20
001011
TCCR2BFOC2AFOC2B--WGM22CS22CS21CS20
000010

Y en el registro OCR2B cargaremos el valor del duty cicle, los bits COM2A0-1 y el registro OCR2A, lo dejamos a cero ya son los que controlan el pin 11, y nosotros tenemos conectado el led al pin 3.

int potenciometerPin = A0;    // select the input pin for the potentiometer
int ledPin = 3;               // select the pin for the LED
int potenciometerValue = 0;   // variable to store the value coming from the potenciometer

void setup() {
pinMode(ledPin, OUTPUT);    // declare the ledPin as an OUTPUT
  TCCR2A = 0;
  TCCR2B = 0;

  TCCR2A |= ( 0 << COM2A1);
  TCCR2A |= ( 0 << COM2A0);
  TCCR2A |= ( 1 << COM2B1);
  TCCR2A |= ( 0 << COM2B0);
  TCCR2A |= ( 1 << WGM21);
  TCCR2A |= ( 1 << WGM20);
  
  TCCR2B |= (0 << FOC2A);
  TCCR2B |= (0 << FOC2B);
  TCCR2B |= (0 << WGM22);
  TCCR2B |= (0 << CS22); 
  TCCR2B |= (1 << CS21); 
  TCCR2B |= (0 << CS20); 
  
  TCNT2  = 0;
  OCR2A = 0;
}

void loop() {
  potenciometerValue = analogRead(potenciometerPin);   // read the value from the sensor
  OCR2A = potenciometerValue/4;
}

Descargate el codigo en este link.

Dejar una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Aviso sobre Cookies en WordPress por Real Cookie Banner