Cronometro con Atmega32

Hola compañeros, necesito ayuda con la programación de un cronometro con un Atmega32, no soy muy conocedor, pero los atmega han sido los únicos micros que e programado, necesito hacer un cronometro donde pueda ingresar el tiempo a medir, con el código que hice solo he podido hacer el contador de 9min, ne he podido guardar el registro del tiempo para poder hacer una pausa y de nuevo le reanudación del tiempo. La programación esta con el Timer1, entonces quisiera saber de que forma puedo hacer un tipo de delay donde pueda conservar el ultimo registro de tiempo, y que después pueda restaurar el conteo donde había quedado.
Agradezco de gran manera sus comentarios y ayudas
 

Adjuntos

  • codigo.txt
    7.9 KB · Visitas: 15
Te tiro una par de ideas, después fijate si te sirven:

1- Usar un cristal, nada de usar el oscilador R-C interno.

2- Como es un cronómetro, al menos deberías mostrar décimas de segundos, lo ideal sería centésimas. Por lo tanto si son centésimas, tu base de tiempo en el timer deberá ser de 10mS, si son décimas 100mS.

3- Usar dos vectores "unsigned char" (hora, min, seg, centésimas), uno con el valor actual de cuenta y otro con el parcial (incluso podrías hacer varios parciales). La actualización de esos del primer vector lo haría con una función que tendrá varios condicionales típicos de un reloj.

4- Para hacer algo bien fácil podrías usar dos pulsadores, 1 para almacenar el parcial/arrancar la cuenta, otro para parar la cuenta/resetear la cuenta. Esos dos pulsadores irían a las dos pines de interrupción externa que tenés.

5- El manejo del display (no se que usarás), dependerá mucho de lo que busques, pero si usas un LCD 2x16, podrías dejar la línea de arriba para la cuenta actual y en la línea inferior el último parcial, incluso si tenés varios parciales, podrías ir rotando la pantalla para ir mostrándolos.
 
Hola Cosmefulanito este cronometro no lo necesito, con décimas, solo lo voy a usar con números enteros, el reinicio del cronometro por razones de rapidez lo hice con el reset del atmega, y pues también por razones de simplicidad activar la pausa y la reanudación con un pulso de un pin, pero he tenido problemas justo con el almacenamiento del parcial, y de nuevo continuar con la cuenta. La visualización por ahora con dígitos de 7 segmentos.
 
Ok.

- Lo del reseteo no está mal si no usas las centésimas/décimas.
- LCD no vá, entonces con los 7 segmentos, con un pulsador cambias entre parcial/cuenta actual.
- El otro pulsador lo podrías dejar solo para almacenar el último parcial.

Si te sirve, te dejo este código que hice para un RTC por soft para un atmega16/128 (obviamente te va a servir para un atmega32). Lo que hice yo fue usar el oscilador interno R-C como clock para el uC y un cristal de 32,768 kHz para el RTC.

PHP:
#define SEGUNDO			0
#define MINUTO			1
#define HORA			2
#define DIA			3
#define MES			4
#define ANIO			5
#define BISIESTO		6
#define TAMANIO_VECTOR_RTC	7

void RTC_MES_ANIO(u8 hora[])
{
	if(hora[MES]>=12)
		{
			hora[MES]=1;
			
			hora[ANIO]++;
			
			if((hora[ANIO]%4)==0)
				hora[BISIESTO]=1;
			else
				hora[BISIESTO]=0;
		}
	else
		hora[MES]++;
}

void RTC_DIA(u8 hora[])
{
	hora[DIA]++;
	
	if(hora[MES]==2)
		{
			if(hora[BISIESTO])
				{
					if(hora[DIA]>=30)
						{
							hora[DIA]=1;
							RTC_MES_ANIO(hora);	
						}
				}
			else
				{
					if(hora[DIA]>=29)
						{
							hora[DIA]=1;
							RTC_MES_ANIO(hora);	
						}
				}	
		}//febrero
	else
		{
			if((hora[MES]==4)||(hora[MES]==6)||(hora[MES]==9)||(hora[MES]==11))
				{
					if(hora[DIA]>=31)
						{
							hora[DIA]=1;
							RTC_MES_ANIO(hora);	
						}
							
				} //30 dias
			else
				{
					if(hora[DIA]>=32)
						{
							hora[DIA]=1;
							RTC_MES_ANIO(hora);	
						}
				} //31 dias
		}//El resto de los meses
}

