Está en la página 1de 13

9- PWM

Ing. Juan Ramon Terven Salinas 139


9 MODULACIN DE ANCHO DE PULSO (PWM)


La tcnica de PWM consiste en producir un pulso rectangular con un ciclo de
trabajo determinado, este ciclo de trabajo puede variar de 0 a 100%. En la Figura 9-1 se
muestra un pulso con un ciclo de trabajo del 50%, es decir Ton/T = 0.5.

Figura 9-1. Ciclo de trabajo de 50% [16]

En la Figura 9-2 se muesta un pulso con un ciclo de trabajo del 10%; Ton/T = 0.1.

Figura 9-2. Ciclo de trabajo del 10% [16]

Un ciclo de trabajo del 0% significa que la seal siempre est nivel bajo; y un ciclo
de trabajo del 100% significa la seal siempre en nivel alto, el nmero de casos
intermedios posibles es un nmero finito llamado resolucin del PWM y se expresa
como Log
2
(nmero de casos). Por ejemplo si puede haber 256 ciclos de trabajo posibles
se dice que el PWM tiene una resolucin de 8 bits.

Si conectamos una seal rectangular a un analizador de espectros para ver su
contenido de frecuencias, veramos que est formada por tres partes (Figura 9-3):
- Una componente de DC, cuya amplitud es proporcional al ciclo de trabajo.
- Una sinusoide en la frecuencia fundamental (f=1/T).
- Un nmero infinito de armnicas cuyas frecuencias son mltiplos de la
fundamental (2f, 3f, 4f, 5f, 6f, ).
9- PWM
Ing. Juan Ramon Terven Salinas 140

Figura 9-3. Espectro de la seal PWM

De tal forma que si conectamos un filtro ideal pasa bajas a la salida del PWM
para remover todas las frecuencias de la fundamental para arriba, obtendramos un seal
de CD limpia, cuya amplitud sera directamente proporcional al ciclo de trabajo. Aqu
radica la importancia del PWM.
Podemos aproximar este filtro pasabajas con un simple filtro pasivo RC (de primer
orden) o un filtro activo de un orden superior. En la Figura 9-4 se muestra la
componente de CD (lnea punteada) para una seal con un ciclo de trabajo de 50% y
otra con un ciclo de trabajo de 10%.


Figura 9-4. Salida analogica del PWM y el filtro pasa bajas
9- PWM
Ing. Juan Ramon Terven Salinas 141
Mdulo Output Compare (OC)
La familia PIC32 posee un mdulo llamada Output Compare, el cual es usado para
generar un pulso o un tren de pulsos en respuesta a eventos seleccionados [10] . Este
mdulo tiene varios modos de funcionamiento, entre ellos uno llamado Modo PWM en
el cual el PIC32 genera un pulso rectangular con un ciclo de trabajo establecido por
nuestro cdigo.
9.1.1 Pasos para configurar el modo PWM

1. Ajuste el periodo del PWM escribiendo en el registro de periodo del timer
seleccionado (PRx). (se puede usar el Timer2 o el Timer3)
2. Ajuste el ciclo de trabajo del PWM escribiendo en el registro OCxRS.
3. Escriba el registro OCxR con el ciclo de trabajo inicial.
4. Habilite las interrupciones para el timer usado y el mdulo OCx usado (en caso de
ser necesarias). La interrupcin del mdulo OC es necesaria para el modo PWM con
proteccin de falla.
5. Configure el mdulo Output Compare para algn modo de operacin de PWM
escribiendo en los bits OCM (OCxCON<2:0>).
6. Seleccione el Timer a usar en el bit OCTSEL (OCxCON<3>). Si OCTSEL = 0, se
usa el Timer2, si OCTSEL = 1 se usa el Timer3.
7. Ajuste el prescaler del TMRx y habilitelo activando el bit TON (TxCON<15>).

