Contraste de LCD por PWM y un filtro RC

Honestamente yo no entiendo qué es lo que pretendes hacer como proyecto final, y se me hace que lo que quieres hacer es una Término innecesariamente vulgar y te diría que entre tus cálculos considera que de lenguaje C se pasa a lenguaje ensamblador y cada instrucción es un ciclo de tiempo que debes meter en tu fórmula si quieres mucha precisión.

 
Última edición por un moderador:
honestamente yo no entiendo que es lo que pretendes hacer como proyecto final, y se me hace que lo que quieres hacer es una mamada (como se dice en mexico) y te diria que entre tus calculos considera que de lenguaje C se pasa a lenguaje ensamblador y cada instruccion es un ciclo de tiempo que debes meter en tu formula si quieres mucha precisión.


Realmente lo que necesito es poder mantener el duty cycle constante mientras varío la frecuencia del pwm. Pero no encuentro la forma de hacerlo. Esto es sólo una parte del proyecto final y necesito que cuando yo cambie la frecuencia por medio de
HTML:
setup_timer_2(t2_div_by_x,y,1);
, mantenga el duty al 50%.
 
¿y para que quieres cambiar la frecuencia y no el duty?

te lo pregunto para que no solo sino todos se den una idea clara. si ya lo mencionaste y los demas entendieron haz caso omiso de mi comentario XD
 
¿y para que quieres cambiar la frecuencia y no el duty?

te lo pregunto para que no solo sino todos se den una idea clara. si ya lo mencionaste y los demas entendieron haz caso omiso de mi comentario XD

Por que el contraste se trabaja por tension (y no corriente como la retroiluminacion) y supongo que esta implementando un filtro para generar esta tension variable..sera eso?
 
¿y para que quieres cambiar la frecuencia y no el duty?

te lo pregunto para que no solo sino todos se den una idea clara. si ya lo mencionaste y los demas entendieron haz caso omiso de mi comentario XD

No te preocupes si lo dejo más claro mejor.

Necesito variar la frecuencia porque el objetivo principal del proyecto es sacar pulsos precisamente a frecuencias determinadas. Estos pulsos irán a un multivibrador monoestable y tras él a un biestable, todo esto para acortar el ancho de pulso mucho más de lo que cualquier duty cycle me puede dar. Eso por una parte.

Por otro lado, al usar una lcd, necesito controlar también el contraste de ésta (a unas malas hago un divisor resistivo y aunque quede cutre funcionará). Mi idea principal era controlar el voltaje con PWM y un filtro RC, pero después me di cuenta de que la frecuencia del PWM es la misma para las dos salidas (ese fue mi fallo, por eso tengo el hardware diseñado con esa idea y necesito una solución lo más elegante posible)...

Y ahí está mi problema, necesito tener el duty del pwm fijo en la salida que va al contraste de la lcd para poder verla bien, pero teniendo en cuenta que por el funcionamiento pricipal del dispositivo voy a trabajar con diferentes frecuencias, y cambia la resolución de duty, etc.

Ahora mismo estoy pensando en que también puedo usar pwm por software para el objetivo principal de los pulsos y dejar el pwm hardware para la lcd. Pero ahora surge entonces el otro problema, que no tengo ni idea de cómo se hace el pwm por software, qué rango de frecuencias puedo alcanzar con él y si es fácil de modificar sus parámetros con variables.
Tengo que aclarar que para la función de los pulsos no necesito que el pwm esté activo siempre, sino sólo desde que le de a "start" y hasta que pulse "stop" , para entendernos. A diferencia del que controla el contraste de la lcd.

Creo que ya está más claro el tema y mi problema, a ver si a alguien se le ocurre una solución buena o me muestra cómo usar bien el pwm por software.

Gracias de nuevo
 
Pero puedes obtener ambos pulsos por software, pero por supuesto respetando el orden de programación. Mientras controlas la frecuencia no podrás controlar el contraste y viceversa. Yo utilizaría el modulo CCP para la frecuencia principal y cualquiera de los Timers restantes para el control del contraste.
 
