TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: pirata88 en 29 de Agosto de 2009, 14:04:35

Título: Error en frecuencia Timer1
Publicado por: pirata88 en 29 de Agosto de 2009, 14:04:35
Hola, el problema esque tendria q generarse una onda cuadrada ( por software ) de 880Hz, pero sin embargo no da 880...sino unos 746Hz, la formula es clara, viene en el programa y si me equivoco por algun lado...seria de gran ayuda saber en donde, gracias y ay va el programa


#include <16f628a.h>
#use standard_io(a,b)
#fuses intrc_io, NOWDT, NOMCLR, NOBROWNOUT, NOLVP, NOCPD
#use delay(clock = 4000000)

#define ONDA PIN_B5

//T=Tosc*4*Preescaler*N
//Tosc es periodo reloj ( 4Mhz), 4 por el tiempo de ejecucion de cada instruccion, N el numero a cargar en timer1
//para una frecuencia de 880Hz, el numero N es 568.1818
//es decir, para una onda cuadrada de 880Hz generamos interrupcion con frecuencia de 1760Hz


float A=568.1818;

int16 A1=0;

int1 e=0;



#int_timer1
void Segunda_Onda(void)
{

if ( e==0){

A1=A;

set_timer1(65536-A1);
output_high(ONDA);
e=1;
}
else {

set_timer1(65536-A1);
output_low(ONDA);
e=0;
}


}





void main (void) {


disable_interrupts(global);

setup_timer_1 (T1_INTERNAL | T1_DIV_BY_1 );

disable_interrupts(INT_TIMER0);
enable_interrupts(INT_TIMER1);
disable_interrupts(INT_TIMER2);
disable_interrupts(INT_RB);
disable_interrupts(INT_EXT);
disable_interrupts(INT_TBE);
disable_interrupts(INT_RDA);
disable_interrupts(INT_CCP1);
disable_interrupts(INT_COMP);
enable_interrupts(global);
set_timer1(50000);

do {



}
while(true);
}
Título: Re: Error en frecuencia Timer1
Publicado por: Suky en 29 de Agosto de 2009, 15:12:48
El problema surge en las instrucciones que CCS realiza para salvaguardar los registros y seleccionar que interrupción se ha generado. Debido a eso es complicado tener exactitud. Puedes usar el módulo CCP en modo PWM para generar la señal.


Saludos!
Título: Re: Error en frecuencia Timer1
Publicado por: pirata88 en 30 de Agosto de 2009, 07:19:27
Podria no ser exacto en unos cuantos Hz, pero esque difieren mucho...nose, tendre q averiguar eso del pwm del timer 2
Título: Re: Error en frecuencia Timer1
Publicado por: Suky en 30 de Agosto de 2009, 10:27:19
No, fíjate que estas trabajando a 4MHz, osea Tcy=1us. Y la diferencia entre periodos de la deseada y la que estas obteniendo es de 204us, 204 instrucciones. Estas pueden ser la suma de lo anterior mencionado mas las instrucciones realizadas dentro de la interrupción (If/else)


Saludos!
Título: Re: Error en frecuencia Timer1
Publicado por: fabianjsm en 30 de Agosto de 2009, 12:15:50
Deberias optimizar un poco tu codigo quitando esas estructuras condicionales que estan ocacionando la perdida de tiempo.
La cuestion es que programando en lenguajes de alto nivel pierdes la nocion del tiempo y del espacio (que loco!).
En vez de utilizar la variable 'e' para controlar el nivel actual de la onda, podrias invertir directamente el quinto bit con un XOR.
No estaria mal definir ademas un valor de correccion que te permita 'calibrar' la frecuencia hasta que logres el valor buscado.
Quedaria algo asi, donde K es la correcion (solo toma valores enteros mayores o igual a cero):

Código: C
  1. #define K 0
  2. #define T 65536-568
  3. #int_timer1 void Segunda_Onda(void)
  4. {
  5.     PORTB ^= 32;
  6.     set_timer1(T-K);
  7. }

La diferencia de frecuencia con la que te encuentres es el valor que deberas asignarle a K.
Título: Re: Error en frecuencia Timer1
Publicado por: ppyote en 30 de Agosto de 2009, 17:39:53
A1=A; ??

si el valor A es un valor de 32bits, y A1 es un valor de 16 bits... lo que pasara es que se desbordara, no crees?
Título: Re: Error en frecuencia Timer1
Publicado por: pirata88 en 31 de Agosto de 2009, 06:02:49
El caso esque esa frecuencia puede cambiar desde los 2000 Hz hasta 32.7 Hz, tendre q corregir el parametro K, ya lo habia hecho con los servos este año, controlaba 8 servos con un timer y tenia 16 comparaciones jeje, no habia pensao en lo de xor gracias!
A1=A solo es para que se copie la parte no decimal, ya que el timer no va cargar los decimales xD, porque las frecuencias aveces tienen decimales y se le aplican efectos...enfin que puede aparecer una frecuencia de 345.6 y al aplicarle la formula para obtener el numero es mas preciso con decimales que sin ellos, o sino como lo hago? como paso de un float a int16? si yo paso float a int16 los numeros despues de las comas, desaparecen, o eso me han explicado ami desde siempre, por lo que no se va desbordar...o me equivoco?
Título: Re: Error en frecuencia Timer1
Publicado por: ppyote en 31 de Agosto de 2009, 07:53:42
No estoy seguro pero creo que te desbordara, aunque no estoy seguro... todo es mirarlo
pues con A1=(int16)A //te lo hara

prueba a ver que tal

puedes crear otro int 16 guardando los 4 ultimos decimales,

int16 prueba;

prueba=(A*10000)%10000;
Título: Re: Error en frecuencia Timer1
Publicado por: reiniertl en 01 de Septiembre de 2009, 13:04:38
Prueba a utilizar TIMER1+CCP en modo comparación, con eso lo que tienes que hacer es ajustar el valor de comparación del módulo CCP cuando quieras que la frecuencia de salida sea otra y listo en la interrupción del CCP sólo tienes que cambiar el valor del pin que quieres a 1 ó 0 según sea el caso.

Más explicado:

Utilizar TIMER1+CCP para hacer un contador ascendente con tope configurable. Es decir auxiliarse del CCP para resetear el TIMER1 cuando éste llegue a un valor determinado, como el CCP hace este trabajo por hardware no hay que estar escribiendo el temporizador, cosa que seguramente es la causa de tu actual error.

Luego bastaría con cambiar el valor de "corte" para el TIMER1 en el módulo CCP cuando quieras una frecuencia diferente.

Como quieres un tren de pulso simétrico de ciclo útil 1/2 (50%) tienes que hacer que el TIMER1 se resetee dos veces por pulso, es decir un reset para el estado lógico alto y otro para el estado lógico bajo, así que en el ejemplo que pones se debe resetear el TIMER con una frecuencia de 440Hz.

En la interrupción del CCP (ahora ya no utilizarías la del TIMER1) lo único que tienes que hacer es cambiar el estado del pin por donde debe salir la onda cuadrada y listo.

En cualquier otra parte del programa cambiar el valor del registro CCP, cuando sea necesario (igual a como cambias ahora la variable que determina la frecuencia de interrupción del timer)

Yo creo que con eso debe bastarte

saludos
Reinier