Saltar al contenido
Control Automático Educación

PWM con PIC – (Modulación por Ancho de Pulso)

Hola controleros y controleras, en esta entrada aprenderemos a usar el PWM con PIC (Modulación por Ancho de Pulso), la cual es una de las señales más utilizadas para realizar control con nuestros microcontroladores. Con lo que vamos a ver aqui aprenderás a configurar las velocidades del PWM PIC y al final del post te dejaré un código de implementación de ejemplo que puedes usarlo en cualquier microcontrolador PIC que tu uses. El código se encuentra en PIC C Compiler.

Antes que nada te hago la invitación para ver: CURSO GRATIS PIC

y para ver: LISTA DE REPORDUCCIÓN YOUTUBE.

PWM PIC

Para poder generar esta señal con nuestro PIC, se hace uso de los módulos CCP (Comparador, Captura y PWM). Dicho módulo permite realizar tres funciones básicas.

Comparar: Compara el valor del temporizador con el valor de un registro y provoca una acción en el PIC.

Captura: Obtiene el valor del temporizador en un momento dado, fijado por la acción de un terminal del PIC.

PWM: Genera una señal modulada por ancho de pulso.

En esta entrada, nos vamos a centrar en esta ultima, en el PWM. Para nuestro caso en especifico, como estamos usando el PIC16F887, dicho microcontrolador tiene 2 modulos CCP como se puede apreciar en la siguiente figura, los cuales corresponden a los PINES 16 y 17 (Correspondientes al puerto C, RC1 y RC2).

pickit3 + pic16f887

El módulo PWM (Pulse Width Modulation), permite obtener de los pines CCP1 (Pin 17) y CCP2 (Pin 16) una señal periódica (Es decir que se repite en el tiempo) la cual podemos modificar su ciclo de trabajo (Duty Cycle en ingles). Dicho PWM o Modulación por Ancho de Pulso, puede tener una resolución máxima de 10 BITS. En otras palabras. Como sabemos que el PIC trabaja con voltajes binarios (0V o +5V), podemos configurar el PWM para que trabaje un determinado tiempo en +5V (Ton) frente al tiempo que está en nivel bajo 0V (Toff), tal y como lo podemos apreciar en la siguiente figura.

Modulación por Ancho de Pulso
Modulación por Ancho de Pulso

De esta manera, la tensión media aplicada a la carga, es proporcional al tiempo en que la señal estuvo en +5V (Ton) y asi podemos por  ejemplo controlar la luminosidad de lamparas, o la velocidad de un motor.

PWM con PIC
PWM – Modulación por Ancho de Pulso

La resolución de salida del modulo CCP es de 10 bits, y para que funcione correctamente, no debemos olvidar configurarlo como salida en el TRIS C.

Esta señal PWM funcina igual en cualquier microcontrolador, lo único que cambia es la forma como se configura en cada plataforma. Por ejemplo si te interesa, puedes darle un vistazo a como configurar el PWM con Arduino.

MODULO CCP EN C PARA PWM PIC – Modulación por Ancho de Pulso

El compilador nos suministra dos instrucciones basicas para el manejo del PWM.

Para configurar el módulo CCP:

setup_ccpx(modo);

Donde modo hace referencia a los bits CCPxM3:CPxM0 del registro CCPxCON y en PIC C puede ser configurado según la siguiente tabal:

CCP

El ciclo de trabajo para el PWM se define como:

set_pwmx_duty(valor);

donde el x hace alusión al modulo CCP a utilizar, en el caso del PIC16F887 solo tiene CCP1 y CCP2, así que si queremos usar el PWM del PIN 17 ponemos set_pwm1_duty(valor); y si queremos usar el PWM del PIN 16 ponemos set_pwm2_duty(valor);

Valor es un dato de 10 bits (int16) que determina el ciclo de trabajo o ancho de pulso, es decir ese valor va a determinar el porcentaje en que la señal de PWM se va a mantener encendida. Este valor junto con el valor del preescaler del TMR2 definen el ciclo de trabajo. En la configuración del TIMER 2 el postcaler debe valer 1.

  • Prescaler determina el tiempo de interrupción. Con este podemos disminuir el clock interno del timer, puede tomar valores de 1, 4, o 16.
  • El Postcaler es un número de 1-16 que dice cuántas veces el Timer2 tiene que desbordarse para llamar a la interrupción (1 es una vez, 2 es 2 veces, y así sucesivamente).

Por ejemplo, si se determina con el Prescaler y el Periodo del Timer2 un tiempo de 1s para el desbordamiento, pero realmente se quieren 2s, entonces se coloca el Postcaler en 2.

Como comenté anteriormente el ancho de Pulso ó Ciclo de trabajo para el modulo CCP del PIC puede tener como máximo un valor de 10 bits, eso si, ésta resolución depende exclusivamente del periodo del PWM que nosotros queramos implementar.

Como uso estas instrucciones?

Para generar una señal de Modulación por Ancho de Pulso con el PIC, tenemos que utilizar el TIMER 2, el cual es un Timer de 8 Bits.