Tome en cuenta lo siguiente:
El registro OCxR debe ser inicializado antes de que el mdulo Output
Compare sea habilitado.
El registro OCxR se convierte de solo-lectura cuando el mdulo Output
Compare opera en modo PWM.
El valor en OCxR se convierte en el ciclo de trabajo del primer periodo del
PWM.
El contenido del registro OCxRS se transfiere a OCxR cuando ocurre una
coincidencia del Timer.

En la Figura 9-5 se muestra el funcionamiento del PWM del mdulo Output Compare.
9- PWM
Ing. Juan Ramon Terven Salinas 142


Figura 9-5. Funcionamiento del PWM [10]

1) El Timer
x
es puesto en 0 y se carga un nuevo ciclo de trabajo de OCxRS a OCxR.
2) El valor del Timer iguala al valor de OCxR, el pin OCx pasa a nivel bajo.
3) El Timer
x
termina de contar (iguala a PR
x
), se carga el valor de OCxRS a OCxR, el
pin OCx pasa a nivel alto. Se genera una interrupcin del Timer
x
.

Ejemplo 1. Generacin de voltaje analgico usando el mdulo OC en
modo PWM.
En este ejemplo se configura el registro de periodo del Timer3 con un valor de
2000, este valor a su vez representa la resolucin del PWM, ya que podemos tener 2000
valores de voltajes diferentes. Si nuestro PBCLK es de 80MHz, entonces tendremos un
pulso rectangular de 5kHz, podemos conectar un filtro pasabajas a la salida del PWM
como se muestra en la Figura 9-6. El filtro pasabajas de la figura tiene una frecuencia de
corte de 15.9 Hz atenuando de manera efectiva los componentes armnicos del PWM.


Figura 9-6. Filtro Pasa bajas a la salida del PWM

De esta manera podemos usar el PWM como un convertidor digital-anlogo o DAC.

9- PWM
Ing. Juan Ramon Terven Salinas 143

Programa 9-1. Salida de voltaje analgico
/*
* Uso del modulo Output Compare en modo PWM
* Utiliza el OC1, sale por el pin RD0
*/

#include <p32xxxx.h>
#include <plib.h>

//Bits de configuracion
#pragma config POSCMOD = HS, FNOSC = PRIPLL, FPLLMUL = MUL_20
#pragma config FPLLIDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FPBDIV = DIV_1, FWDTEN = OFF, UPLLEN = ON
#pragma config UPLLIDIV = DIV_2, FVBUSONIO = ON, FUSBIDIO = ON
#pragma config FSOSCEN = OFF, CP = OFF, FCKSM = CSECMD

//PBCLK = 80MHz
#define FPB 80000000L

int main(void)
{
//Frecuencia del PWM
int freqPWM = 10000;

// inicializa el modulo OC1 con Timer2
OpenOC1( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);

// inicializa Timer2 y PR2
//La siguiente funcin inicializa el valor de PR2 = FPB/freqPWM
//en este ejemplo PR2 = 80,000,000/10,000 = 8000
//Esto quiere decir que tenemos 8000 ciclos de trabajo distintos
OpenTimer2( T2_ON | T2_PS_1_1 | T2_SOURCE_INT,FPB/freqPWM);

//Ajusta el ciclo de trabajo al 50%, es decir OC1RS = 4000
OC1RS = PR2/2;

while(1);
return 0;
}

9- PWM
Ing. Juan Ramon Terven Salinas 144
Ejemplo 2. Generacin de una seal diente de sierra
El ejemplo anterior provoca un voltaje fijo por el pin RD0, sin embargo podemos
hacer que este voltaje cambie con el tiempo. Podemos aprovechar la rutina de
interrupcin del Timer usado para cambiar el ciclo de trabajo del PWM como se
muestra en el siguiente ejemplo.

Programa 9-2. Generacin de seal diente de sierra
/*
* Uso del modulo Output Compare en modo PWM
* para generar una seal diente de sierra
* Utiliza el OC1, sale por el pin RD0
*/

