Autor Tema: ajustar PWM a un periodo de segundos  (Leído 2710 veces)

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

Desconectado ceci_lamorocha

  • PIC12
  • **
  • Mensajes: 94
ajustar PWM a un periodo de segundos
« en: 30 de Mayo de 2015, 15:45:16 »
Hola que tal, les comento mi duda, queria realizar un PWM cuyo periodo sea de segundos pero segun la formula del Datasheet esto no es posible, o lo estoy viendo mal.

Segun la formula (que envio en archivo adjunto) para el pic 16f883 (que es la misma de muchos otros) utilizando un cristal de 4MHz el periodo T mas largo  que podemos obtener es de 4ms

aprox, y si usamos un cristal de mas alta frecuencia el periodo se hace mas corto aun !  entonces... como podria hacer que el PWM tenga un periodo mas largo de segundos ?

 

Desconectado juaperser1

  • Colaborador
  • DsPIC30
  • *****
  • Mensajes: 2979
Re: ajustar PWM a un periodo de segundos
« Respuesta #1 en: 30 de Mayo de 2015, 15:56:13 »
Hola ceci_lamorocha hay una solución muy sencilla, usa timer para generar tu pwm, de esta manera podrás darle el tiempo que quieras con una variable acumulativa, es decir si tu período Maximo es de por ejemplo 10ms y quieres contar un segundo pues cada vez que entres en el timer aumentas la variable en 1, cuando esa variable valga 100 sabrás que ha pasado un segundo y modificas tu señal.

Un saludo
Visita mi canal para aprender sobre electrónica y programación:

https://www.youtube.com/channel/UCxOYHcAMLCVEtZEvGgPQ6Vw

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: ajustar PWM a un periodo de segundos
« Respuesta #2 en: 30 de Mayo de 2015, 18:23:37 »
Tal cual como dijo juaperser, un PWM por software, y ademas podes definir una resolucion. Por ejemplo si queres con los valores que te dio en su ejemplo, si queres un periodo de 1 segundo y tu interrupcion es de 10ms, tendrias una resolucion de 100 (100 pasos de 0% a 100% duty). si haces las interrupciones de 1ms tendrias una resolucion de 1000 o casi 10bits.
« Última modificación: 30 de Mayo de 2015, 18:30:32 por KILLERJC »

Desconectado ceci_lamorocha

  • PIC12
  • **
  • Mensajes: 94
Re: ajustar PWM a un periodo de segundos
« Respuesta #3 en: 04 de Junio de 2015, 19:58:55 »
Gracias por las respuestas!  el problema es que queria hacer el PWM con los datos del ADC ( es decir el circuito seria un potenciometro conectado al ADC del pic  y el valor del ADC luego lo cargo al modulo PWM del pic) y de hacerlo como ustedes dicen,,, de usar el timer para hacer el PWM ,,, no se como se podria hacerlo usando el valor del ADC ??  :oops:

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: ajustar PWM a un periodo de segundos
« Respuesta #4 en: 04 de Junio de 2015, 20:30:16 »
Se puede....

Suponete que tenes un ADC de 8 bits (255 posiciones, siendo 100% el 255 y 0 el 0%)
Para ser mas simple vamos a hacer un PWM de 8 bits de resolucion

1 segundo / 255 = 3.92156862 ms = 255Hz

Tu periodo del clock es de 4/4Mhz = 1us

necesitarias contar segun el preescaler que tengas:

1:1 = 3921.5686
1:2 = 1960.7843
1:4 = 980.3921
1:8 = 490.196
1:16 = 245.098
1:32 = 122.54

El tema es que ningun es entero, ademas notar que si usamos preescaler de 1 a 8 o hacemos un par de calculos para usarlo con un timer de 8bits o simplemente usamos el timer de 16bits, luego con 1/16 y 1/32 vemos que se peude usar el timer de 8 bits.
Veamos ahora la frecuencia que logramos al ponerle numeros enteros, redondeando a los mas cercanos