Internamente el PIC, usa el TIMER 2 como base de tiempo para la Modulación por Ancho de Pulso (PWM) utilizando el módulo CCP.

Con la siguiente formula podemos calcular la frecuencia de salida

F_{PWM}=\dfrac{F_{Osc}}{4(Carga\ del\ Timer2\ +1) (Preescaler\ del\ TIMER\ 2)}

donde: El Prescaler del TIMER 2 Puede ser 1, 4 o 16, F_{PWM} es la frecuencia del PWM y F_{Osc} es la frecuencia del oscilador que estamos usando en el PIC (por ejemplo un cristal de cuarzo externo)

La carga del Timer 2 (conocido como PR2), también podría ser llamada como el Periodo de la Señal y puede tomar valores entre 0 y 255, debido a que es un registro de 8 bits.

Considerando que vamos a utilizar un cristal de cuarzo de 4Mhz, calculemos cual seria la frecuencia mínima para dicho cristal.

Valor mínimo:

\dfrac{4 MHz}{(255 + 1) * 16 * 4}=\dfrac{4,000,000}{16,384}=244Hz

Valor Máximo:

\dfrac{4 MHz}{(1 + 1) * 1 * 4}=\dfrac{4,000,000}{8}=500000Hz

Recordando claro, que estos son valores teóricos.

Listo, ya sabemos que lo primero que debemos encontrar es el valor de carga del timer 2 (PR2) y que éste depende del tipo de cristal que estamos usando y depende de los valores de preescaler que nosotros seleccionemos (1,4 o 16).

Resolución del PWM

La resolución determina el número de ciclos de trabajo (duty cicle) disponibles para un período determinado. Por ejemplo, una resolución de 10 bits dará como resultado 1024 ciclos de trabajo discretos, mientras que una resolución de 8 bits dará como resultado 256 ciclos de trabajo discretos.

La resolución máxima de PWM es de 10 bits cuando PR2 es 255. La resolución es una función del valor del registro PR2.

Si observamos la ecuación de frecuencia del PWM, F_{PWM}, en su denominador los dos parámetros [4 (PR2 + 1)] hacen referencia a la resolución que se puede alcanzar con el PWM.

Note que si la carga del timer 2 (PR2) fuera su valor máximo (255) el resultado de esa operación nos daría 1024

4 (255 + 1) = 1024

Entonces para saber cuantos bits tenemos en una señal PWM a la frecuencia que nosotros deseamos, podriamos representar ese termino como [4 (PR2 + 1)] = 2^n, donde n es el numero de bits que como máximo sería 10 bits.

Así, podriamos reescribir la ecuación de la frecuencia del PWM como:

F_{PWM}=\dfrac{F_{Osc}}{2^n(Preescaler\ del\ TIMER\ 2)}

Y como lo que queremos es determinar la resolución, simplemente despejamos n de la ecuación anterior aplicando logaritmos a ambos lados de la igualdad:

2^n=\dfrac{F_{Osc}}{F_{PWM}*(Preescaler\ del\ TIMER\ 2)}

n.log(2)=log\left (\dfrac{F_{Osc}}{F_{PWM}*(Preescaler\ del\ TIMER\ 2)} \right )

n=\dfrac{log\left (\dfrac{F_{Osc}}{F_{PWM}*(Preescaler\ del\ TIMER\ 2)} \right )}{log(2)} bits

Este valor es equivalente a la ecuación mostrada en el datasheet del 16F887:

n=\dfrac{log\left [4(PR2+1) \right ]}{log(2)} bits

Con ese valor de resolución de ancho de pulso (n) sabremos cuanto es el Duty Cicle que debemos colocar.

Duty Cicle

Como vimos anteriormente el ancho de pulso del pwm es configurado por:

set_pwmx_duty(valor);

Dado que previamente se tuvo que calcular el valor de la carga del timer 2 (PR2), es importante destacar que el valor de la Carga del Timer 2 NUNCA puede ser mayor que el ancho de pulso (Variable valor).

En este punto somos capaces de determinar el máximo número que puede tomar el duty cicle (int16) que se coloca en el parámetro de entrada de la función set_pwmx_duty(valor);

valor=4(PR2 +1)=2^n 

Vamos ahora a configurar el PIC utilizando un ejemplo Práctico.

Ejemplo 1 del uso del PWM PIC – Modulación por Ancho de Pulso

Vamos a generar una señal cuadrada de 1Khz utilizando el TIMER 2 y el módulo CCP1 del PIC usando nuestro compilador CCS C. Con un cristal de cuarzo de 4MHz.

Solución:

Para generar una señal cuadrada de 1Khz es necesario calcular primero el periodo (Inverso de la frecuencia) f=1Khz=1000hz.

T_{PWM}=\dfrac{1}{1000}=0.001s=1ms

Periodo de 1ms (mili-segundo) o 0,001 segundos donde T=Periodo.