#include <p32xxxx.h>
#include <plib.h>

//Bits de configuracion
#pragma config POSCMOD = HS, FNOSC = PRIPLL, FPLLMUL = MUL_20
#pragma config FPLLIDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FPBDIV = DIV_1, FWDTEN = OFF, UPLLEN = ON
#pragma config UPLLIDIV = DIV_2, FVBUSONIO = ON, FUSBIDIO = ON
#pragma config FSOSCEN = OFF, CP = OFF, FCKSM = CSECMD

//PBCLK = 80MHz
#define FPB 80000000L

//Frecuencia del PWM
#define freqPWM 10000

// VARIABLES GLOBALES
//Periodo del PWM (FPB/freqPWM = 8000)
short valorMax = FPB/freqPWM;

//Contador usado para generar el diente de sierra
short count = 0;

int main(void)
{
// inicializa el modulo OC1 con Timer2
OpenOC1( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);

// inicializa Timer2 y PR2
//La siguiente funcin inicializa el valor de PR2 = FPB/freqPWM
//en este ejemplo PR2 = 80,000,000/10,000 = 8000
//Esto quiere decir que el diente de sierra subira
//desde 0 hasta 8000 (valorMax)
OpenTimer2( T2_ON | T2_PS_1_1 | T2_SOURCE_INT,valorMax);

//Ajusta la interrupcin de Timer2 con prioridad de 2
IPC2bits.T2IP = 2; //prioridad 2
IPC2bits.T2IS = 1; //subprioridad 1
IFS0bits.T2IF = 0; //Limpia la bandera de interrupcion
// Activa el modo MultiVectored
INTEnableSystemMultiVectoredInt();
9- PWM
Ing. Juan Ramon Terven Salinas 145
IEC0bits.T2IE = 1; //Activa la interrupcion del Timer2

//Ajusta el ciclo de trabajo incial a 0%, es decir OC1RS = 0
OC1RS = 0;

while(1);
return 0;
}


//RUTINA DE INTERRUPCIN DE TIMER2
//Cambia el ciclo de trabajo del PWM para generar un diente de sierra
//de 125Hz (1/8ms)
//Esta interrupcin se ejecuta cada 100us, y el voltaje
//sube linealmente desde 0 hasta el mximo en 80 interrupciones
//por lo tanto el periodo del diente de sierra es de 8ms (80 x 100us)
void __ISR(_TIMER_2_VECTOR, ipl2) Timer2Handler(void)
{
//Ajusta el Nuevo ciclo de trabajo
OC1RS = count;

count+=100;
//Si el contador llega a valorMax, regresa a 0
if (count >= valorMax)
count = 0;

//Limpia la bandera de interrupcion del Timer2
IFS0bits.T2IF = 0;
}

Esta rutina producir una seal diente de sierra de aproximadamente V
DD
de
amplitud con una rampa gradual del ciclo de trabajo de 0 a 100% en 80 pasos, seguida
de una caida abrupta a 0. Esta seal tendr una frecuencia de 125 Hz.


9- PWM
Ing. Juan Ramon Terven Salinas 146
Ejemplo 3. Generacin de un Senoidal
El siguiente ejemplo es idntico al anterior solo cambia la rutina de interrupcin en
la cual se usa la funcin sin de la librera math.h para generar cada valor de voltaje
de una seal senoidal.
Programa 9-3. Generacin de una seal senoidal usando PWM
/*
* Uso del modulo Output Compare en modo PWM
* para generar una seal senoidal
* Utiliza el OC1, sale por el pin RD0
*/

#include <p32xxxx.h>
#include <plib.h>
#include <math.h>

//Bits de configuracion
#pragma config POSCMOD = HS, FNOSC = PRIPLL, FPLLMUL = MUL_20
#pragma config FPLLIDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FPBDIV = DIV_1, FWDTEN = OFF, UPLLEN = ON
#pragma config UPLLIDIV = DIV_2, FVBUSONIO = ON, FUSBIDIO = ON
#pragma config FSOSCEN = OFF, CP = OFF, FCKSM = CSECMD

