-         
Ergebnis 1 bis 9 von 9

Thema: Probleme mit Timer0 und Timer1

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    04.06.2017
    Beiträge
    19

    Probleme mit Timer0 und Timer1

    Anzeige

    HI zusammen,

    ich habe ein Problem mit den Timer0 und Timer1 des ATtiny2313A.

    Vorab mal der Code um den es geht.
    Code:
    #define F_CPU 1000000UL
    
    #include <util/delay.h>
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <stdio.h>
    
    #define LED1 1
    uint8_t i;
    
    #define a 50			//Zeit in ms/10 für Blinkfrequenz der LED1
    uint16_t b;
    
    //variablen für entprellung
    #define TASTERPORT PIND
    #define TASTERBIT PIND3
    
    //Entprellung
    char taster(void)
    {
    	static unsigned char zustand;
    	char rw = 0;
    
    	if(zustand == 0 && !(TASTERPORT & (1<<TASTERBIT)))			//Taster wird gedrueckt (steigende Flanke)
    	{
    		zustand = 1;
    		rw = 1;
    	}
    	else if (zustand == 1 && !(TASTERPORT & (1<<TASTERBIT)))   //Taster wird gehalten
    	{
    		zustand = 2;
    		rw = 0;
    	}
    	else if (zustand == 2 && (TASTERPORT & (1<<TASTERBIT)))   //Taster wird losgelassen (fallende Flanke)
    	{
    		zustand = 3;
    		rw = 0;
    	}
    	else if (zustand == 3 && (TASTERPORT & (1<<TASTERBIT)))   //Taster losgelassen
    	{
    		zustand = 0;
    		rw = 0;
    	}
    	else if (((zustand == 1) || (zustand == 2)) && !(TASTERPORT & (1<<TASTERBIT)))   //Taster wird gehalten
    	{
    		zustand = 2;
    		rw = 0;
    	}
    	return rw;
    }
    
    int main(void)
    {
    
    	DDRB = 0b00000010;
    	
    	//Einstellung Interrupt
    	PORTD = 0b00000100;
    	GIMSK = (1<<INT0);
    	MCUCR = (1<<ISC01); //The falling edge of INT0 generates an Interrupt
    
    	i=0;
    	b=2*a;
    	
    	//Globale interrupts aktivieren
    	sei();
    	
    	while (1)
    	{
    		if (i==0)
    		{
    			PORTB &=~ (1<<LED1);
    		}
    		if ((i>=1) && (i<=a))
    		{
    			PORTB |= (1<<LED1);
    		}
    		if ((i>=1) && (i>a) && (i<=b))
    		{
    			PORTB &=~ (1<<LED1);
    			if (i==b)
    			{
    				i=1;
    			}
    		}
    		
    	}
    }
    
    ISR(INT0_vect)
    {
    	_delay_ms(50);
    	
    	TIMSK ^= (1<<OCIE0A);				//Ineterrupt aktivieren
    	TCCR0A ^= (1<<WGM01);				//CTC-Mode aktivieren
    	OCR0A ^= 155;						//Interrupt auslösen bei Zählerstand (10ms)
    	TCCR0B ^= ((1<<CS00) | (1<<CS01));	//Timer starten mit Prescaler 64
    	
    	if (i==0)
    	{
    		i=1;
    	}
    	if (i>=1)
    	{
    		i=0;
    	}
    
    }
    
    ISR(TIMER0_COMPA_vect)
    {
    	i++;
    }
    Ich habe den Timer0 (8-bit-Timer) im CTC-Modus mit dem Prescaler64 laufen. Wenn der Timer bis 155 gezählt hat sind 10ms vergangen und ein Interrupt wird ausgelöst. Mit dem Timer wird der Blinckintervall einer LED gesteuert. Das funktioniert auch einwandfrei. Wenn ich aber nun den Timer1 (16-bit-Timer) genauso einstelle blinkt die LED allerdings nur sehr sehr langsam.

    Was mir auch noch aufgefallen ist wenn ich den 8-bit-Timer mit dem Prescaler8 laufen lasse und bis 125 zähle sollte 1ms vergangen sein. Variable a setzte ich dann auf 500 da ja 500ms/1ms= 500 ist. Da blinkt meine LED auch nicht wie sie soll.

    Wenn ich das mit den Timern und Presaclern richtig verstanden habe müsste der Blinckrythmus beim 16-Bit-Timer doch genau so sein wie beim 8-Bit-Timer. Bzw. wenn ich nur bis 1ms zähle müsste es doch auch übereinstimmen.

    Errechnet habe ich den Zählerstand mit folgender Formel:
    Systemtakt[Hz]/Prescaler/1000*Zeit[ms]

    Hoffe ich habe mein Problem verständlich geschildert.

    Danke schon einmal im voraus
    Gruß Lichti01

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    1.927
    Wenn Du Variablen in einer Interrupt Routine ändern willst, solltest Du die volatile setzen.
    Ein 8 Bit Timer kann nur maximal den Zählerstand 255 erreichen, ebenso eine uint8_t Variable - Eventuell hast Du da einen Denkfehler drin.

    Noch was ist mir aufgefallen.
    Wenn Du einzelne Bits mit dem Hochpfeil ^ bearbeitest kann das schief gehen.
    ^ bedeutet Exclusiv Oder, wenn das Bit also schon gesetzt war würde es bei einer weiteren 1 wieder gelöscht.
    Sicherer ist es mit ODER = |, oder mit UND = & zu arbeiten.
    Das ODER benutzt man üblicherweise zum setzen von Bits.
    Das UND zum löschen.
    Geändert von wkrug (28.05.2018 um 06:34 Uhr)

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    04.06.2017
    Beiträge
    19
    Danke dir schon einmal für deine Antwort. Werde mein Code einmal entsprechend anpassen. Melde mich dann nochmal ob es dann funktioniert.

  4. #4
    Neuer Benutzer Öfters hier
    Registriert seit
    04.06.2017
    Beiträge
    19
    Hi

    habe meinen Code jetzt so überarbeitet wie du es geschrieben hast. Leider hat es nicht funktioniert. Das Problem mit dem 16-Bit-Timer besteht weiterhin.

    So sieht der COde jetzt aus:
    Code:
    #define F_CPU 1000000UL
    
    #include <util/delay.h>
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <stdio.h>
    
    #define LED1 1
    volatile uint8_t i;
    
    #define a 50			//Zeit in ms/10 für Blinkfrequenz der LED1
    uint8_t b;
    
    //variablen für entprellung
    #define TASTERPORT PIND
    #define TASTERBIT PIND3
    
    //Entprellung
    char taster(void)
    {
    	static unsigned char zustand;
    	char rw = 0;
    
    	if(zustand == 0 && !(TASTERPORT & (1<<TASTERBIT)))			//Taster wird gedrueckt (steigende Flanke)
    	{
    		zustand = 1;
    		rw = 1;
    	}
    	else if (zustand == 1 && !(TASTERPORT & (1<<TASTERBIT)))   //Taster wird gehalten
    	{
    		zustand = 2;
    		rw = 0;
    	}
    	else if (zustand == 2 && (TASTERPORT & (1<<TASTERBIT)))   //Taster wird losgelassen (fallende Flanke)
    	{
    		zustand = 3;
    		rw = 0;
    	}
    	else if (zustand == 3 && (TASTERPORT & (1<<TASTERBIT)))   //Taster losgelassen
    	{
    		zustand = 0;
    		rw = 0;
    	}
    	else if (((zustand == 1) || (zustand == 2)) && !(TASTERPORT & (1<<TASTERBIT)))   //Taster wird gehalten
    	{
    		zustand = 2;
    		rw = 0;
    	}
    	return rw;
    }
    
    int main(void)
    {
    
    	DDRB = 0b00000010;
    	
    	//Einstellung Interrupt
    	PORTD = 0b00000100;
    	GIMSK = (1<<INT0);
    	MCUCR = (1<<ISC01); //The falling edge of INT0 generates an Interrupt
    
    	//Timerkonfiguration
    	//TIMSK = (1<<OCIE0A);				//Ineterrupt aktivieren
    	//TCCR0A = (1<<WGM01);				//CTC-Mode akrivieren
    	//OCR0A = 155;						//Interrupt asulösen bei Zählerstand (10ms)
    	//TCCR0B = ((1<<CS00) | (1<<CS01));	//Timer starten mit Prescaler 64
    	
    	i=0;
    	b=2*a;
    	
    	//Globale interrupts aktivieren
    	sei();
    	
    	while (1)
    	{
    		if (i==0)
    		{
    			PORTB &=~ (1<<LED1);
    		}
    		if ((i>=1) && (i<=a))
    		{
    			PORTB |= (1<<LED1);
    		}
    		if ((i>=1) && (i>a) && (i<=b))
    		{
    			PORTB &=~ (1<<LED1);
    			if (i>=b)
    			{
    				i=1;
    			}
    		}
    		
    	}
    }
    
    ISR(INT0_vect)
    {
    	_delay_ms(50);
    	
    	if (bit_is_set (TIMSK,OCIE0A))
    	{
    		TIMSK &= ~(1<<OCIE0A);				//Ineterrupt aktivieren
    		TCCR0A &= ~(1<<WGM01);				//CTC-Mode akrivieren
    		OCR0A |= 0;						//Interrupt asulösen bei Zählerstand (10ms)
    		TCCR0B &= ~((1<<CS00) | (1<<CS01));	//Timer starten mit Prescaler 64
    	}
    	if (bit_is_clear (TIMSK,OCIE0A))
    	{
    		TIMSK |= (1<<OCIE0A);				//Ineterrupt aktivieren
    		TCCR0A |= (1<<WGM01);				//CTC-Mode akrivieren
    		OCR0A |= 156;						//Interrupt asulösen bei Zählerstand (10ms)
    		TCCR0B |= ((1<<CS00) | (1<<CS01));	//Timer starten mit Prescaler 64
    	}	
    
    	if (i==0)
    	{
    		i=1;
    	}
    	if (i>=1)
    	{
    		i=0;
    	}
    
    }
    
    ISR(TIMER0_COMPA_vect)
    {
    	i++;
    }
    Bei meinem Anderen Problem habe ich den Fehler gefunden.

    Über weitere Tipps bin ich sehr dankbar.

    LG Lichti01
    Geändert von Lichti01 (31.05.2018 um 14:57 Uhr)

  5. #5
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    610
    Hallo Lichti01

    Ich habe noch nicht ganz begriffen was deine Software machen soll.
    Wenn die Taste gedrückt wird soll eine LED blinken und wenn die Taste losgelassen wird soll sie aus gehen ?

    Deine Abfrage

    Code:
    if (i==0)     // wenn i null ist, dann
    { 
        i=1;   // setzte i auf 1
    }
    
    
    if (i>=1)      // wenn i größer oder gleich 1 ist dann 
    {
        i=0;   // setze i = null, dann hättest Du Dir das sparen können auf 1 zu setzen
    }
    wundert mich:

    nehmen wir an i ist 0
    dann wird ausgeführt i = 1
    danach folgt die Abfrage wenn i größer oder gleich 1 ist, dann setze i = 0

    das kommt irgendwie auf den gleichen Code als wenn Du den gesamten block weglässt und
    i = 0 schreibst, oder verstehe ich da etwa falsch ?

    evtl. ein "else if" oder so ?

  6. #6
    Neuer Benutzer Öfters hier
    Registriert seit
    04.06.2017
    Beiträge
    19
    Hallo Siro,

    Ja du hast recht da fehlt ein else vor dem zweiten if (nur komisch, dass es beim 8-bit timer keine probleme damit gab).

    Theorie ist:
    Wenn der Taster gedrückt wird soll der Timer1 im CTC Mode gestartet werden. Wenn der angegebene Wert erreicht wird soll die Variable i immer um ein erhöht werden und somit der blinkintervall "generiert" werden. Wird der Taster erneut betätigt soll der Timer angehalten und die LED ausgeschaltet werden.

    Das Problem das ich jetzt (hoffentlich) eigentlich nur noch hab ist, dass der Timer irgendwie viel zu langsam läuft.

    Gruß
    Lichti01

  7. #7
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    21.06.2011
    Ort
    Dresden
    Beiträge
    177
    Timer zu langsam:
    Fuses nicht eingestellt, läuft Dein Controller evtl. mit dem internen Clock?
    Datenblatt, S. 23: "The device is shipped with CKSEL = “0100”, SUT = “10”, and CKDIV8 programmed."
    mfg
    Achim

  8. #8
    Erfahrener Benutzer Robotik Einstein Avatar von 021aet04
    Registriert seit
    17.01.2005
    Ort
    Niklasdorf
    Alter
    30
    Beiträge
    4.676
    Wenn die Fuses nicht passen, würde das für beide Timer falsch sein.

    MfG Hannes

  9. #9
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    21.06.2011
    Ort
    Dresden
    Beiträge
    177
    Sorry, hat ich doch glatt überlesen.
    Der code ist m.M.n. eh recht "unüblich". OCRA |= 0, was soll das bringen?
    Jedes mal int ein/ aus halt ich auch für nicht nötig, reicht aus, den Timer-Takt
    abzuschalten, wichtig: beim wiedereinschalten sicherheitshalber dann erstmal den Zähler nullen.
    Würde wegen der Übersichtlichkeit überhaupt viel aus der ISR 'rausnehmen und über Flags
    in der while(1) abarbeiten.
    mfg
    Achim

Ähnliche Themen

  1. ISR für TIMER0 und TIMER1 laufen nicht zusammen
    Von PhilSU im Forum C - Programmierung (GCC u.a.)
    Antworten: 3
    Letzter Beitrag: 10.11.2012, 09:32
  2. Timer0 + Timer1 Input Capture
    Von Kesandal im Forum C - Programmierung (GCC u.a.)
    Antworten: 5
    Letzter Beitrag: 02.07.2011, 00:50
  3. Probleme mit Timer1
    Von Cyrus777 im Forum Schaltungen und Boards der Projektseite Mikrocontroller-Elektronik.de
    Antworten: 5
    Letzter Beitrag: 27.06.2011, 20:26
  4. PWM mit ATMEGA644p mit timer0, timer1 und timer2
    Von lebratmaxe im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 4
    Letzter Beitrag: 29.07.2010, 18:42
  5. Probleme mit Timer0
    Von frankne im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 3
    Letzter Beitrag: 09.08.2007, 21:53

Stichworte

Berechtigungen

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