void RTC_HORA(u8 hora[])
{
	
	if(hora[SEGUNDO]>=59)
		{
			hora[SEGUNDO]=0;
			
			if(hora[MINUTO]>=59)
				{
					hora[MINUTO]=0;
					
					if(hora[HORA]>=23)
						{
							hora[HORA]=0;
							RTC_DIA(hora);
						}
					else
						hora[HORA]++;
				}
			else
				hora[MINUTO]++;
		}
	else
		hora[SEGUNDO]++;
	
}

Desde main hacía esto:

PHP:
//-------------- Definiciones de tipos de variables
typedef unsigned char u8;
typedef unsigned int u16;
//-------------- Definiciones de tipos de variables

//.... Código necesario 

int main(void)
{
  //--------------- VECTOR HORA PARA EL RTC -----------//
  u8 vector_hora_rtc[TAMANIO_VECTOR_RTC]={1,1,1,1,1,13,0}; //Defino la hora actual!
  //--------------- VECTOR HORA PARA EL RTC -----------//	
  
  //... Inicialización del timer0 IMPORTANTE!
  
  while(1)
  {
    if(flag_timer0)
      {
        RTC_HORA(vector_hora_rtc);	//Actualizo el vector RTC
        ...
       } //La interrupción del Timer 0 saltaba c/1 seg debido al cristal de 32,768 kHz
   }
}

A vos no te resulta útil la fecha ni si es año bisiesto, por lo tanto podrías recortar bastante ese código.

El cristal de 32,768kHz en los pines TOSC1 y TOSC2 sin capacitores ni nada, de una. Y según el modelo de uC, configurar el timer, en el atmega128 es el timer 0, en el atmega16 creo que era el timer 2 (no recuerdo, es cuestión de ver la hoja de datos).
 
Última edición:
Hola cosmefulanito, gracias por la ayuda, la verdad es que me sirvió pero no he podido con el asunto de que despues de pausarlo y reiniciarlo pueda volver a pausarlo, mejor dicho, solo se puede pausar y reanudar una sola vez, no se como solucionar ese problema, ahí va el codigo


Código:
#include <avr/io.h>
#include <stdio.h>
#include <stdlib.h> 
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>


// -----------------------------------------------------------------------------
//*********************** Definiciones de Variables Globales *******************
// -----------------------------------------------------------------------------

volatile int frac, segundos, decima, pausa;

// -----------------------------------------------------------------------------
// ************************* Definiciones y Macros *****************************
// -----------------------------------------------------------------------------

#define T1_INI  53035    //0.1s  Fosc=8M  Esc=64

//  TCNT1= 65535 - Tiemp*Fosc/escala

// -----------------------------------------------------------------------------
// ************************ Rutinas de Interrupción ****************************
// -----------------------------------------------------------------------------

ISR(TIMER1_OVF_vect) 
{
	 TCNT1=T1_INI;


     frac++;
	 if(frac>=1)
	 {
 	  segundos++;
	  frac=0;

		
if (PIND & (1<<PIND0))

{
	
	while (!(PIND & (1<<PIND1)))
	
	{
		pausa = segundos;
		frac = 0;
		
	}
	
		
}

	 }
	 
}

// -----------------------------------------------------------------------------
// ************************* Declaración de Funciones **************************
// -----------------------------------------------------------------------------



// -----------------------------------------------------------------------------
// **************************** Cuerpo del Programa ****************************
// -----------------------------------------------------------------------------