Al parecer lo que necesitas es generar una señal de frecuencia variable con ciclo de trabajo fijo (50%). No entiendo porque complicarse con PWM (que además no tiene nada que ver con tu objetivo). Lo único que necesitas es cargar uno de los timers (TIMER1 por ejemplo) con un el valor adecuado (dependiendo del oscilador que uses y de la frecuencia deseada) y cada vez que el temporizador desborde cambiar el estado del pin de salida de la señal (a alto o bajo, según corresponda). En otras palabras, con un timer generas ½ periodo de la señal deseada, cada que se cumpla este ½ periodo, cambias de estado la salida…


Y dejas el PWM para el control del contraste del LCD, exclusivamente.
 
Al parecer lo que necesitas es generar una señal de frecuencia variable con ciclo de trabajo fijo (50%). No entiendo porque complicarse con PWM (que además no tiene nada que ver con tu objetivo). Lo único que necesitas es cargar uno de los timers (TIMER1 por ejemplo) con un el valor adecuado (dependiendo del oscilador que uses y de la frecuencia deseada) y cada vez que el temporizador desborde cambiar el estado del pin de salida de la señal (a alto o bajo, según corresponda). En otras palabras, con un timer generas ½ periodo de la señal deseada, cada que se cumpla este ½ periodo, cambias de estado la salida…


Y dejas el PWM para el control del contraste del LCD, exclusivamente.

Creo que voy a probar esta opción, puedes confirmarme que lo que dices es lo mismo que este ejemplo?
http://www.aquihayapuntes.com/indice-practicas-pic-en-c/uso-del-tmr0-como-temporizador.html

Gracias!
 
Hola @jipc. El ejemplo en el enlace que publicaste es muy bueno. Lo mire brevemente y según parece cada 32ms cambia el estado del pin RB7, es decir genera una señal perfectamente cuadrada de 1/(2*32ms) =15.625Hz; para cualquier otra frecuencia es solo cuestión de calcular el valor adecuado para el pre-escalador y el valor a cargar en el TMR0. Aunque en el caso de este último Yo no elegiría este método, pues mientras el PIC atiende la interrupción el tiempo continua su avance y como simultáneamente la cuenta sobre el TMR0 continúa incrementándose lo mejor es calcular un valor de ajuste para sumárselo al TMR0; de esa manera logras mejor precisión.


Saludos, espero te sirva lo comentado…
 
Hola @jipc. El ejemplo en el enlace que publicaste es muy bueno. Lo mire brevemente y según parece cada 32ms cambia el estado del pin RB7, es decir genera una señal perfectamente cuadrada de 1/(2*32ms) =15.625Hz; para cualquier otra frecuencia es solo cuestión de calcular el valor adecuado para el pre-escalador y el valor a cargar en el TMR0. Aunque en el caso de este último Yo no elegiría este método, pues mientras el PIC atiende la interrupción el tiempo continua su avance y como simultáneamente la cuenta sobre el TMR0 continúa incrementándose lo mejor es calcular un valor de ajuste para sumárselo al TMR0; de esa manera logras mejor precisión.


Saludos, espero te sirva lo comentado…

Se lo que me quieres decir pero no estoy seguro de cómo expresarlo en el código. En set_TIMER0(0x83) añadirle dentro la suma de una variable con el valor del ajuste?

Por cierto, en mi proyecto no se va a cambiar la el valor de la frecuencia al mismo tiempo en el que se está ejecutando dicha frecuencia. Quiero decir que selecciono el valor que quiero, me voy a otro menú y ahí inicio la ráfaga de pulsos a esa frecuencia seleccionada, hasta que manualmente lo pare. De hecho aún tengo que ver cómo se desactivan las interrupciones, es la primera vez que trabajo con ellas

Gracias de nuevo!
 
Pues sólo es cuestión de cargar en el timer su valor actual más el valor de ajuste. (0x83 para el ejemplo actual)
Cabe notar, que en éste ejemplo (el del link que publicaste) no habría problema de desajustes, pues el pre-escalador está puesto a 256, y por tanto, mientras la interrupción es atendida, los ciclos de máquina que transcurran se verán registrados precisamente en el pre-escalador, y cuando hagas el ajuste del TIMER, lo más seguro es que éste último aún esté en “cero” (pues no creo que en atender la interrupción se consuman más de 256 ciclos de máquina) y será indiferente si simplemente lo estableces a 0x83 o si lo haces con su valor actual (0x00) más 0x83.