El periodo del oscilador del PIC (en este caso usando un cristal de cuarzo externo de 4MHz como oscilador) viene dado por:

T_{Osc}=\dfrac{1}{4000000}=0.000000250s=0.250\mu s

Ahora necesitamos calcular el desbordamiento del TIMER 2 con la siguiente formula.

T_{PWM}=(PR2+1)*4*(Preescaler\ del\ TIMER\ 2)*T_{Osc}

PR2 =\dfrac{T_{PWM}}{4(Preescaler\ del\ TIMER\ 2)T_{Osc}} - 1

Reemplzando valores tenemos que:

PR2 =\dfrac{0.001s}{4*4*0.000000250s} - 1=249

Obtenemos que el valor de  PR2=249. (Recordando que PR2 tiene que estar entre 0-255, por eso se escoge un preescaler de 4)

El Timer 2 quedaría así:

setup_timer_2(T2_DIV_BY_4,249,1);

Ahora solo nos falta determinar el valor de resolución para saber cuanto es lo máximo que podremos variar el ancho de pulso (duty cicle), aplicando cualquiera de las 2 formula para el cálculo de la resolución tenemos:

n=\dfrac{log\left (\dfrac{4000000}{1000*4} \right )}{log(2)}=9.9657 bits

n=\dfrac{log\left [4(249+1) \right ]}{log(2)} =9.9657 bits

Vemos que con ambas ecuaciones llegamos al mismo resultado.

El máximo ancho de pulso (duty cicle) lo voy a obtener colocando la variable valor:

valor=2^n=2^{9.9657} = 1000

O también puedo calcularlo como:

valor=(249+1)*4 = 1000

El  duty cycle es  configurado entonces por la siguiente instrucción:

set_pwm1_duty(valor);

Donde si valor vale 0, tendre un ciclo de trabajo del 0%, si valor vale 1000, tendré un ciclo de trabajo de 100%, si valor vale 500, tendré un ciclo de trabajo de 50%

Si se ingresa un número directamente en la función, se recomienda ingresarla por medio de un cast para forzar que ese número sea un int16. Por ejemplo, quiero tener un 25% del ciclo de trabajo:

set_pwm1_duty((int16)250);

PWM PIC – Ejemplo 2

Si se necesita una frecuencia de la señal PWM de 4Khz, y se utiliza con el microcontrolador PIC con un oscilador o cristal de 4Mhz, se tendrían que realizar los siguientes cálculos:

Para generar una señal cuadrada de 4Khz es necesario calcular primero el periodo (Inverso de la frecuencia) f=4Khz=4000hz.

T=\dfrac{1}{4000}=0,250ms

Periodo de 0,250ms (mili segundos) donde T=Periodo.

Ahora necesitamos calcular el desbordamiento del TIMER 2 (PR2) con la siguiente formula.

T_{PWM}=(PR2+1)*4*(Preescaler\ del\ TIMER\ 2)*T_{Osc}

El PR2 debe estar entre 0 – 255. Para conseguir esto el preescaler puede ser 1, 4 o 16, con cualquiera va a cumplir. Se selecciona para este ejemplo un preescaler de 16, para estudiar como esto va a afectar enormemente la resolución. Reemplzando valores tenemos que:

PR2 =\dfrac{0,000250s}{4*16*0.000000250s} - 1=14.625

Obtenemos que el valor de  PR2=14,625. Así como necesitamos un valor entero, redondeamos PR2=15.

El Timer 2 quedaría así, empleando un postcaler de 1:

setup_timer_2(T2_DIV_BY_16,15,1);

El máximo ancho de pulso (duty cicle) lo voy a obtener colocando la variable valor:

valor=(PR2+1)*4=(15+1)*4 = 64

Una resolución de 64 es muy baja y pobre, si comparamos con su máxima resolución que sería 1024. El  duty cycle es  configurado entonces por la siguiente instrucción:

set_pwm1_duty(valor);

Donde si valor vale 0, tendre un ciclo de trabajo del 0%, si valor vale 64, tendré un ciclo de trabajo de 100%, si valor vale 32, tendré un ciclo de trabajo de 50%

Si se ingresa un número directamente en la función, se recomienda ingresarla por medio de un cast para forzar que ese número sea un int16. Por ejemplo, quiero tener un 25% del ciclo de trabajo:

set_pwm1_duty((int16)16);

Código de Implementación del PWM PIC

Vamos a llevar a la practica el concepto del PWM del PIC:

EJEMPLO

Existen muchos procesos electrónicos o industriales donde necesitamos controlar la velocidad de un Motor DC. Una manera simple de lograr este objetivo es utilizar un control por PWM. Para esto vamos a diseñar el siguiente circuito y el código del microcontrolador por medio del compilador CCS C con el fin de poder regular la velocidad de un Motor DC por medio de un potenciometro conectado al Terminal RA0 (Para esto sera necesario utilizar el concepto de conversión análogo digital visto en el Post anterior).

En el post de interrupciones PIC encontrarás una mejora de esta práctica donde además de regular la velocidad del motor, se mide la velocidad del mismo a través de un encoder. (Click aqui para ir al post de Interrupciones PIC).

