PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ATMEGA 16 TIMER-Problem



fulltime
10.03.2012, 15:58
Hallo Leute,

ich habe mir einen Atmega 16 zugelegt und schon einiges programmiert. jz möchte ich mir eine Stopp uhr aus meinen 7-Segmenten basteln und da komme ich mit der Funktion _delay_ms() nicht mehr weiter. So hab ich auf mikrocontroller.net das Timer-Tutorial durch gearbeitet. Leider funtioniert mein Programm nicht, vielleicht könnt Ihr mir weiterhelfen!

Danke schon im vorhinein! :)

Hier ist mein Code:


#define F_CPU 1000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

int zaehler=0;

ISR (TIMER0_OVF_vect)
{
zaehler++;
}

int main()
{
//Timer konfigurieren
//Prescaler = 1024
TCCR0 = (1<<CS02)|(1<<CS00);
//Overflowinterrupt erlauben
TIMSK |= (1<<TOIE0);
//Aktivierung der Interrupts
sei();
//Ports konfigurieren
DDRB = 0xFF //PortB sind Ausgänge für LEDs

while(1)
{
if(zaehler==12)
{
PORTB = 0xF0;
}
}
return 0;
}



Das Problem ist das die LEDs sofort zu leuchten beginnen.
Wenn ich eine Frequenz von 1MHz habe und eine Prescaler von 1024
heißt dass das der Timer 976 mal erhöht wird pro sekunde=> darausfolgt das ich 976/256=3,81 Overflows habe.
Wenn ich die Variable zaehler dann bis 12 zählen lasse heißt, das das ich ungefähr 3sekunden warten muss bis die LEDs leuchten


MFG
fulltime

021aet04
10.03.2012, 16:17
Was mir auffällt ist das du bei der Variable nicht volatile genommen hast. Du brauchst es aber damit die Variable ind der ISR gespeichert wird. Du musst also "volatile int zaehler=0;" schreiben. Ansonsten müsste ich im DB nachschauen.

MfG Hannes

fulltime
10.03.2012, 16:23
Danke für die schnelle Antwort, doch leider ist sie nicht des Rätselslösung.

Kampi
10.03.2012, 16:26
Hallo,

ich habe dein Programm mal auf meinem RN-Control ausprobiert und bei mir funktioniert es problemlos.
Ich hab das "unnütze" jetzt mal raus gemacht:



#include <avr/io.h>
#include <avr/interrupt.h>

volatile int Zaehler=0;

ISR (TIMER0_OVF_vect)
{
Zaehler++;
}

int main()
{
//Timer konfigurieren
TCCR0 = (1<<CS02)|(1<<CS00); //Prescaler = 1024
TIMSK |= (1<<TOIE0); //Overflowinterrupt erlauben

sei(); //Aktivierung der Interrupts

//Ports konfigurieren
DDRC = 0xFF; //PortB sind Ausgänge für LEDs

while(1)
{
if(Zaehler==12)
{
PORTC = 0x01;
}
}
}


Mein Mega32 läuft auf 1MHz (interner Oszilator) und nach etwa 3-4 Sekunden (geschätzt) geht die eine LED aus.
Also am Code liegt das Problem nicht :)

fulltime
10.03.2012, 16:35
Ich habe jetzt statt PORTB PORTD verwendet aber es ist wieder das gleiche Problem. Könnte es sein, dass das Registers des Timers irgendwie defekt ist? Habe jetzt uach noch den 'Timer1 statt Timer0 verwendet, aber noch immer kein Erfolg

Kampi
10.03.2012, 16:47
Bist du sicher das du 1MHz verwendest?
Auf was hast du den das Fusebit für den Takt am Mega16 stehen?
"#define F_CPU 1000000" ist nur eine Variable für die Software, welche die Taktgeschwindigkeit die du verwenden willst beinhaltet. Das stellt den Takt nicht auf 1MHz um. Das machst du nur mit den Fusebits :)
Deswegen kannst du in deinem Programm das #define F_CPU auch löschen, weil es macht in dem jetzigen Programm keinen Sinn und hat auch keine Funktion.
Eventuell hast du noch den 8MHz internen Oszillator aktiv und damit ist der Timer zu schnell für deine Berechnungen.