El problema vendría cuando de generar frecuencias altas se trate, y te veas en la necesidad de usar valores muy bajos para el pre-escalador, o incluso prescindir de él; podría ocurrir que al retorno de atender la interrupción, el TIMER haya avanzado en su cuenta (ya no contenga 0x00).
En ese caso lo correcto sería recargarlo con su valor actual mas el valor de ajuste calculado.

Por otro lado, no me queda claro cómo es eso de colocar después del PIC un monoestable.
Para dispararlo no necesitas de una señal, precisamente con ciclo útil del 50% ?
Y sobre todo, me resulta difícil de comprender, qué haría después un biestable.

¿Nos podrías contar también; qué tan angosto necesitas el ciclo útil de la señal definitiva?
 
Última edición por un moderador:
Pues sólo es cuestión de cargar en el timer su valor actual más el valor de ajuste. (0x83 para el ejemplo actual)
Cabe notar, que en éste ejemplo (el del link que publicaste) no habría problema de desajustes, pues el pre-escalador está puesto a 256, y por tanto, mientras la interrupción es atendida, los ciclos de máquina que transcurran se verán registrados precisamente en el pre-escalador, y cuando hagas el ajuste del TIMER, lo más seguro es que éste último aún esté en “cero” (pues no creo que en atender la interrupción se consuman más de 256 ciclos de máquina) y será indiferente si simplemente lo estableces a 0x83 o si lo haces con su valor actual (0x00) más 0x83.

El problema vendría cuando de generar frecuencias altas se trate, y te veas en la necesidad de usar valores muy bajos para el pre-escalador, o incluso prescindir de él; podría ocurrir que al retorno de atender la interrupción, el TIMER haya avanzado en su cuenta (ya no contenga 0x00).
En ese caso lo correcto sería recargarlo con su valor actual mas el valor de ajuste calculado.

Por otro lado, no me queda claro cómo es eso de colocar después del PIC un monoestable.
Para dispararlo no necesitas de una señal, precisamente con ciclo útil del 50% ?
Y sobre todo, me resulta difícil de comprender, qué haría después un biestable.

¿Nos podrías contar también; qué tan angosto necesitas el ciclo útil de la señal definitiva?

Pero... el problema que dices cuando se cambia un valor estando el timer activo ¿no se puede solucionar desactivando el timer0 cuando modificamos sus valores y luego iniciarlo todo otra vez?

Como te digo, en mi programa principal primero selecciono la frecuencia, luego me voy a otro menú y enciendo la ráfaga de pulsos a esa frecuencia y no se puede cambiar. El duty cycle no cambia, lo necesito al 50% siempre. Sólo necesitaba cambiarlo para el contraste de la lcd, pero eso lo voy a hacer como dijiste por pwm.

El concepto del circuito, el uso del monostable y posteriormente el biestable lo puedes ver en la pagina 7 de aquí http://m.eet.com/media/1151236/21978-51100di.pdf

Gracias!
 
Última edición:
no se estaran complicando mucho la existencia?
que no con un simple toggle dentro de la rutina de interrupcion de un timer es suficiente.
si se desea una frecuencia de 100Hz ejem entonces se define el la int a 200Hz y se pone un toggle y vuala siempre es al 50%

 
Las interrupciones se desactivan con el registro INTCON, pero para ser mas preciso debes leer bien la hoja de datos. De cajón te dan la formula para calcular el valor del TMR (Timer0 y Timer1) o el PR2 (para el Timer2), así que si vas a cambiar la frecuencia debes parar las interrupciones, luego calcular el nuevo valor del TMR o PR2, resetearlo y luego volver a habilitar la interrupción. Serian varias sub-rutinas y lineas de código, nada es fácil en esta vida.

O también podrías guardar el valor de la variable en la EEPROM del microcontrolador, resetearlo y que comience con el valor guardado. Obvio tendrías que presionar el botón de reset cada vez que cambies de frecuencia. Pero igual implica varias lineas de código.