1:1 = 3922 = 254.97Hz
1:2 = 1961 = 254.97Hz
1:4 = 980 = 255.10Hz
1:8 = 490 = 255.10Hz
1:16 = 245 = 255.10Hz
1:32 = 123 = 254.07Hz

Eso te deja con el timer que quieras, voy a hacer el de 2 para un PIC16F877A, uno de TMR0(8bits) y otro de TMR1(16bits)

1:16 = 245 = 255.10Hz  -> TMR0
1:1 = 3922 = 254.97Hz  -> TMR1

TMR0
Código: C
  1. // Interrupt Handler
  2. void interrupt()
  3. {
  4.   // Timer0 Interrupt - Freq = 255.10 Hz - Period = 0.003920 seconds
  5.   if (INTCON.TMR0IF ==1) // timer 0 interrupt flag
  6.   {
  7.     PORTB.F0 = ~PORTB.F0;      // Toggle PORTB bit0 LED
  8.     INTCON.TMR0IF = 0;         // clear the flag
  9.     INTCON.TMR0IE = 1;         // reenable the interrupt
  10.     TMR0 = 11;           // reset the timer preset count
  11.   }
  12.  
  13. }
  14.  
  15.  
  16.  
  17. // code starts here...
  18. void main()
  19. {
  20.  
  21.   // setup portb to show the interrupts by blibking LEDs
  22.   TRISB = 0x00;    // PORT is all output...to show the interrupts
  23.   PORTB = 0;       // start with all outputs low
  24.  
  25. //Timer0 Registers Prescaler= 16 - TMR0 Preset = 11 - Freq = 255.10 Hz - Period = 0.003920 seconds
  26. OPTION_REG.T0CS = 0;  // bit 5  TMR0 Clock Source Select bit...0 = Internal Clock (CLKO) 1 = Transition on T0CKI pin
  27. OPTION_REG.T0SE = 0;  // bit 4 TMR0 Source Edge Select bit 0 = low/high 1 = high/low
  28. OPTION_REG.PSA = 0;   // bit 3  Prescaler Assignment bit...0 = Prescaler is assigned to the Timer0
  29. OPTION_REG.PS2 = 0;   // bits 2-0  PS2:PS0: Prescaler Rate Select bits
  30. OPTION_REG.PS1 = 1;
  31. OPTION_REG.PS0 = 1;
  32. TMR0 = 11;             // preset for timer register
  33.  
  34.  
  35. // Interrupt Registers
  36.   INTCON = 0;           // clear the interrpt control register
  37.   INTCON.TMR0IE = 1;        // bit5 TMR0 Overflow Interrupt Enable bit...1 = Enables the TMR0 interrupt
  38.   INTCON.TMR0IF = 0;        // bit2 clear timer 0 interrupt flag
  39.   INTCON.GIE = 1;           // bit7 global interrupt enable
  40.  
  41.  
  42.   while(1)  //endless loop
  43.   {
  44.   }
  45. }