//PBCLK = 80MHz
#define FPB 80000000L

//Frecuencia del PWM
#define freqPWM 10000;

//Periodo del PWM (FPB/freqPWM = 8000)
short valorMax = FPB/freqPWM;

//Contador usado para generar la seal senoidal
short count = 0;

int main(void)
{
// inicializa el modulo OC1 con Timer2
OpenOC1( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);

// inicializa Timer2 y PR2
//La siguiente funcin inicializa el valor de PR2 = FPB/freqPWM
//en este ejemplo PR2 = 80,000,000/10,000 = 8000
OpenTimer2( T2_ON | T2_PS_1_1 | T2_SOURCE_INT,valorMax);

//Ajusta la interrupcin de Timer2 con prioridad de 2
IPC2bits.T2IP = 2; //prioridad 2
IPC2bits.T2IS = 1; //subprioridad 1
IFS0bits.T2IF = 0; //Limpia la bandera de interrupcion
// Activa el modo MultiVectored
INTEnableSystemMultiVectoredInt();
IEC0bits.T2IE = 1; //Activa la interrupcion del Timer2

//Ajusta el ciclo de trabajo incial a 0%, es decir OC1RS = 0
OC1RS = 0 ;

while(1);
9- PWM
Ing. Juan Ramon Terven Salinas 147
return 0;
}


//RUTINA DE INTERRUPCIN DE TIMER2
//Cambia el ciclo de trabajo del PWM para generar una senoidal
//de 100Hz (1/10ms)
//Esta interrupcin se ejecuta cada 100us, y el voltaje
//cambia senoidalmente generando un periodo completo cada
//100 interrupciones (2pi/100 = pi/50)
//por lo tanto el periodo de la senoidal 10ms (100 x 100us)
void __ISR(_TIMER_2_VECTOR, ipl2) Timer2Handler(void)
{
// calcula el nuevo valor de la senoidal
OC1RS = PR2/2 + PR2/2 * sin(M_PI/50*count);
count++;

//Limpia la bandera de interrupcion del Timer2
IFS0bits.T2IF = 0;
}

La funcin seno de la librera math.h tarda bastante tiempo en ser calculada (unos
cuantos milisegundos), de tal manera que si se desea generar una senoidal de alta
frecuencia no es recomendable usar la funcin de la librera. En su lugar, podramos
generar un arreglo con los valores del seno y simplemente mandarlos llamar.

9- PWM
Ing. Juan Ramon Terven Salinas 148
Ejemplo 4. Generacin de una seal senoidal usando una tabla de
datos
Para el siguiente ejemplo se uso una hoja de clculo para generar una tabla de 100
valores que representan 1 ciclo de una seal senoidal. Estos valores se mapearon a un
rango de 0 a 160, en donde 160 ser el valor del 100% del ciclo de trabajo (PR1 = 160).


Figura 9-7. Generacin de datos

Una vez teniendo los datos se pasan a una tabla que se almacena en la memoria Flash
del PIC32 y dentro de la RSI del TMR2 se usa cada uno de estos valores para generar
una senoidal de aproximadamente 1kHz.
Observe que podemos usar la memoria de programa (Flash) para almacenar datos
constantes y asi no malgastar la preciada memoria RAM. Para hacer esto simplemente
declare su variable de tipo constante con el modificador const y el compilador
automticamente la guarda en memoria Flash.
9- PWM
Ing. Juan Ramon Terven Salinas 149
Programa 9-4. Generacin de senoidal a partir de una tabla de datos
/*
* Uso del modulo Output Compare en modo PWM
* para generar una seal senoidal a partir de
* una tabla de datos
* Utiliza el OC1, sale por el pin RD0
*/

#include <p32xxxx.h>
#include <plib.h>
#include <math.h>