No has pensado utilizar dos microcontroladores conectados entre si? Mientras uno genera la frecuencia, el otro le manda las ordenes en serie o paralelo.
 
Última edición:
Saludos señores. Al parecer hay cosas que no se han comprendidos del todo:


En el post #27
cada vez que el temporizador desborde cambiar el estado del pin de salida de la señal (a alto o bajo, según corresponda).


En el post #33
con un simple toggle dentro de la rutina de interrupcion de un timer es suficiente.


Creo que hablamos de lo mismo. ¿Cierto?


En el post #30
Por cierto, en mi proyecto no se va a cambiar la el valor de la frecuencia al mismo tiempo en el que se está ejecutando dicha frecuencia.


Y en el #32
Como te digo, en mi programa principal primero selecciono la frecuencia, luego me voy a otro menú y enciendo la ráfaga de pulsos a esa frecuencia y no se puede cambiar. !


Estas confundido estimado @jipc. El constante ajuste del TIMER en cuestión no es para cambiar la frecuencia, es para mantenerla en su valor.


Te explico: el TIMER en cuestión sea el TIMER0, TIMER1 y TIMER3 producen interrupción ante un desbordamiento de su contenido (cuando pasa de su valor máximo a cero). Para generar una señal a una frecuencia determinada, con el método que te propuse es necesario ajustar el TIMER involucrado en cada semi-ciclo de la señal, pues este TIMER incrementará su contenido, al ritmo de los ciclos de máquina desde cierto valor inicial (el de ajuste) hasta su máximo valor, se desbordará, producirá una interrupción, en ella se deberá cambiar el estado de la señal generada (toggle como bien lo llama @papirrin) retornará de la interrupción, se reajustará de nuevo el TIMER para generar el siguiente semi-ciclo, y así continuará hasta que por menú lo detengas….


Nota: al inicio del párrafo anterior, no te mencioné el TIMER2, porque no lo podrás usar debido a que estará ocupado con el PWM, manejando el contraste del LCD. Cabe mencionar además que el TIMER2 a diferencia de los otros, produce interrupción no cuando se desborda sino cuando su contenido es igual al del contenido del registro PR2, y me parece que justamente es el motivo de tu confusión….


Mas tarde trataré de hacer un tiempito para escribir unas líneas de código a manera de ejemplo de lo expuesto.


Cualquier cosa a la orden…