TMR1
Código: C
  1. // Interrupt Handler
  2. void interrupt()
  3. {
  4.  
  5.   // Timer1 Interrupt - Freq = 254.97 Hz - Period = 0.003922 seconds
  6.   if (PIR1.TMR1IF == 1) // timer 1 interrupt flag
  7.   {
  8.     PORTB.F1 = ~PORTB.F1;      // Toggle PORTB bit1 LED
  9.     PIR1.TMR1IF = 0;           // interrupt must be cleared by software
  10.     PIE1.TMR1IE  =   1;        // reenable the interrupt
  11.     TMR1H = 240;             // preset for timer1 MSB register, Value TMR1 = 61614
  12.     TMR1L = 174;             // preset for timer1 LSB register
  13.   }
  14.  
  15. }
  16.  
  17.  
  18.  
  19. // code starts here...
  20. void main()
  21. {
  22.  
  23.   // setup portb to show the interrupts by blibking LEDs
  24.   TRISB = 0x00;    // PORT is all output...to show the interrupts
  25.   PORTB = 0;       // start with all outputs low
  26.  
  27. //Timer1 Registers Prescaler= 1 - TMR1 Preset = 61614 - Freq = 254.97 Hz - Period = 0.003922 seconds
  28. T1CON.T1CKPS1 = 0;   // bits 5-4  Prescaler Rate Select bits
  29. T1CON.T1CKPS0 = 0;   // bit 4
  30. T1CON.T1OSCEN = 1;   // bit 3 Timer1 Oscillator Enable Control bit 1 = on
  31. T1CON.T1SYNC = 1;    // bit 2 Timer1 External Clock Input Synchronization Control bit...1 = Do not synchronize external clock input
  32. T1CON.TMR1CS = 0;    // bit 1 Timer1 Clock Source Select bit...0 = Internal clock (FOSC/4)
  33. T1CON.TMR1ON = 1;    // bit 0 enables timer
  34. TMR1H = 240;             // preset for timer1 MSB register
  35. TMR1L = 174;             // preset for timer1 LSB register
  36.  
  37.  
  38. // Interrupt Registers
  39.   INTCON = 0;           // clear the interrpt control register
  40.   INTCON.TMR0IE = 0;        // bit5 TMR0 Overflow Interrupt Enable bit...0 = Disables the TMR0 interrupt
  41.   PIR1.TMR1IF = 0;            // clear timer1 interupt flag TMR1IF
  42.   PIE1.TMR1IE  =   1;         // enable Timer1 interrupts
  43.   INTCON.TMR0IF = 0;        // bit2 clear timer 0 interrupt flag
  44.   INTCON.GIE = 1;           // bit7 global interrupt enable
  45.   INTCON.PEIE = 1;          // bit6 Peripheral Interrupt Enable bit...1 = Enables all unmasked peripheral interrupts
  46.  
  47.  
  48.   while(1)  //endless loop
  49.   {
  50.   }
  51. }

Ahora ya tenemos configurado el Timer para que haga 255 interrupciones por segundo
Lo unico que queda hacer es...

Poner un contador en la rutina de interrupcion que cuando llegue a 256, se ponga a 0 y comienze nuevamente.
El valor del ADC ( valor de 0 a 255 ) se compara con ese contador.

Suponete que el ADC mide 200. Cuando llega a 0 el contador pone a 1 la salida, y cuando llega a 200 el contador pone a 0 la salida

Código: C
  1. Contador++;
  2.  
  3. if ( Contador > ADCResultado )
  4. {
  5.    Salida = 0;
  6. }
  7. else
  8. {
  9.     Salida =1;
  10. }
  11.  
  12. if ( Contador == 255 ) { Contador = 0;}

Se podria evitar el ultimo if, si uno declara a contador como un numero sin signo y de 8 bits
Y tambien leeria el ADC un poco mas lento o solo actualizaria el valor del ADC ( me refiero a mover el dato de ADRES ( ADRESH:ADRESL si usas 16bits) a ADCResultado.
Asi evitas posibles mal funcionamientos.

PD:
Te dejo una calculadora del TMR
http://eng-serve.com/pic/pic_timer.html

Y lo hice en C, por que no sabia en que querias hacerlo, pero si usas ASM vas a poder pasarlo facilmente.

Fin...
« Última modificación: 04 de Junio de 2015, 20:34:05 por KILLERJC »

Desconectado ceci_lamorocha

  • PIC12
  • **
  • Mensajes: 94
Re: ajustar PWM a un periodo de segundos
« Respuesta #5 en: 12 de Junio de 2015, 13:26:29 »
Excelentisima la respuesta KILLERJC !!

 ahora me pongo a ver si me sale bien!!   :-/

gracias !


 

anything