//Bits de configuracion
#pragma config POSCMOD = HS, FNOSC = PRIPLL, FPLLMUL = MUL_20
#pragma config FPLLIDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FPBDIV = DIV_1, FWDTEN = OFF, UPLLEN = ON
#pragma config UPLLIDIV = DIV_2, FVBUSONIO = ON, FUSBIDIO = ON
#pragma config FSOSCEN = OFF, CP = OFF, FCKSM = CSECMD

//PBCLK = 80MHz
#define FPB 80000000L

//Contador usado para generar la seal senoidal
short count = 0;

//Tabla de datos, representa 1 ciclo completo de una seal senoidal
const short tabla[100] = {
80,85,90,95,100,105,109,114,119,123,127,131,135,138,142,145,148,150,15
2,154,156,157,159,159,160,160,160,159,159,157,156,154,152,150,148,145,
142,138,135,131,127,123,119,114,109,105,100,95,90,85,80,75,70,65,60,55
,51,46,41,37,33,29,25,22,18,15,12,10,8,6,4,3,1,1,0,0,0,1,1,3,4,6,8,10,
12,15,18,22,25,29,33,37,41,46,51,55,60,65,70,75};


int main(void)
{
// inicializa el modulo OC1 con Timer2
OpenOC1( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);

// inicializa Timer2 y PR2
//La siguiente funcin inicializa el valor de PR2 = 160
OpenTimer2( T2_ON | T2_PS_1_1 | T2_SOURCE_INT,160);

//Ajusta la interrupcin de Timer2 con prioridad de 2
IPC2bits.T2IP = 2; //prioridad 2
IPC2bits.T2IS = 1; //subprioridad 1
IFS0bits.T2IF = 0; //Limpia la bandera de interrupcion
// Activa el modo MultiVectored
INTEnableSystemMultiVectoredInt();
IEC0bits.T2IE = 1; //Activa la interrupcion del Timer2

//Ajusta el ciclo de trabajo incial a 0%, es decir OC1RS = 0
OC1RS = 0;

while(1);
return 0;
}


//RUTINA DE INTERRUPCIN DE TIMER2
//Cambia el ciclo de trabajo del PWM para generar una senoidal
9- PWM
Ing. Juan Ramon Terven Salinas 150
//de 5kHz (1/200us)
//Esta interrupcin se ejecuta cada 2us, y el voltaje
//cambia senoidalmente generando un periodo completo cada
//100 interrupciones
//por lo tanto el periodo de la senoidal es de 200us (2us x 100)
void __ISR(_TIMER_2_VECTOR, ipl2) Timer2Handler(void)
{
// Obtiene el nuevo valor de la senoidal
// de la tabla de datos
OC1RS = tabla[count];
count++;

//Si llega al final del arreglo, reinicia
if (count > 99)
count = 0;


//Limpia la bandera de interrupcion del Timer2
IFS0bits.T2IF = 0;
}


Generacin de Audio
Podemos aprovechar el ejemplo anterior y conectar una bocina a la salida del PWM
para escuchar el tono lmpio de una senoidal de 5kHz.
Podriamos agregarle amplificador operacional y un potencimetro que varie la ganancia
para que funcione como control de volumen. Sin embargo un amplificador operacional
no es capaz por si solo de entregar corrientes muy grandes por la salida, por lo que no
podemos conectarles directamente un altavoz y oir el tono; necesitamos entonces aadir
algn dispositivo que sea capaz de ampliar esa corriente. Podemos usar el arreglo que se
muestra en la Figura 9-8.
El amplificador operacional empleado es un LM833, especial para audio. La etapa de
transistores formada por Q1 y Q2 tiene como nica finalidad suministrar la corriente
que el operacional no puede. Los transistores empleados son los BC547 y BC557, Estos
no son de gran potencia por lo que se deber usar una bocina pequea.
9- PWM
Ing. Juan Ramon Terven Salinas 151

Figura 9-8. Amplificador sencillo de Audio

También podría gustarte