PWM Circuit
PWM – Modulación por Ancho de Pulso

Para poder controlar el motor de 12 V necesitamos utilizar un Mosfet.

Los mosfets de potencia (power mosfets) son componentes electrónicos que nos permiten de controlar corrientes muy elevadas. Como en el caso del los mosfets comunes, tienen tres terminales de salida que se llaman: Drain, Source y Gate (D, S y G). La corriente principal pasa entre Source y Drain (ISD) mientras que el control de esta corriente se obtiene aplicando una tensión sobre el terminal Gate (respecto al terminal Source), conocida como VGS.

Código – PWM PIC C Compiler:

A continuación se presenta el código de uso del PWM PIC (Modulación por Ancho de Pulso) para que lo copies y lo pegues en tu compilador y puedas reproducirlo. Recuerda que para ver el código debes compartir o darle me gusta al contenido de este post para que más personas se beneficien de esta información.

El ejemplo esta en PWM PIC16f887, sin embargo te muestro como usar el programa PWM PIC 16F877A e incluso como usar el programa en el PIC18F4550. En conclusión te sirve para cualquier PIC.

// Por: Sergio Andres Castaño
// https://controlautomaticoeducacion.com/
//___________________________________________________________________________

#include <16f887.h>
#device ADC=10 
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT,INTRC_IO  
#use delay(clock=4000000)  

int16 duty=0;
int Timer2,Poscaler;

void main() { 
   // Generemos una Señal cuadrada de 1 Khz
   Timer2=249;    //Se carga timer 2 con 249 como lo vimos en la pagina
   //Preescaler=4;  //Preescaler solo puede tomar valores de: 1 - 4 - 16
   //Para el preescaler colocamos "t2_div_by_4"
   Poscaler=1;  //Preescaler solo puede tomar valores de: 1
   
   setup_timer_2(t2_div_by_4,Timer2,Poscaler);   //Configuracion de Timer 2 para establecer frec. PWM a 1kHz
   setup_ccp1(ccp_pwm);                //Configurar modulo CCP1 en modo PWM
   setup_adc_ports(all_analog);        //Configurar ADC
   setup_adc(adc_clock_internal);
   while(1)
   {
        set_adc_channel(0);   
        delay_us(100);       
        duty=read_adc(); 
        set_pwm1_duty(duty);
   }
}

Si desean utilizar el PWM PIC 18F4550 CCS o cualquier otro de la familia 18, debes cambiar el encabezado por:

#include <18f4550.h>
#byte porta = 0xf80 // Identificador para el puerto A. 
#byte portb = 0xf81 // Identificador para el puerto B. 
#byte portc = 0xf82 // Identificador para el puerto C. 
#byte portd = 0xf83 // Identificador para el puerto D. 
#byte porte = 0xf84 // Identificador para el puerto E.

Si desean utilizar el PWM PIC 16F877A o cualquier otro de la familia 16, debes cambiar el encabezado por:

#include <16f877A.h>

Eso es todo por la entrada del dia de hoy, espero les haya gustado y hayan aprendido algo nuevo. Si te ha servido el contenido de esta entrada, de los videos y los códigos de implementación y deseas apoyar mi trabajo invitandome a un café super barato, puedes hacerlo en el siguiente link:

👉 Invitar a Sergio a un Café ☕️

Que esten muy bien, nos vemos en la siguiente entrada.

Entradas relacionadas

Deja una respuesta

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

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Comentarios (57)

muy bueno para implementarlo

Responder

Hola, buena explicación pero tengo una duda.
En conversores DC/DC se usa el PWM para controlar un transistor para lograr una buena conmutación pero surge un problema al aplicar en un inicio (primer periodo) este PWM aparecen corrientes muy grandes al inicio del sistema y eso pueden dañar los componentes. Un solución es aplicar el PWM en un inicio como una rampa hasta llegar a los primeros 5V y luego dejarlo como un PWM normal. ¿Como es posible realizar esto?

Responder

saludos , master ase tiempo estoy tratando de aprender programación de micro controladore , gracias a persona como usted e avanzado un poco , pero quiero hacer un trabajo para una fuente oscilada que traba a una frecuencia a unos 20 , o 30 kg con un 12f615 , pero no logro activar o hacer funcionar el pwm

Responder

como seria el calculo si se usa oscilador interno del pic 16f883 8 mhz
setup_timer_2(t2_div_by_4,249,1); esto seria 2 khz
gracias

Responder

Saludos profesor, de acuerdo con la formula la frecuencia minima con un cristal de 4MHz es de 244 Hz usando todos los valores al maximo, en caso de que necesitara una frecuencia menor a 244 Hz tendria que usar otro timer? o cual seria la solucion para este problema
de verdad necesito saber, gracias

Responder

Hola Juan, debes cambiar el oscilador del PIC, por ejemplo en lugar de colocar un cristal de 4Mhaz, puedes usar el oscilador interno. Puedes darle un vistazo a la entrada de Servomotores, donde configuramos el oscilador interno a 500kHz para obtener un PWM de 50Hz.

