Autor Tema: programar un PWM  (Leído 21955 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:programar un PWM
« Respuesta #15 en: 24 de Noviembre de 2015, 03:56:05 »
Creo que no leiste esto detenidamente:

Citar
El programa que necesitás hacer no es de gran complejidad, siempre y cuando puedas atender debidamente a tus PWMs y no satures al uC con otras tareas que puedan perjudicar la precisión de los PWMs.

El codigo que paso BrunoF es justamente para cuando solo necesitas el PWM y nada mas en el programa. Cualquier otra parte de programa variairia el periodo de la señal. Tales como tus delays y lecturas del ADC. O llevaria a algo demasiado complicado el tener en cuenta todas las situaciones para obtener un ciclo siempre igual.

Si intentas hacer un PWM de varios canales y no que no se vea afectado por cualquier  codigo que este en el main, debes hacerlo con interrupciones ( timers o CCP si queres )

Desconectado deray8

  • PIC10
  • *
  • Mensajes: 9
Re:programar un PWM
« Respuesta #16 en: 27 de Noviembre de 2017, 23:29:17 »
Estimados todos... después de casi 9 años, he vuelto a buscar este mismo tema... sin recordar que antes lo había postrado. Lamento no haber seguido los que ha puesto BrunoF.

Pero bueno... he tomado su programa y lo he modificado para hacer un mezclador de colores automático...

He acá el código, realizado y compilado con CCS

#include <16F628A.h>
#fuses   HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock = 20M)

void main(){

int c, pwm1, pwm2, pwm3, a, b;

c=a=b=0;
pwm1=1;
pwm2=1;
pwm3=1;



while(1){
         if(pwm1>=c) {output_high(pin_b0);}
         else {output_low(pin_b0);}

         if(pwm2>=c) {output_high(pin_b1);}
         else {output_low(pin_b1);}
         
         if(pwm3>=c) {output_high(pin_b2);}
         else {output_low(pin_b2);}
         
//delay_us(10);
c++;                    //incrementar paso

if(c==255){pwm1++; a++;}
if(a==50){pwm2++; a=0; b++;}
if(b==10){pwm3++; b=0; }

}
}

Desconectado Laucha12345

  • PIC10
  • *
  • Mensajes: 1
Re: programar un PWM
« Respuesta #17 en: 16 de Diciembre de 2017, 16:38:41 »
Hola jeremy,

es un pequeño error común en mucha gente que implementa el PWM por software, e incluso lo he visto en algunos PWM hardware también al fallo.

La idea es que cuando el PWM es 0%, el pin tendría realmente estar siempre en bajo. Lo opuesto para un duty del 100% (siempre activo). Si no salteas el cero, en realidad cuando pones el PWM al 0% ocurre un muy breve duty, debido a que el IF se cumple si pwm = 0 y step = 0.

Esto ocurre inicialmente, porque cuando uno elige hacer un pwm de n bits de resolución, la cantidad de pasadas (iteraciones) que se necesitan hacer para generar un ciclo de PWM no son 2^n, sino 2^n - 1. Tal vez sea dificil verlo al principio, pero esa pasada de menos que aparece, es porque cuando tu tomas una decisión binaria, estás obteniendo dos resultados posibles (SI o NO).

Si lo hacemos con un PWM de 2 bits de resolución, se ve fácilmente que sólo necesitamos 3 (2^n-1) iteraciones para generarlo perfectamente:
la primera iteración decide mediante el IF si el duty es del 0% o mayor;
la segunda iteración decide mediante el IF si el duty es del 33% o mayor;
la tercera iteración decide mediante el IF si el duty es del 67%, caso contrario es del 100%;

Fijate que con 3 iteraciones, hemos logrado 4 resultados de duty distintos, que son los que necesitamos.

Visto en código:
step = 1;

while(1){
if(pwm1>=step) output_high(pin_b0) else output_low(pin_b0);
//delay_us(xxx);
step++;                    //incrementar paso
if(step == 0x04) step = 1;        //si no hay más iteraciones, step=1
}

De manera idéntica ocurre cuando hacemos un PWM de 8 bits de resolución (256 posiciones efectivas), sólo necesitamos 255 iteraciones.  Si lo quieres ver más básico aún. para hacer un PWM de 1 bit de resolución (2 valores posibles), sólo necesitas un sólo if (una sola iteración), que nuevamente resulta ser 2^n - 1.

Saludos.

Que tal, haciendo uso de tu programa intente hacer el mio para un sistema de control para una tira de leds RGB, el problema que tengo es con los ciclos, ya que se queda en la parte del PWM y no vuelve a verificar el estado de las variables de entrada en este caso el ADC, espero me puedan ayudar u orientar para resolver mi problema, adjunto mi codigo en C:

Código: C
  1. #include <18f4550.h>
  2. #fuses hs,nowdt,nolvp,noprotect
  3. #use delay(clock=20000000)
  4. #use standard_io(C)
  5. #use standard_io(B)
  6. #define use_portB_lcd true
  7. #include <lcd.c>
  8.  
  9.  
  10. int res0, res1, res2;
  11. char step, pwm0,pwm1,pwm2;
  12.  
  13.  
  14.  
  15. void main()
  16. {
  17.      
  18.       setup_port_A(all_analog);
  19.       setup_adc(adc_clock_internal);
  20.       lcd_init();
  21.      
  22.       delay_ms(100);
  23.       printf(lcd_putc,"\fBienvenido");
  24.       delay_ms(500);
  25.       printf(lcd_putc,"\nRGBControl");
  26.       delay_ms(500);
  27.       printf(lcd_putc,"\fColor code");
  28.      
  29.       do{
  30.      
  31.          delay_ms(50);
  32.          set_adc_channel(0);
  33.          res0=read_adc();
  34.          delay_ms(50);
  35.          lcd_gotoxy(1,2);
  36.          printf(lcd_putc,"%uR ",res0);
  37.              
  38.          delay_ms(60);
  39.          set_adc_channel(1);
  40.          res1=read_adc();
  41.          delay_ms(60);
  42.          lcd_gotoxy(6,2);
  43.          printf(lcd_putc,"%uG ",res1);
  44.  
  45.          delay_ms(70);
  46.          set_adc_channel(2);
  47.          res2=read_adc();
  48.          delay_ms(70);
  49.          lcd_gotoxy(11,2);
  50.          printf(lcd_putc,"%uB ",res2);
  51.          
  52.        
  53.          step=1;
  54.          pwm0=res0;
  55.          pwm1=res1;
  56.          pwm2=res2;
  57.  
  58.             do{
  59.             if(pwm0>=step) output_high(pin_c0); else output_low(pin_c0);
  60.             if(pwm1>=step) output_high(pin_c1); else output_low(pin_c1);
  61.             if(pwm2>=step) output_high(pin_c2); else output_low(pin_c2);
  62.             //delay_us(xxx);
  63.             step++;                    //incrementar paso
  64.             if(!step) step++;        //si step==0, step=1
  65.             }while(true);
  66.          
  67.  
  68.      }while(true);
  69.      
  70.      
  71.      
  72.      
  73. }



De antemano Gracias! :)

