- fchao-Sinus-Wechselrichter AliExpress         
Ergebnis 1 bis 6 von 6

Thema: Problem mit dem Timer2 eines ATMega8

  1. #1
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    26.11.2006
    Ort
    Hamburg
    Alter
    32
    Beiträge
    384

    Problem mit dem Timer2 eines ATMega8

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hi,

    ich habe wie gesagt ein Problem mit dem 8 bit Timer meines ATMega8. Ich betreibe ihn mit einem externen Quarz bei 3,6864 MHz. Der Timer soll einen Interupt bei einem Überlauf auslösen und das möglichst 1000 mal die Sekunde. Dafür habe ich mit dem RN-Tool rnAVR einen prescaler von 64 und einen preloader von 198 ausgerechnet (ist das richtig?). Nun hab ich allerdings das Problem, dass wenn ich eine Lampe immer bei der gleichen
    Anzahl von Interrupts an bzw. ausschalte, immer ein Abstand von ca. drei Sekunden habe auch wenn ich den Wert von 255 auf z.B. 85 runtersetze. Zudem hab ich noch eine Frage die sich auf die Variable "countTimer2" bezieht: Die Variable müsste doch eigentlich, wenn die Berechnungen von rnAVR stimmen, nach 1 sek. den Wert 1000 haben, doch bei mir erreicht sie lediglich 255, also einen 8 bit Wert, aber die 8 bit beziehen sich doch nicht auf die Variable aus der ISR oder? Irgendwie läuft das ganze nicht so wie ich mir das Vorstelle. Hier ist noch mein Code. Nicht erschrecken das meiste ist für die Ansteuerung einses LCD nur die ersten drei Funktionen beziehen sich auf mein Timerproblem.

    Code:
    #define 	F_CPU 3686400	// Taktfrequenz des myAVR-Boards
    #define		CLOCK	3686400
    #include	<avr\io.h>		// AVR Register und Konstantendefinitionen
    #include	<avr\interrupt.h>
    #include	<avr/delay.h>
    #include    <stdlib.h>
    
    //----------------------------------------------------------------------
    
    
    volatile int countTimer2;	// Speichert den aktuellen Zählerwert
    SIGNAL (SIG_OVERFLOW2)		// ISR
    {
    	
      countTimer2++;
    
    }
    
    void init (void)
    {
    	DDRB= 0x00;				// PortB Eingang	
    	DDRC= 0xFF;				// PortC Ausgang
    	PORTB |= (1<<PB0); 		// PortB.0 Pull up 
    	TCCR2 = 0x04;		// Prescaler von 64
    	TCNT2  = 198;			// Vorladen mit 198
    	TIMSK |= (1<<TOIE2);		// Interrupts aktivieren und damit Timer starten
    	sei();						// interupts erlauben
    }
    
    int get_time(void)			// gibt die Anzahl der Überläufe wieder
    {
    	return countTimer2;
    	
    }
    
    void  reset_timer(void)   // stellt den Timer wieder auf Null
    {
    	 countTimer2=0;
    	 TIMSK |= (1<<TOIE2);
    	
    }
    
    void wait_ms(int miliSec)
    {
    	_delay_loop_2( 1*(CLOCK/(1000/4)) * miliSec);	// 4 Zyklen warteschleife
    }
    
    void lcd_send(char data)
    {
    	// aktuelles RS ermitteln
    	char rs=PORTD;
    	rs&=4;
    	// High-Teil senden
    	char tmp=data;
    	tmp&=0xf0;
    	tmp|=rs;
    	PORTD=tmp;
    	// Schreibsignal
    	sbi(PORTD,3);
    	cbi(PORTD,3);
    	// Low-Teil senden
    	tmp=data;
    	tmp&=0x0f;
    	tmp*=16;
    	tmp|=rs;
    	PORTD=tmp;
    	// Schreibsignal
    	sbi(PORTD,3);
    	cbi(PORTD,3);
    	// verarbeiten lassen
    	wait_ms(1);
    }
    //---------------------------------------------------------------------------
    //	lcd_cmd(..) - sendet ein Kommando an LCD
    //	PE:	cmd=Kommando-Byte
    //---------------------------------------------------------------------------
    void lcd_cmd(char cmd)
    {
    	cbi(PORTD,2);		// RS löschen = Kommando
    	lcd_send(cmd);		// senden
    }
    //---------------------------------------------------------------------------
    //	lcd_write(..) - sendet ein Zeichen (Daten) an LCD
    //	PE:	text=Zeichen
    //---------------------------------------------------------------------------
    void lcd_write(char text)
    {
    	sbi(PORTD,2);		// RS setzen = Daten
    	lcd_send(text);		// senden
    }
    //---------------------------------------------------------------------------
    //	lcd_write(..) - sendet eine Zeichenkette an LCD
    //	Die Zeichenkette muss mit 0x00 abgeschlossen sein
    //	PE:	pText=Zeiger auf Zeichenkette
    //---------------------------------------------------------------------------
    void lcd_write(char* pText)
    {
    	while(pText[0]!=0)
    	{
    		lcd_write(pText[0]);
    		pText++;
    	}
    }
    //---------------------------------------------------------------------------
    //	lcd_write(..) - sendet eine Zeichenkette an LCD
    //	PE:	pText=Zeiger auf Zeichenkette
    //		count=Anzahl der zu sendenden Zeichen
    //---------------------------------------------------------------------------
    void lcd_write(char* pText, int count)
    {
    	while(count!=0)
    	{
    		lcd_write(pText[0]);
    		pText++;
    		count--;
    	}
    }
    //---------------------------------------------------------------------------
    //	lcd_home(..) - Cursor auf Position 1,1
    //---------------------------------------------------------------------------
    void lcd_home()
    {
    	lcd_cmd(0x02);
    	wait_ms(2);			// warten
    }
    //---------------------------------------------------------------------------
    //	lcd_clear(..) - löscht die Anzeige im LCD
    //---------------------------------------------------------------------------
    void lcd_clear()
    {
    	lcd_cmd(0x01);
    	wait_ms(2);			// warten
    }
    //---------------------------------------------------------------------------
    //	lcd_on(..) - schaltet das LCD an
    //---------------------------------------------------------------------------
    void lcd_on()
    {
    	lcd_cmd(0x0E);
    }
    //---------------------------------------------------------------------------
    //	lcd_off(..) - schaltet das LCD aus
    //---------------------------------------------------------------------------
    void lcd_off()
    {
    	lcd_cmd(0x08);
    }
    //---------------------------------------------------------------------------
    //	lcd_goto(..) - setzt die Cursorposition
    // 	PE:	row = Zeile 1..2
    //		col = Spalte 1..16
    //---------------------------------------------------------------------------
    void lcd_goto(int row, int col)
    {
    	row--;				// Null-basierend
    	row&=0x01;			// sicherheitshalber
    	row*=0x40;			// Zeile nach Bit 6 bringen
    	col--;				// Null-basierend
    	col&=0x0f;			// sicherheitshalber
    	char tmp=row|col;
    	tmp|=0x80;			// Cursor setzen
    	lcd_cmd(tmp);		// senden
    }
    //---------------------------------------------------------------------------
    //	lcd_init(..) - Schaltet die Ports und Initialisiert das LCD
    //---------------------------------------------------------------------------
    void lcd_init()
    {
    
    	ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1);
    	TCCR1A=0xA1;
    	TCCR1B =0x02;
    	// Port D = Ausgang
    	DDRD=0xff;
    	PORTD=0;
        
    	
    	// warten bist LCD-Controller gebootet
    	wait_ms(200);		
    	// 4-BitModus einschalten
    	PORTD=0x20;			
    	// Schreibsignal
    	sbi(PORTD,3);
    	cbi(PORTD,3);
    	wait_ms(5);			// Zeit zum Umschalten lassen
    	// ab hier im 4-Bit-Modus
    	lcd_cmd(0x28);		// Funktions-Set: 2 Zeilen, 5x7 Matrix, 4 Bit
    	//lcd_off();
    	lcd_cmd(0x06);		// Entry Mode
    	lcd_on();
    	lcd_clear();
    }
    
    
    main ()						
    {
    char string[3];
    int time;
    
    
    init();
    lcd_init();
    
    	while(1)
    	{
    			if(get_time==255)
    			{
    				PORTC |=(1<<PC5);
    			}
    			
    			else
    			{
    				PORTC &= ~(1<<PC5);
    			}
    		
    				
    			
    				
    			
    		
    		
    	}
    		
    }
    schon mal Danke im Vorraus

    mfg
    Erik

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Das Vorladen wird nur 1x in init() gemacht, danach nicht mehr.

    Das korrekte Register heisst OCR2 oder so.

    Code:
    void timer2_init (uint8_t ocr2)
    {
        // Mode #2 für Timer2 (Manual S. 115)
        // und PRESCALE=8
        TCCR2 = (1 << WGM21) | (1 << CS21);
        
        // PoutputCompare für gewünschte Timer2 Frequenz
        OCR2 = ocr2;
        
        // OutputCompare-Interrupt A für Timer 2
        TIMSK |= (1 << OCIE2);
    }
    Disclaimer: none. Sue me.

  3. #3
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    26.11.2006
    Ort
    Hamburg
    Alter
    32
    Beiträge
    384
    Braucht man das Register OCR2 nicht nur wenn man den Compare Match modus benutzt?

  4. #4
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    22.05.2005
    Ort
    12°29´ O, 48°38´ N
    Beiträge
    2.731
    Hallo,

    die 198 müssen bei jedem IRQ neu gesetzt werden, sonst zählt der immer von 0 bis 255 !
    Deshalb die Zeile bei init() auch oben bei SIGNAL am Anfang einbauen.
    Die Variable countTimer2 ist schon global, deshalb brauchts keine extra function (get_time) die den Wert zurückgibt.

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Zitat Zitat von sloti
    Braucht man das Register OCR2 nicht nur wenn man den Compare Match modus benutzt?
    Es ermöglicht genauere Zeiten, weil man das TCNT2 nicht bei jedem Interrupt von Hand setzen muss, sondern die Hardware setzt TCNT2 beim Erreichen von OCR2 zurück. Voraussetzung ist natürlich der richtige Timer-Modus (Clear Timer on Compare Match, CTC).
    Disclaimer: none. Sue me.

  6. #6
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    11.12.2007
    Ort
    weit weg von nahe Bonn
    Alter
    39
    Beiträge
    3.416
    also prinzipiell würde ich sogar voschlagen statt mit 198 vorzuladen gleich CTC zu benutzen und das OCR2 register mit 57 einmal initialisieren und statt der SIG_OVERFLOW2 das SIG_COMPAREMATCH2 (oder wie hiess das) zu verwenden, was SprinterSB schon angedeutet hat

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Solar Speicher und Akkus Tests