Responder

Gracias profesor, no se imagina lo mucho que he aprendido con usted

Responder

Excelente Juan, me alegra que el contenido te haya servido. Saludos!

Responder

Sergio verdaderamente agradecido con tu ayuda y el contenido del blog, solucionado el problema del switch, la respuesta era agg la opción antirebote en el código dirijido a la onda pwm, pasaré a leer todos tus curso y a recomendarlo, gracias por sus consejos y su preocupación en responder.

Responder

Y eso hice, coloque una condición de if y else en esos caso, todo a un pin de entrada, pero ahora una sol condición me funciona, coloque el switch de un punto a vcc de 5v y cuando conecta va a tierra, debería solo dejar la entrada de vcc sin aterrarlo??

Pd: hice otro comentario porque no me daba la opción de responder a tu respuesta Sergio

Responder

Coloca el switche con una resistencia pulldown para que el pic detecte los 5v o el GND. Algo parecido a lo que hicimos en el segundo ejemplo con los pulsadores de la entrada del display 7 segmentos.

Responder

Muy buenas Sergio, tengo una duda con respecto a la modulación de la pwn, ando trabajando con pic compiler, pero en una practica nos pidieron que una salida del ccp se trabajará de 50 y 100 %, mi pregunta es, si cambiando el potenciómetro por un switch, podría varía la entrada de 0 y 1 (que en 0 este desconectado el pulsador, y conectado haga el paso a 5v), respetando el mismo código para el potenciómetro en el compilador?, y así en alta me trabaje al 100% y en baja me trabaje al 50%.
En preciso, que el switch si lo pongo en la posición del potenciómetro, hará su función con el mismo código que nos has demostrado en este segmento?

Responder

Es posible hacer eso, pero debes modificar el código. Debes leer el switch y con un condicional cuando esté activo mandas 100% en el duty, cuando esté inactivo mandas los 50%.

Responder

Buenas tardes Sergio, excelente material, tengo una duda, para generar una señal de 1kHz la resolución sale de 1000, pero el potenciómetro da un máximo de 1024, ¿Se tiene que modificar el valor del potenciómetro para que esté en un rango de 0-1000?
Saludos desde México.

Responder

No, puedes dejarlo asi, la diferencia entre 1000 a 1024 es mínima. Si quieres ser exacto, es solo colocar un if(ADC>1000) then (PWM = 1000;) o puedes hacer una regla de 3. Saludos.

Responder

Buenas Sergio, muchas gracias por compartir tu conocimiento.

Tenía una duda en el cálculo de la resolución, más concretamente en esta igualdad:
{(Carga\ del\ Timer2\ +1)*4=2^n-1} Me parece que sobra el – 1 de la derecha de la igualdad, así si CargaDelTimer2 es igual a 255, (255+1)*4=2^10.
Luego el despeje mediante logaritmos no entiendo como se ha hecho, pues log(2^n – 1)!=log(2^n) – log(1). Creo que son dos errores que sorprendentemente uno contrarresta el efecto negativo del otro, de tal modo que el resultado obtenido es el correcto.
Si se me escapa algo y efectivamente está bien resuelto problema hazmelo saber por favor! Un saludo

Responder

Hola Guzmán, tienes razón, estaba mal formulado el cálculo. Esta entrada la hice hace buen tiempo y nadie me había avisado del error. Ya está corregido. Gracias por la observación. Saludos!

Responder

Sergio, muchisimas gracias por la respuesta lo estoy implementando todo ok.
Te hago una ultima pregunta, quiero ponerle un ups al motor: cuando se corta la alimentacion del microcontrolador, se puede alimentar el motor directamente (conectando el negativo directamente al motor) en ese caso se quemaria el mosfet con el tiempo? si es asi que otra manera puede haber saludos

Responder

Hola Sergio, ante todo muy bueno el post queria preguntarte si se puede en vez de utilizar lectura de adc para controlar la velocidad, si se puede ingresarle directamente un valor. Lo que deseo es controlar un motor que arranque suave y luego quede en una velocidad al 50% del pwm se puede? de antemano muchas gracias

Responder

Hola Guido, claro que se puede, para regular la velocidad del motor solo basta con colocar el valor del duty cicle, ese valor lo puedes poner como mejor te venga en tu proyecto a través de un teclado, un potenciometro, directamente en el programa, el computador, etc…

Responder

Disculpa tengo una duda ,tengo que hacer algo similar hice mi código y calcule valores
sera que lo puedas revisar es a 50 kHZ

Responder

Parece que si esta bien. Lo malo es en el duty cicle, tu solo tienes hasta una resolución de 7. Por lo tanto tu duty cicle solo puede variar desde 0 hasta 128, no puedes poner directamente el valor leido del análogo digital, debes primero validar para que el máximo duty cicle sea 128

Responder