int main( void )
{
 
 
// -----------------------------------------------------------------------------
// **************** DECLARACIÓN DE VARIABLES Y DEFINICIONES ********************
// -----------------------------------------------------------------------------

  char s_num[20];



// _____________________________________________________________________________

// -----------------------------------------------------------------------------
// ********************* INICIALIZACIÓN DE REGISTROS ***************************
// -----------------------------------------------------------------------------


	TCCR1B=(1<<CS11)|(1<<CS10);		//Escala 64
	TCNT1=T1_INI;					//Inicializa el temporizador

// _____________________________________________________________________________

// -----------------------------------------------------------------------------
// ******************** HABILITACIÓN DE INTERRUPCIONES *************************
// -----------------------------------------------------------------------------

	TIMSK= (1<<TOIE1);			//Habilita interrupción por desbordamiento TMR1
	sei();						//Habilita interrupción global

// _____________________________________________________________________________
// -----------------------------------------------------------------------------
// **************** INICIALIZACIÓN DE FUNCIONES Y VARIABLES ********************
// -----------------------------------------------------------------------------
// _____________________________________________________________________________

// -----------------------------------------------------------------------------
// ********************** CICLO PRINCIPAL DE EJECUCIÓN *************************
// -----------------------------------------------------------------------------

while(1)
{
	
	
	
	while(segundos<=31)
	
	{
		

		
		if (segundos==1 || segundos==11 || segundos==21)
		{
		
	PORTC |= (1<<PC2) | (1<<PC1) | (1<<PC0) | (1<<PC3) | (1<<PC4) | (1<<PC5);
	

		}	


if (segundos==2 || segundos==12 || segundos==22)

{
	PORTC &= ~((1<<PC4));
	
	PORTC |= (1<<PC6);

	
}
	

if (segundos==3 || segundos==13 || segundos==23)

{
	
	
	PORTC |= (1<<PC4);
	

}

	

if (segundos==4 || segundos==14 || segundos==24)

{
	PORTC &= ~((1<<PC6) | (1<<PC4) | (1<<PC3));
	
}
	

if (segundos==5 || segundos==15 || segundos==25)

{
	PORTC &= ~((1<<PC1));
	
	PORTC |= (1<<PC4) |(1<<PC0) | (1<<PC5) | (1<<PC6) | (1<<PC2) | (1<<PC3);
	
}

	
if (segundos==6 || segundos==16 || segundos==26)

{
	
	PORTC &= ~((1<<PC4));

}
	
if (segundos==7 || segundos==17 || segundos==27)

{
	PORTC &= ~((1<<PC0) | (1<<PC4) | (1<<PC3));
	
	PORTC |= (1<<PC1);
	
}


	
if (segundos==8 || segundos==18 || segundos==28)

{
	PORTC &= ~((1<<PC5));
	
	PORTC |= (1<<PC0) | (1<<PC3);
	
}

	
if (segundos==9 || segundos==19 || segundos==29)

{
	PORTC &= ~((1<<PC2));
	
	PORTC |= (1<<PC4);
	


}

	
	
if (segundos==10 || segundos==20)

{
	PORTC &= ~((1<<PC6)| (1<<PC3)| (1<<PC4)| (1<<PC0));
	
	PORTC |= (1<<PC2);
	
		
}
	
if (segundos==30)
{
	PORTC &= ~((1<<PC6)| (1<<PC3)| (1<<PC4)| (1<<PC0));
	
	PORTC |= (1<<PC2);
	 
	 
	 
	
}
	
if (segundos==1)

{
	PORTA &= ~((1<<PA5) | (1<<PA4));

	PORTA |= (1<<PA0) | (1<<PA1) | (1<<PA6) | (1<<PA2) | (1<<PA3);
	
}	
	
	if (segundos>1 && segundos<12)

{
	
	
	PORTA |= (1<<PA0) | (1<<PA1) | (1<<PA6) | (1<<PA3) | (1<<PA4);
	PORTA &= ~((1<<PA2));
	
}	

	if (segundos>11 && segundos<22)

{
	
	
	PORTA |= (1<<PA1) | (1<<PA2);
	PORTA &= ~((1<<PA0) | (1<<PA3) | (1<<PA4) | (1<<PA6));
	
}

	if (segundos>21 && segundos<30)

{
	
	
	PORTA |= (1<<PA0) | (1<<PA4) | (1<<PA5) | (1<<PA3);
	
	

}

	if (segundos==31)

{
	
	PORTC |= (1<<PC0) | (1<<PC4) | (1<<PC5) | (1<<PC3);
	PORTA |= (1<<PA0) | (1<<PA4) | (1<<PA5) | (1<<PA3);	

}



}

}
		}
 
Me llama la atención que vos preguntás por el estado de los pines dentro de la rutina de interrupción del timer :confused:.

¿No sería más conveniente usar interrupciones externas?

Otro gran inconveniente que tiene ese código es que no contempla los rebotes, es posible que al presionar una vez, el uC detecta muchas pulsaciones espúreas.

Y por último, el gran error que le veo, es que te metés dentro de un while en la rutina de interrupción del timer, mala idea, una rutina de interrupción debe ser lo más corta posible, no podés quedarte en ella haciendo polling (sobre PD.1).

Te recomiendo que uses las interrupciones externas del uC en conjunto con una rutina de antirrebote.
 
Atrás
Arriba