PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Probleme mit Timer0 und Timer1



Lichti01
27.05.2018, 20:34
HI zusammen,

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

Vorab mal der Code um den es geht.

#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

wkrug
27.05.2018, 22:02
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.

Lichti01
28.05.2018, 20:51
Danke dir schon einmal für deine Antwort. Werde mein Code einmal entsprechend anpassen. Melde mich dann nochmal ob es dann funktioniert.

Lichti01
31.05.2018, 14:34
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:


#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

Siro
31.05.2018, 15:44
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



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 ?

Lichti01
31.05.2018, 18:01
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

seite5
01.06.2018, 07:13
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

021aet04
01.06.2018, 07:19
Wenn die Fuses nicht passen, würde das für beide Timer falsch sein.

MfG Hannes

seite5
01.06.2018, 14:59
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

Lichti01
23.06.2018, 13:05
so nach langem schwerem Kampf hab ich meinen Fehler gefunden.
Habe den CTC-Modus im Falschen Register aktiviert.

Trotzdem danke für eure Tipps.

LG Lichti01