Hola Sergio, oye como se llama el potenciómetro que usaste en PROTEUS. Lo busque en “devices” y no el que usaste. Me podrías decir como buscarlo por favor.

Responder

Búscalo como POT-HG Saludos!!

Responder

tengo una duda si se quiere hacer el uso de los dos pines ccp pero quiero configurarlos con frecuencias distintas que es los que puedo hacer, también uso el timer 2 pero lo configuro para que trabaje de formas distintas cada vez que se tenga que utilizar o se utiliza otro timer o que es lo que se hace si ademas de ello las frecuencias siempre quiero que sean continuas y no se vean afectadas una u otra por la configuracion del timer 2

Responder

Hola Diego, para trabajar con dos frecuencias diferentes deberás emplear dos timers diferentes, y no todos los chips soportan ese tipo de aplicación por ejemplo el pic18f8722 permite hacer eso que pretendes. Siempre toca mirar primero en el datasheet porque varios pics traen diferentes TIMERs, sin embargo muchas veces esos timers no estan directamente relacionados con el modulo CCP, entonces no sirven para ese objetivo.

Responder

voy a estudiar el codigo, despues comparto experiencia

Responder

El mejor de los éxitos.

Responder

Hola, estoy haciendo un proyecto, el cual tengo que controlar dos servomotores que simulan una antena parabólica. Utilizo el micro-controlador 18F4550, y el CCS C Compiler. El problema es que el timer 2 de este micro es de 8 bits y no consigo que sea preciso. Me gustaría saber si hay algún método parecido al del ADC utilizando 10 bits o mas pero sin utilizar potenciometros. Muchas gracias por tu tiempo.

Responder

Hola David, no entendi tu pregunta. En el post estamos usando un PIC16f887 donde el tiemer 2 también es de 8 bits. El 18F4550 es muy parecido, solo que es más poderoso, con más memoria y ambos tienen el conversor ADC de 10 bits. No entiendo tu pregunta de los potenciometros. En el ADC debe llegar un voltaje con valores entre 0 y 5 VDC independiente de donde vengan, pueden venir de un sensor, una fuente, algún circuito, un potenciometro, etc.

Responder

Hola Sergio, lo que necesito es algun metodo para acortar la diferencia entre dos “ticks”. Es decir, con los 8 bits del T2, que serian 255 ticks como maximo, la diferencia de un tick a otro en un servomotor es mas de 1º. Necesito aumentar la carga del timer para poder ganar mas precisión. En el ejemplo , dices que “donde si valor vale 0, tendre un ciclo de trabajo del 0%, si valor vale 1000, tendré un ciclo de trabajo de 100%, si valor vale 500, tendré un ciclo de trabajo de 50%”. El problema es que la señal solo me funciona en el rango de 0 a 255.

Responder

solo que esa señal de 0 a 1000 solo es valida para generar un pwm de 1khz, con un cristal de 4000MHz y un preescaler de 4 para que nuestra resolución llegue a 1000. Si observas el ejemplo 2, se desea tener una frecuencia mayor de 4Khz, aqui cambiamos el prescaler para 16, y con lo cual nuestra resolución máxima nos dio 63. Por lo que la señal solo funciona en el rango de 0 a 63. Es decir si valor vale 0, tendre un ciclo de trabajo del 0%, si valor vale 63, tendré un ciclo de trabajo de 100%, si valor vale 32, tendré un ciclo de trabajo de 50%

Responder

Hola, que tendria q cambiar para controlar el duty por teclado matricial y no por potenciometro

Responder

Edisson puedes ver la entrada de teclado matricial click aqui, tomar el numero que digitaste en el teclado, validando que sea de 0 a 1000, convirtiendo aquel numero de caracter a double, y colocandolo en la variable duty del PWM. Saludos.

Responder

De antemano excelente explicación Muchas gracias por la colaboración de estos cursos

Responder

Un saludo especial amigo Sergio C, tengo que realizar un proyecto de Universidad para el control de una caminadora con 4 pulsadores, que al seleccionar el pulsador1 arranque con un 25 %, al seleccionar pulsador 2 suba al 50%, 3 al 75% y 4 al 100%, con encoder para calcular la velocidad del motor y se refleje en pantalla, si me puedes ayudar te estaré colaborando por paypal, mi correo es [email protected]

Responder

Hola John, con lo que hemos visto acá en la pagina se puede hacer ese proyecto que requieres. Saludos y muchos éxitos.

Responder

Hola Sergio que tal, te envío un cordial saludo y agradecerte por la valiosa información que nos compartes.
quiero hacerte una pregunta: ¿cual sería la lógica para programar una secuencia con pulsadores, es decir, con un P/B1 activo una salida cualquiera, con otro P/B2 activo otra salida y así sucesivamente; y si vuelvo a presionar cualquier P/B se desactiva la salida correspondiente.
Suerte.

Responder

