Haz una pregunta
  Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos
Foros Registrarse ¿Olvidaste tu contraseña?

Temas similares

16/02/2012 #1


Problemas con TIMER0 y PIC 16F877A
Buenas, el problema es el siguiente, estoy diseñando un tacomentro para auto con un PIC y un LCD.
La primer versión contaba las variaciones de entradas en la pata A1 por cada siclo completo del programa (incluía un delay_ms(1) al final del bucle principal), al tener 200ms de registros procesaba la información.
Esto no me permitía tener una buena resolución, procesando cada 200ms tengo una resolución de 150rpm.

Opte por contar 4 pulsos y en base al tiempo transcurrido medir las rpm.
Esta cuenta la hice agregando un dalay_us(100) al final del bucle principal.
Para hacerlo mas profesional pase a usar la interrupción TIMER0 pero el problema es que esta interrupción esta corriendo mas lento de lo que debería y reporta peor las RPM que el precario sistema de poner un delay al final del bucle principal.

El codigo es el siguiente:

Código:
#include <16f877A.h>                         /* PIC16F877A */
#fuses HS,NOWDT,NOPROTECT,PUT,NOLVP,BROWNOUT /* Fusibles (lo mas comun) */                                            
#use delay (clock=20000000)          /* Ajuste retardos 20M*/
//#use delay (clock=4000000)          /* Ajuste retardos 4M*/
#use fast_io(a)                              /* Opcional */

#define LED_SHIFT  PIN_C1
#define RPM_SIG PIN_A0 //IN

#include <lcd.c>

//VARIABLES!
int32 tmp1;//USO TEMPORAL.-
int32 tmp2,tmp3,tmp4;//USO TEMPORAL.-
long rpmant,rpm,rpmcount;//RESULTADO DE RPM Y CUENTA PARCIA.-
short int rpmhi,velhi;//GUARDA ESTADO DE SENSORES.-

int32 rpmtime1,rpmtime2;

void sensores2()
{
	if((input(RPM_SIG)) && !rpmhi)
	{
		rpmhi=1;
		rpmcount++;
		if(rpmcount==1)
		{
			rpmtime1=tmp3;
		}
		else if(rpmcount==2)
		{
		/*
			DEBERIA HACER 20.000 SICLOS CADA 1 SEGUNDO
			EN REALIDAD HACE 15.533 POR SEGUNDO
		*/
			rpmcount=0;
			rpmtime2=tmp3;
			tmp1=rpmtime2-rpmtime1;
			//rpm=1200000/2/tmp1; //VALOR IDEAL (20.000 * 60) /2 /tmp1
			rpm=932000/2/tmp1; //VALOR FORZADO (15533 * 60) /2 /tmp1
			tmp3=0;
		}
	}
	if((!input(RPM_SIG)) && rpmhi)
	{
		rpmhi=0;
	}
}


#int_TIMER0
Void TIMER0_isr(void)
{

	tmp3++; //LO USO PARA VER LA VARIACION EN TIEMPO DENTRO DE sensores(); 
	tmp2++; //LO USO PARA PRENDER Y APAGAR UN LED CADA 1 SEGUNDO.

	if(tmp2==10000)
	{
		output_high(LED_SHIFT);
	}
	if(tmp2==20000)
	{
		tmp2=0;
		output_low(LED_SHIFT);
	}

	sensores2(); //RECIBO DATA DE RPM Y PROCESO.
	set_timer0(0);

}

//PROGRAMA PRINCIPAL !!!
void main(void)
{
	lcd_init();

	setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
	enable_interrupts(GLOBAL | INT_TIMER0); 
	set_timer0 (0);

	rpmcount=0;
	rpm=0;

	while(TRUE)
	{

		printf(lcd_putc,"\fTMP1: %Lu", rpmtime2);
		printf(lcd_putc,"\nTMP2: %Lu", rpm);

		delay_ms(1);
	}
}
Espero se haya entendido y puedan ayudarme.
Saludos,
Federico.
16/02/2012 #2

Avatar de Basalto

Hola, en tu caso para un programa siempre y que se necesita un buena precisión para medir tiempos, haría el programa en ASM. Un saludo
16/02/2012 #3


Pero estoy haciendo algo mal? es bastante simple como para que falle me parece.
La verdad asm no se nada de nada, a C me estoy adaptando porque manejo php y perl.
16/02/2012 #4

Avatar de Basalto

Aumenta el preescalado del timer 0, ya que creo que se desborda antes de que acabe de tratar la interrupcion. Un saludo
17/02/2012 #5


nose si en C tiene el comando pulsin pero si lo tiene podes usarlo para medir cuanto tarda en dar una vuelta y hacer el calculo
17/02/2012 #6


La verdad es que ya no se que pensar, les muestro el ultimo codigo de pruebas.
Defino TIMER0 y TIMER1 (son lo que pienso usar en mi programa).
Cambiando el Prescaler del TIMER0 me varia considerablemente el resultado:

CODIGO:
Código:
#include <16f877A.h>                         /* PIC16F877A */
#fuses HS,NOWDT,NOPROTECT,PUT,NOLVP,BROWNOUT /* Fusibles (lo mas comun) */                                            
#use delay (clock=20000000)          /* Ajuste retardos 20M*/
//#use delay (clock=4000000)          /* Ajuste retardos 4M*/
#use fast_io(a)                              /* Opcional */

#include <lcd.c>
int32 tmp1;//USO TEMPORAL.-

#int_TIMER0
void TIMER0_isr(void)
{
	//tmp1 ++;
	//delay_us(1);
}

//PROGRAMA PRINCIPAL !!!
//PROGRAMA PRINCIPAL !!!
void main(void)
{
//CON ESTO EL LCD IMPRIME 6318:
	setup_timer_0(T0_INTERNAL | RTCC_DIV_1);
//CON ESTO EL LCD IMPRIME 5122:
//	setup_timer_0(T0_INTERNAL | RTCC_DIV_8);

	enable_interrupts(GLOBAL | INT_TIMER0);
	set_timer0(0);


	setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
	set_timer1(0);

	lcd_init();
	while(TRUE)
	{
		tmp1=get_timer1();
		printf(lcd_putc,"\f%Lu", tmp1);
		set_timer1(0);
		delay_us(1000);
	}
}
La verdad no se que hacer, porque cualquier cambio varia la precisión de los TIMERS.
Sera un problema de la simulación?
17/02/2012 #7


Podes hacer asi, no programo en C asi que te lo explico en palabras. (lo calcule con un cristal de 20Mhz)

Usas 2 interrupciones, una por timer y otra por RB0

La interrupcion TIMER0 la configuras para que salte cada 10us e incremente la variable "tiempo"
Configuras el preescaler en 2 y el TMR0 en 230
entonces


A 20 Mhz son 5000000 int/seg
5000000/2=2500000 inst/seg (divido por 2 con el preescaler)
2500000/25= 10000 inst/seg (El TMR0 esta en 230 entonces cuenta 25 y desborda)
1seg/10000 = 0.0001 = 10us (Salta la interrupcion TMR0 casa 10us)


Cuando salta el timer pone que incremente en 1 la variable tiempo "inc tiempo" o "tiempo = tiempo +1"
Y Cuando salta la interrupcion RB0 pone que haga esta cuenta y te da las rpm "RPM=6000000/tiempo"


Bueno espero haber echo bien los calculos
Respuesta
¿Tienes una mejor respuesta a este tema? ¿Quieres hacerle una pregunta a nuestra comunidad y sus expertos? Registrate

Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO ©2011, Crawlability, Inc.