Yo logre resolver ese error. Simplemente tenes que modificar la ulima parte del código y tiene que quedar de esta manera.
Código: C
  1. #include <18f4550.h>
  2. #fuses hs,nowdt,nolvp,noprotect
  3. #use delay(clock=20000000)
  4. #use standard_io(C)
  5. #use standard_io(B)
  6. #define use_portB_lcd true
  7. #include <lcd.c>
  8.  
  9.  
  10. int res0, res1, res2;
  11. char step, pwm0,pwm1,pwm2;
  12.  
  13.  
  14.  
  15. void main()
  16. {
  17.      
  18.       setup_port_A(all_analog);
  19.       setup_adc(adc_clock_internal);
  20.       lcd_init();
  21.      
  22.       delay_ms(100);
  23.       printf(lcd_putc,"\fBienvenido");
  24.       delay_ms(500);
  25.       printf(lcd_putc,"\nRGBControl");
  26.       delay_ms(500);
  27.       printf(lcd_putc,"\fColor code");
  28.      
  29.       do{
  30.      
  31.          delay_ms(50);
  32.          set_adc_channel(0);
  33.          res0=read_adc();
  34.          delay_ms(50);
  35.          lcd_gotoxy(1,2);
  36.          printf(lcd_putc,"%uR ",res0);
  37.              
  38.          delay_ms(60);
  39.          set_adc_channel(1);
  40.          res1=read_adc();
  41.          delay_ms(60);
  42.          lcd_gotoxy(6,2);
  43.          printf(lcd_putc,"%uG ",res1);
  44.  
  45.          delay_ms(70);
  46.          set_adc_channel(2);
  47.          res2=read_adc();
  48.          delay_ms(70);
  49.          lcd_gotoxy(11,2);
  50.          printf(lcd_putc,"%uB ",res2);
  51.          
  52.        
  53.          step=1;
  54.          pwm0=res0;
  55.          pwm1=res1;
  56.          pwm2=res2;
  57.  
  58.             do{
  59.             if(pwm0>=step) output_high(pin_c0); else output_low(pin_c0);
  60.             if(pwm1>=step) output_high(pin_c1); else output_low(pin_c1);
  61.             if(pwm2>=step) output_high(pin_c2); else output_low(pin_c2);
  62.             step++;                    //incrementar paso
  63.             }while(step++);
  64.          
  65.  
  66.      }while(true);
  67.      
  68.      
  69.      
  70.      
  71. }