fulltime
10.03.2012, 17:09
Nein ich verwende 1MHz das "#define F_CPU 1000000" braucht ich für den "_delay_ms()"-Befehl, denn damit liefert der delay-Befehl die richtige Zeitspanne. Sonst habe ich noch einen 12MHz Quarz doch denn verwende ich momentan nicht.

021aet04
10.03.2012, 17:18
Hast du die Fuses kontrolliert? Funktionieren andere Programme (zum Testen kannst du den Ausgang togglen lassen)?

MfG Hannes

fulltime
10.03.2012, 17:21
ja andere Programme funktionieren kann lauflichter, LEDs mit Taster an steuern, auf einer 7-Segment Anzeige rauf un runter zählen lassen. Das funktioniert einwandfrei. Nur der Timer geht nicht.

Kampi
10.03.2012, 17:22
Also wie gesagt das Programm von mir läuft auf dem RN-Control und einem Mega32 problemlos und ich verwende den internen RC-Oszillator mit 1MHz.
Selbst dein Programm funktioniert so (hab nur PortB auf C geändert, weil da LEDs dran sind).

fulltime
10.03.2012, 17:50
kann man beim Timer irgendetwas raus messen? Um zu schauen ob er überhaupt etwas tut?

Kampi
10.03.2012, 17:57
Du kannst entweder den Registerinhalt über UART ausgeben lassen oder du togglest einen Pin.

021aet04
10.03.2012, 18:05
Du kannst den Timer so konfigurieren das er zählt oder eine PWM ausgibt. Messen kannst du nichts. Du könntest nur debuggen (damit meine ich mit Debugwire o.Ä.), wenn du die richtige Hardware (Programmer) hast.

So wie Daniel vorgeschlagen hat kannst du zwar über UART Dinge ausgeben, das birgt aber wieder das Risiko von Programmfehlern.

MfG Hannes

fulltime
10.03.2012, 18:09
Ich programmier den Mega mit dem AVRStudio4.

021aet04
10.03.2012, 18:14
Ich meine nicht die Programmierumgebung sondern den Programmer (Hardware damit du das Programm auf den µC spielst). Dieser musst Debugwire, JTAG,... unterstützen. Der µC muss diese Technik natürlich auch unterstützen. Der Atmega16 unterstützt soweit ich gesehen habe nur JTAG.

MfG Hannes

fulltime
10.03.2012, 18:30
Ich kann des HEX-File direkt mit dem AVRStudio auf den µC spielen und das Studio hat auch noch was zum Debuggen.

021aet04
10.03.2012, 18:52
Das ist klar. Es gibt aber spezielle Programmer (Hardware) mit dem man debuggen kann. AVR Studio unterstützt das Debuggen, dein µC unterstützt debuggen (JTAG) aber du brauchst auch noch einen speziellen JTAG Programmer, nicht nur einen ISP Programmer.

MfG Hannes

fulltime
11.03.2012, 10:35
Danke für den Tipp, werde ich mal versuchen und melde mich dann wieder.

durchgebrannt
13.03.2012, 12:22
Da es am Code ja offensichtlich nicht liegen kann, ließ doch bitte einmal die Fuse-Bits aus und schreibe die Werte hier rein.
Gruß Jannis