Ah… otra cosa; lo expuesto por @ruben90 (post #34) nada que ver con la idea que se está manejando…

Edito: El ajuste del TIMER debe hacerse dentro de la misma rutina que atiende la interrupción.
 
Última edición:
Ah, pues sí es lo que dices, creía que funcionaba como el timer2. :unsure:
La verdad es que te agradecería muchísimo ese ejemplo que dices y de nuevo gracias por la ayuda, voy mal de tiempo y con tus explicaciones estoy aprendiendo bastante más rápido.

Tendría que calcular qué rango de frecuencias puedo tener con el prescaler a 256 y el pic a 48 MHz, si me valen es posible que nos quitemos esos problemas.

Saludos.
 
Última edición por un moderador:
A continuación lo ofrecido:

Configuré la parte del oscilador para que corra a 32MHz. Implica que los ciclos de máquina lo harán a 32/4 = 8MHz, y que por tanto tendrán, un periodo de 125nS. Esta será la base de tiempo primaria.

Me he propuesto generar una señal de 1KHz. Para ello: configuro el pre-escalador en “1:8”, a su salida tendré una señal con periodo 125nS x 8 = 1uS, muy conveniente a mi parecer para desde aquí sintetizar cualquier frecuencia (inferior a 500KHz, por supuesto).

Una señal de 1KHz tiene un periodo de 1mS; para generarla necesitaré semi-ciclos de 500us. Es decir, el TIMER0 deberá desbordar (y producir interrupción, obviamente) cada 500 pulsos que le entregue el pre-escalador. Para ello, en primer lugar necesito configurarlo a 16 bits y el valor de ajuste será 65536 – 500 = 65036, en binario 11111110 00001100 (11111110 para el byte alto -MR0H- y 00001100 para el byte bajo -TMR0L- )

Código:
sbit signalOut at PORTC.B1;     //salida de señal por el pin 1 del PORTC

void main() {
     TRISC.B1 = 0;              //pin asociado a signalOut como salida
     TMR0IE_bit = 1;            //interrupcion del TIMER0 habilitada
     GIE_bit = 1;               //Interupciones globales habilitadas
     T0CON = 0b10010010;        //TIMER0 ON, 16 bits, fuente ciclos de maquina,
                                //pre-escalador asignado, 1:8
     TMR0H = 0b11111110;        //valores iniciales
     TMR0L = 0b00001100;        //para TIMER0
     
     while(1){
     
     }
}

void interrupt(void){           //cada vez que TMR0 produce interrupción:
     signalOut = !signalOut;    //cambia el estado de la señal de salida
     TMR0H = 0b11111110;        //reajusta el TIMER, byte alto
     TMR0L += 0b00001100;       //y byte bajo
     TMR0IF_bit = 0;            //limpia la bandera de interrupción del TIMER0
}
Adjunto una imagen de simulación en Proteus…

1KHz.jpg

PD. El código está escrito en mikroC, pero pienso que no tendrás problema en pasarlo al que Tú estés usando (CCS supongo).
Además: con el PDF que subiste comprendí lo de los monoetables … Sin embargo te hago notar que con el PIC puedes producir señales con ciclos de trabajo de 125ns trabajando 32MHZ e incluso 83,333nS trabajando a 48MHz; si tus requerimientos andan por ahí, podrías obviarte esa parte de hardware y aprovechar mejor los recursos que te ofrece el micro-controlador…
 
Última edición:
A continuación lo ofrecido:…

Aquí estoy de nuevo, tras probar el ejemplo y varias opciones. Lo primero el codigo:
Código:
#include <18F4550.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL6,CPUDIV2,VREGEN,NOPBADEN   // usando cristal de 24 Mhz -> PLL=6 para los 48 Mhz del USB y CPUDIV2 para 32 MHz de la CPU 
#use delay(clock=32MHz)  

#INT_TIMER0
void  TIMER0_isr(void)   // funcion que se ejecuta cuando se produce la interrupcion
{

output_toggle(pin_c1);
set_timer0(65036); 

}

void main()
{
   

   
   enable_interrupts(INT_TIMER0);                    // activa desbordabiento del Timer0

   enable_interrupts(GLOBAL);              
            
    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);    
    
    set_timer0(65036);                             
                                                    
   while(TRUE)
   {
     
   }

}

Pues bien, si hago el mismo ejemplo para tener una señal de 1 kHz, obtengo una frecuencia de 988 Hz, tiene un pequeño error pero me valdría.

El problema viene cuando, por ejemplo, pruebo con 50 kHz. Según los mismo cálculos tendríamos 1 uS por pulso ((32 MHz / 4) * prescaler 8) y para una señal de 50 kHz debemos hacer toggle a una frecuencia de 100 kHz (cada semiperiodo), que hace un total de 10 uS lo que debemos temporizar. 10 uS/1 uS = 10 pulsos que restar a 65536.

Pues con todo esto, lo simulo con un valor de 65526 y en lugar de los 50 kHz me salen 30 kHz...

Lo único que se me ocurre es a partir de lo que he leído, que CCS introduce algunas líneas de código ocultas y puede que eso me fije el límite de lo que puedo sacar.
Entiendo que los fuses están bien ya que para 1 kHz si va bien la cosa, pero no entiendo el problema realmente.

De nuevo un saludo y muchas gracias!
 
CCS es un lenguaje de alto nivel, eso quiere decir que genera un código de bajo nivel y eso es a lo que tu llamas "lineas ocultas" cada líneas oculta es un ciclo del CPU del micro controlador. Para ser mas preciso en esos ciclos es mejor programar en ASM, creo que ya te lo había mencionado antes. También debes tener en cuenta que las simulaciones no son precisas en cuestión de tiempos y algunas otras cosasXD.

 
Atrás
Arriba