Hola Samuel, para hacer ese proyecto, basta con usar los comandos que vimos en las primeras entradas del curso, te dejo el link con todo el curso:
https://controlautomaticoeducacion.com/microcontroladores-pic/
Ingresa al post numero 2, Alli aprenderás como preguntar por una entrada (pulsadores) y para activar y desactivar usaria el comando output_toggle(pin_x); el cual puedes ver como funciona entrando al post numero 3.
Es solo clickar en cada imagen. Saludos.

Responder

Sin animo de ofender solo de informar esto que usted tiene puesto “PWM: Genera una señal modulada en amplitud de pulso.” es incorrecto, lo correcto es modulación en ancho de pulso no de amplitud (PWM = pulse width modulation)

Responder

Es correcto Miguel. Gracias por la observación.

Responder

Hola Sergio muy bueno el blog, estuve leyendo los comentarios y en uno hay algo que me interesa, que es utilizar un filtro pasa bajo para obtener una salida de 0 a 5 V continua a partir de la señal PWM, me pasarias el link a esa info ? gracias

Responder

Laura en esta entrada hay un ejemplo de un control PID implementado que hace uso de eso. Toma la señal PWM con un filtro pasabajo y lo pasa a un valor en DC de 0 – 5V. Alli está el circuito.
https://controlautomaticoeducacion.com/19-control-pid-en-pic-ejemplo-2/

Responder

Hola sergio , la verdad que hace dias estoy dando vueltas por la web y no encuentro el codigo fuente adecuado a mi proyecto , ya tengo un proyecto con pic 16f886 , se que debo activar el ccp1 y ahi me quedo porque el programa que tengo ya tiene otras funciones como enviar unos datos por I2c a un integrado y escribir en pantalla 16×2 pero quiero solo agregar la funcion pwm que se muestre de 0a 100% en mi display y genere de 0a5v en su salida ccp ,si me podrias dar una mano con eso te paso un correo , gracias

Responder

Hola Rodrigo, no entendi, quieres que de la patilla CCP salga un voltaje directo de 0 a 5V ?? por ejemplo si tu pwm está en el 50% quieres que te salga 2.5V?, si es eso lo que quieres hacer, deber agregar un filtro pasa bajos a la salida del CCP, en esta entrada se muestra un ejemplo de como hacerlo (click aqui para verlo). Para mostrar el porcentaje en el LCD debes hacer una regla de 3 donde por ejemplo x es tu valor de porcentaje y duty es el valor del duty cicle actual: x=dfrac{duty*100}{1024} y utilizar printf(lcd_putc,”porcentaje= %f “,x); como se utiliza en esta entrada (Click aqui)

Responder

Hola Sergio , es correcto lo que me decis quiero que el valor de salida de mi ccp1 del pic 16F886 muestre un texto por ejemplo ( salida ) y % , entonces al subir y bajar en el display puedo ver de 0% a 100% mientras mi ccp1 entrega un valor de 0 a 5v luego de pasar por un filtro pasa bajos , hasta ahi todo bien , el problema es que como te comentaba yo agregaria el uso de ccp1 a un programa que manda I2c a otro integrado que es el principal trabajo y no se en que parte agregar el programa para que funcione el ccp como yo quiero sin afectar al programa principal , ahora bien mi circuito no usa cristal sino un oscilador interno de 4mhz (se puede hacer sin agregar cristal ).
en realidad me gustaria que en una parte del programa que es para hacer servicio y ajustes yo encuentre este (salida%) ademas que el ccp al iniciar no arranque en cero sino donde se dejo por ultima vez que guarde en la ram del micro ese dato , se entiende lo que quiero realizar ? si me pasas un correo te mando el archivo asi lo ves ya que nisiquiera lo logre simular en proteus por falta de conocimiento estuve 2 dias y con todo bien conectado al darle play no hace nada , soy nuevo en esto si me podes dar una mano te agradezco , saludos

Responder

ademas la idea es que el ciclo de trabajo del ccp cambie , (suba o Baje ) por pulsadores que estando en (modo servicio) se usan para modificar cosas y no por el uso de un potenciometro como en tu proyecto , gracias Sergio

Responder

Si, puedes hacer que cuando se presione un pulsador incremente o decremente algún contador dentro de tu código y ese contador será el duty cicle de tu PWM (set_pwm1_duty(duty);), validando siempre dentro del código que este entre 0 y el valor máximo que has calculado para tu cristal interno. Entonces cuando decrementes si llega a cero, debes poner un if y hacer que se mantenga en cero, porque no tiene sentido que coloques números negativos, y lo mismo para el valor máximo.

Bueno Rodrigo, según veo, tu has implementado el PWM al programa del PIC que ya tienes y no te está trabajando bien?. Porque para agregar el pwm es solo colocar los bits de configuración que se hace antes del While Infinito. Recuerda que debes configurar adecuadamente tu PWM para el cristal interno de 4MHz, para que obtengas la señal correcta. Mira que en los ejemplos de la entrada se hace con cristal externo de 4000MHz. El cristal interno no es tan preciso cuanto un cristal externo y obviamente el pic corre más lento, pero bueno pienso que no sea mucho problema. Solo agregando eso al programa ya deberia rodar el PWM, y puedes colocar el set_pwm1_duty(duty); para generar tu señal en cualquier parte del código.
Si quieres que salte a un punto de servicio, puedes implementarlo con alguna interrupción, bien sea por algún pulsador o algo asi. Parece que estas bastante encaminado, aplica lo visto en la entrada de almacenamiento EEPROM interno para no perder el último valor del duty, y debes cargar dicho valor siempre al inicio del programa, antes de entrar en el while infinito y después de haber configurado el PWM.