fulltime
16.03.2012, 07:23
Der Timer zählt zu schnell hoch und dadurch habe ich es nicht gemerkt. Habe bei if(zaehler==30000') hingeschreiben und jetzt wartet er ein bisschen.

ePyx
16.03.2012, 07:31
Die Fuse-Bits oder auch Fuses genannt, sind die Parameter, die man in AVRStudio festlegen kann. Die sind soweit ich weiss, nicht innerhalb des Programms manipulierbar. Damit wird die konfiguration deines Kontrollers festgelegt. OB SPI und/oder JTAG aktiviert (wenn verfügbar), welcher Vorteiler für die Taktquelle und welche Taktquelle überhaupt genutzt wird sind einige der Parameter, die man dort einstellen kann,

Wenn du AVRStudio 5 benutzt, gehst du auf AVR-Programming und auf der linken Seite ist nach dem Verbinden mit dem Programmiergerät ein Reiter der Fuse-Bits oder ähnlich heisst.
Dort kann man die Fuses setzen und auslesen. Dabei gibt es Low-, High und Extended-Fuses (letztere nur bei neueren Kontrollern) . Poste doch einmal welche Werte die haben.

21837

In AVRStudio 4 sieht das Ganze nur anders aus.

21838

Bitte die Werte nicht übernehmen. Mit den Fuses kann man sich auch den Kontroller so verstellen, dass man nur per HV-Programming Zugriff hat.

fulltime
16.03.2012, 07:58
hier sind meine Fuse-bits21839

ePyx
16.03.2012, 08:08
Sieht eigentlich gut aus. Benutzt du JTAG ? Wenn nicht würde ich es deaktivieren. Zum Anfang deines Programms setzt du mit




DDRB = 0xFF //PortB sind Ausgänge für LED



Das Datenrichtungsregister. Ich würde dahinter noch PORTB = 0x00 einfügen. Sonst wüsste ich jetzt auch nicht weiter ohne es auszuprobieren.

durchgebrannt
16.03.2012, 12:40
Hast du ein Oszilloskop zur Verfügung, oder kannst dein Board mal an ein solches anschließen?
Dazu, schließe einfach mal eine LED an irgendeinen Portpin an und schreibe im Programm, das der Pin auf High gesetzt werden soll, wenn die ISR erreicht wird. Leuchtet diese, wird der Interrupt korrekt ausgeführt. Danach schreibst du noch in die ISR, das der Pin an der die LED hängt, am Ende der ISR wieder auf Löw geschaltet wird. Damit ließe sich die Fehlerquelle weiter eingrenzen. Dazu sollte man langsam in Betracht ziehen, dass es auch an der Platine selber liegen könnte.
Gruß Jannis

fulltime
16.03.2012, 12:46
@ePyx ,danke für den Tipp, er hat mein Problem behoben. Allerdings habe ich PORTB = 0xFF geschrieben, da ich die LEDs mit Pullup-Widerständen versehen habe.

Also jetzt funtioniert alles. Danke an alle für eure Hilfe.

ePyx
16.03.2012, 13:14
Oh. Kein Problem, hab ich gern gemacht. ;)

Kampi
16.03.2012, 13:47
@ePyx ,danke für den Tipp, er hat mein Problem behoben. Allerdings habe ich PORTB = 0xFF geschrieben, da ich die LEDs mit Pullup-Widerständen versehen habe.

Also jetzt funtioniert alles. Danke an alle für eure Hilfe.

Komisch bei mir hat der Code direkt auf Anhieb funktioniert......warum?

Aber ist ja gut das es jetzt wenigstens auch bei dir funktioniert :D

ePyx
16.03.2012, 14:04
@Kampi

Du hast es auf dem RN-Control ausprobiert oder ? Eventuell sind die LEDs dort anders verschaltet. LED mit Pullup :

21840

;)

Kampi
16.03.2012, 14:25
@Kampi

Du hast es auf dem RN-Control ausprobiert oder ? Eventuell sind die LEDs dort anders verschaltet. LED mit Pullup :

21840

;)

Stimmt! Du hast recht ^.^
Auf dem RN-Control sind die LEDs als aktive low geschaltet.
Btw.....ist die LED auf deiner Zeichnung nicht falsch rum? ;)

ePyx
16.03.2012, 14:36
Jap, aber so etwas versteh ich unter LED mit Pullup. ;) Anders herum wäre auch langweilig.