logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Atmega8 - zegarek; pisanie programu.

baracuda2 18 Lis 2011 17:06 3293 7
REKLAMA
  • #1 10153206
    baracuda2
    Poziom 13  
    Witam
    Od jakiegoś czasy chce zrobić zegarek na atmega8. Do odliczania sekund użyłem
    unsigned int i=0;
    
    void wait(long t)
    {
    	long cnt = 0;
    	TCCR1A = 0;
    	TCCR1B = 3<<CS10;
    	TCNT1 = 0;
    	TIFR |= (1<<TOV1);
    	
    	while(cnt < t)
    	{
    		if(TIFR & (1<<TOV1))
    		{
    			cnt += 65536;
    			TIFR |= (1<<TOV1);
    		}
    		cnt= (cnt & ~65535) | TCNT1;
    	}
    }
    //-----------------------------------------------------------------------------------
    // Główna funkcja programu	
    int main(void)
    {
    	// Inicjuje wyświetlacz
    	lcd_init();
    	LCD_DISPLAY(LCDDISPLAY);
    
      
    	// Ustawia pozycję kursora
    	LCD_LOCATE(0,0);
    	
    	char bufor[10];
    	
    	while(1)
    	{	
    		wait(15625);
    		
    		i=i+1;;
    		itoa(i, bufor, 10);
    		LCD_LOCATE(0,0);
    		lcd_puts(bufor);
    	}
    return 0;
    }


    atmega chodzi na wewnętrznym taktowaniu MHz, po jakiś 4 min późni się 1s. Czy na zewnętrznym kwarcu 12MHz będzie lepiej i jakoś trzeba odwołać się do tego taktowania (czy starczy zmiana samych fusbitów)

    ps. ma ktoś może schemat użycia atmegi jako obrotomierza, chodzi o podłączenie między atmegą a kablem w samochodzie z którego idą impulsy (ok 5V)
  • REKLAMA
  • #2 10153321
    piotrva
    VIP Zasłużony dla elektroda
    Błąd wynika ze sposobu odmierzania czasu:
    1. odmierzasz czas 1s
    2. zmieniasz zmienną i
    3. konwertujesz liczbę na tekst
    4. wysyłasz komendy do LCD
    5. wysyłasz tekst do wyświetlacza
    6. powróć

    I nie zauważasz, że operacje 2-5 TEŻ TRWAJĄ JAKIŚ CZAS. Pomimo tego że dla oka to ułamek sekundy (załóżmy, że to 0,005s) to jeśli powtórzysz to 240x (czyli teoretycznie Twoje 4 minuty) to otrzymamy błąd już zauważalny (w przykładzie 1,2s).
    Musisz to poprawić tak, aby czas kolejnej sekundy był zliczany już podczas wykonywania tych instrukcji 2-5. To pierwszy poważny błąd, druga sprawa (ale w mniejszym stopniu uwidaczniająca się w Twoim kodzie) to dokładność wewnętrznego rezonatora RC - ogólnie kwarc zewnętrzny powinien dać lepsze wyniki, jednak w Twoim przypadku ta 1s/4min wynika z pierwszego opisanego przeze mnie problemu.
  • REKLAMA
  • REKLAMA
  • #6 10161691
    baracuda2
    Poziom 13  
    mam jeszce jeden problem, według kodu z linku dondu
    #include <avr/io.h>  
    #include <avr/interrupt.h>   
           
    //definicja LED1 (do którego pinu podłączony LED1)    
    #define LED1 PB0    
        
    //definicja LED2 (do którego pinu podłączony LED2)    
    #define LED2 PB1    
           
    //definicja KLAWISZ (do którego pinu podłączony KLAWISZ)      
    #define KLAWISZ PC0    
      
    //definicja początkowej wartości timera  
    #define timer_start 6  
      
    //zmienna pomocnicza-licznik używana w przerwaniu    
    volatile uint8_t cnt=0;   
              
    void main(void)    
    {    
     //########### I/O ###########    
     DDRB  |= (1<<LED1) | (1<<LED2); //Ustawienie pinów sterujących diodami    
                                                      // jako wyjścia    
     PORTB |= (1<<LED1); //Ustawienie stanu wysokiego na wyjściu sterującym LED1     
                                      //(stan początkowy)    
               
     DDRC  &=~ (1<<KLAWISZ); //Ustawienie pinu klawisza jako wejście     
     PORTC |=  (1<<KLAWISZ); //włączenie rezystora podciągającego tzw. Pull_up    
     //##########################    
      
     //######## konfiguracja timera ##############  
     TIMSK |= (1<<TOIE0);           //Przerwanie overflow (przepełnienie timera)  
     TCCR0 |= (1<<CS02) | (1<<CS00); // źródłem CLK, preskaler 1024  
     TCNT0 = timer_start;//          //Początkowa wartość licznika  
     //###########################################  
      
     sei();//Globalne uruchomienie przerwań  
      
     while(1);//główna pętla programu  
      
    }   
      
      
    //############ Procedura obsługi przerwania od przepełnienia timera ############  
    ISR(TIMER0_OVF_vect)   
    {  
      TCNT0 = timer_start;          //Początkowa wartość licznika  
      
      cnt++;     //zwiększa zmienną licznik  
      if(cnt>3)  //jeśli 4 przerwania (czyli ok 1 s)  
      {  
        PORTB ^=(1<<LED1); //suma modulo 2 (XOR) stanu poprzedniego     
                                  //na porcie i pinu LED1 (zmiana stanu na przeciwny)    
           
        PORTB ^=(1<<LED2); //suma modulo 2 (XOR) stanu poprzedniego na porcie     
                                 //pinu LED2 (zmiana stanu na przeciwny)   
        cnt=0;     //zeruje zmienną licznik  
      }  
    }  
    //##############################################################################  


    jedna sekunda to 4 przerwania, ale np dla większego taktowania i preskalera np 8 na
    1 sekunde wypada duża liczba taktów, a maź można użyc 256 (w tym przykładzie 250) czy można jakoś to ominąć albo przy użyciu timer1 16 bitowy
  • REKLAMA
  • #7 10219897
    dondu
    Moderator na urlopie...
    Zobacz do czego Drzasiek użył zmiennej cnt - odlicza ona 4 przerwania, Ty możesz odliczać ile zechcesz.
    Preskaler także możesz zmieniać - Ty decydujesz. Oczywiście możesz także użyć 16-bitowego timera np. Timer1, o którym piszesz.
  • #8 10710710
    baracuda2
    Poziom 13  
    z kwarcem 12 Mhz udało się dojść do błędu ok 15s na godzinę.

    Moderowany przez And!:

    Post raportowany, właściwości zastosowanego rezonatora,
    nie miały bezpośredniego wpływu na bardzo duży błąd pomiaru
    12s / 60min.

REKLAMA