Responder

Muchas gracias el código me fue de gran ayuda para hacer un dimmer digital

Responder

hola SERGIO…saludos …te comento que yo trabajo ya desde hace mas de 10 años con microcontroladores de microchip desde 8 ,18 ,28 , y 40 pin depende del proyecto que me pidan
y siempre trabaje con ensamblador y nunca he tenido problemas….. ultima menta me dio la curiosidad de trabajar con otro lenguaje…probé con arduino ,,c++, y otros pero el que me llamo mucho la atención fue ccs compiler me siento bien con este lenguaje y he pasado varios proyectos que ya tengo trabajando a este nuevo programa…pero hay una cosa que no he podido implementar al cien por ciento la interrupción externa por el pin ( RB0 ) ya que al simular en ccs compiler esta interrupción externa se me pierden los datos …en ensamblador cuando interrumpía el programa con un swich conectado a RB0 por flanco de bajada tenia que guardad todos los datos por programa y al desconectar el swich estos regresan de donde salieron…el problema que tengo es que con ccs compiler no he podido con esta función de interrupción externa por RB0 se me pierde el programa o los datos los regresa incompletos…..le seguiré estudiando para logra sacar este detalle …….por tu atención gracias …..y si vale demaciado la pena invitarte un cafe

Responder

Hola Mario, gracias por visitar la pagina. La verdad es que trabajar con ensamblador es mucho más efectivo para el microcontrolador, porque estas hablando casi que el mismo lenguaje que él, imagino ya tendras muchas rutinas casi listas en ese lenguaje. El problema del ensamblador es que es mucho más dificil de programar pues debes ir muy al detalle y gastas mucho tiempo, igual son cosas que con la experiencia se va mejorando. Hoy en dia los microcontroladores vienen con memoria suficiente para soportar lenguajes de Alto nivel como el lenguaje C que facilitan enormemente la vida del programador, lo que significa un ahorro sustancial de tiempo y la posibilidad de crear cosas mucho más sofisticadas, por lo menos es lo que yo pienso, yo también programé en ensamblador, pero ahora definitivamente me quedo con el lenguaje C. Tenés que ver como estas guardando los datos cuando entras en la interrupción, lo mas recomendable es que guardes esos datos en variables Globales, osea variables declaradas despues del encabezado, afuera de todas las funciones. Asi estas variables pueden ser usadas por todas las funciones de tu código. Saludos y éxitos en tus proyectos.

Responder

hola SERGIO gracias por tu atención….y si al trabajar con ensamblador ya tengo varias librerías elaboradas y solo las tengo que llamar y te comentaba de la interrupción externa en el pin RB0 en ensamblador no tengo problemas con esta función he podido elaborar asta un segundo programa dentro de la interrupción y no tengo problemas al salir de la esta función lo voy a intentar implementar esta acción en ccs compiler y te comento después que paso………….. y nuevamente GRACIAS por tu atención

Responder

Hola sergio, muchas gracias por toda esta información, estoy diseñando un carro a control remoto, he visto que usan el PWM para la dirección de giro de las ruedas, pero no logro entender si el pwm es constante, como logro determinar que el giro se haga hacia un lado o hacia el otro, o si puedes darme alguna idea de como generar este giro a traves de un servomotor, tengo en mente usar puente h para controlar el giro hacia adelante o hacia atras pero me sigue inquietando como generar el giro hacia derecha o izquierda, te agradezco cualquier ayuda o luz que me puedas dar.

Responder

Daniela, pues depende de como sean tus ruedas, si estas tienen como incorporarle la dirección o si son ruedas estaticas, es decir que solo puedes hacerlas girar para adelante o para atras (Como si fuera un tanque, esos de guerra). Efectivamente para tu proyecto vas a necesitar el puente H para poder hacer la inversion de giro, una forma de hacer girar el carro para un lado, digamos a la derecha, es hacer que las dos ruedas de la derecha giren hacia adelante, y las dos ruedas de la izquierda giren hacia atras, asi haras que el Carro gire en su propio eje hacia la derecha. Saludos.

Responder

Hola, soy Pedro Bazan, una pregunta ¿me podrás asesorar a montar este programa en un pic 16f886 en asm?

Responder

Hola Pedro, hace muchisimos años programé microcontroladores en ASM, hoy lastimosamente ya no me acuerdo como programar en ASM, como es algo que nunca volví a utilizar inevitablemente se olvida. Espero que puedas hacer tu programa, busca por la web, que de seguro encuentras. Un saludo.

Responder