Atmega32 und Timer1

Hemi

Aktives Mitglied
Premium Benutzer
30. Nov. 2008
1.103
19
38
Korntal-Münchingen, Germany
Sprachen
  1. ANSI C
  2. C++
  3. PHP
  4. Java
Hallo zusammen,

irgendwie stehe ich gerade im Wald und zwar, will der Timer1 meines Atmega32 nicht so, wie ich will.

Die Idee: Der Timer1 läuft im CTC-Modus und löst alle 1 Sekunde einen Interrupt aus. Meine MCU läuft mit 1,7456MHz.

Einstellungen für den Timer:
Prescaler: 1024
OCR1A: 14399

Hier ist die Funktion, die den Timer initialisiert:

Code:
void timer1_init (void) {
	TIFR |= (1<<OCF1A);  			// Interruptrequest löschen
	TIMSK |= (1<<OCIE1A);   		// Interrupt einschalten
	OCR1A = 14399;					// TOP-Wert setzen
	TCNT1 = 0;

		
	TCCR1A |= (1 << WGM12);
	TCCR1B |= (1 << CS12)|(1 << CS10);	
}

Sieht ganz okay aus.

Hier ist mein Interrupt:

Code:
ISR (TIMER1_COMPA_vect) {
	counter ++;
}

Die Variable counter ist als volatile int counter = 0; definiert, vor der Main, der Interrupt kann auch drauf zugreifen. In der gibt es auch eine sei(); drin.

Hier ist die Auswertung für die Variable:

Code:
switch (counter) {
	case 30:
		sendIKEReady ();
		break;
	case 60:
		sendIKEReady ();
		status = RTC_read();
		RTC_getTime();
		sendTime();
		counter = 0;
		break;
	}

Problem: Es passiert nichts.

Für die Berechnung des Timers habe ich AVR-timer-Calc verwendet. Und dort folgendes eingegeben:

Frequenz: 14745600
Interrupt-Time: 1000000 (ist doch in Mikrosekunden oder?)
Interrupt: Compare
Timer: 16-bit

Was stimmt denn nicht?

Danke Euch.

Grüsse
Heinrich
 
Hallo Heinrich,

ich hatte diese Woche Schwierigkeiten, den Timer2 auf dem Mega 8 zum laufen zu bringen (in Assembler). Da kam es entscheidend auf die Reihenfolge der Beschreibung der Register an.
1.) Interruptflag musste gelöscht sein (TIMSK : OCIE1A löschen)
2.) Timer anhalten !! (TCCR1B : CS12=CS11=CS10=0) - das war wichtig
3.) OCR1A-Wert setzen
4.) TCNT1 = 0 setzen
5.) TCCR1A/B setzen, wie du es möchtest
6.) mit OCIE1A=1 in TIMSK das ganze starten (Global I-Flag muss natürlich gesetzt sein)

Vielleicht hilft dir das


LG Werner
 
Hallo Heinrich,

der Originalcode beim Mega 8 sah so aus (Timerinterruptbit in TIMSK war gelöscht)
Code:
...
[FONT="Courier New"][SIZE="2"]'...............................' TIMER2 anhalten ..............................
  IN      zReg,TCCR2            ' 1. TCCR2-Register : Timer anhalten
  ANDI    zReg,&B11111000       '    durch löschen der Prescale-Bits
  !OUT    TCCR2,zReg            '    WERT (ohne Prescale) BLEIBT IN ZREG !!!!
  clr     mReg                  ' 2. Zählregister TCNT2 auf 0 setzen
  !OUT    TCNT2,mReg            '
  LDS     mReg,{CMDP2BL}        ' 3. Compareregister (OCR2) setzen
  !OUT    OCR2,mReg
  LDS     mReg,{CMDP1BL}        ' 5. Prescale-Bits mit dem vorherigen Wert
  ANDI    mReg,&B00000111       '    (mit gelöschten PreBits) odern
  !OR     mReg,zReg
  !OUT    TCCR2,mReg            '    und ausgeben
'...............................................................................
  SBI     TIMSK,OCIE2           ' CTC-Interrupt erlauben
[/SIZE][/FONT]...

Gruß
Werner
 
Hallo Werner,

ich habe es jetzt wie folgt umgebaut:

Code:
// CTC-Modus, 1s-periode= Prescaler 1024 und compare 14399
void timer1_init (void) {
	TCCR1B |= (1 << WGM12)|(1 << CS12)|(1 << CS10);
	OCR1A = 14399; 			// TOP-Wert setzen
	TCNT1 = 0;
	TIFR |= (1<<OCF1A);  			// Interruptrequest löschen

	TIMSK |= (1<<OCIE1A);   		// Interrupt einschalten
			
	
	
}

Irgnedwie hat es ihn wenig beeindruckt.

Grüsse
Heinrich
 
Hallo Heinrich,

ich hab's jetzt soweit nachvollzogen; bis auf (meiner Meinung nach)

TIFR |= (1<<OCF1A); // Interruptrequest löschen

stimmt das auch.

Durch setzen des Flags signalisierst du einen Match TCNT1/OCR1A (der dann einen Interrupt auslösen kann). Ich selbst habe aber das entsprechende Flag bzw. Flag-Register gar nicht gebraucht!

Schau doch noch einmal auf Seite 98 im Datenblatt des Mega32 (unten). Du setzt die Register, während der Timer schon läuft (du setzt die Prescalerbits als erstes !).

Ich hab' echt ein paar Stunden gebraucht, bis ich meine obige Vorgehensweise 'raus hatte. Vorher hatte ich das gleiche Fehlerbild wie du - es ging nix.

LG Werner
 
Hmm, ich glaube, ich habe irgendwas geschreddert, jetzt geht gar nichts mehr. F**K.

Wenn ich die MCU resette und sie die erste Botschaft raussendet, legt sie mir den ganzen Bus lahm. Irgendwas ist da faul, aber so richtig. Muss ich mal suchen.

Grüsse
Heinrich
 
Hallo Heinrich,
... Meine MCU läuft mit 1,7456MHz.

...folgendes eingegeben:

Frequenz: 14745600
Interrupt-Time: 1000000 (ist doch in Mikrosekunden oder?) Ja, stimmt so
Interrupt: Compare
Timer: 16-bit

Welchen Systemtakt hast du denn nun? 1,7456MHz oder 14,7456MHz?

Schau erst mal, ob es daran liegen kann, wenn es nicht funktioniert, sehe ich mir später mal die Initialisierung genauer an.

Grüße,
Dirk
 
Hallo Dirk,

der Systemtakt ist 14,7456MHz und die Fuses sind auch richtig gesetzt.

Grüsse
Heinrich
 
Hallo Heinrich,

also deine letzte Version der Initialisierung scheint mir richtig, nur dass man TCCR1B als letztes initialisieren sollte, da ab hier der Timer läuft (wegen CS21 und CS10).

Code:
// Timer1 Compare-Interrupt und CTC (MODE 4)
TCNT1 = 0;   // auch Zustand nach Reset
TCCR1A = 0;  // auch Zustand nach Reset
OCR1A = 14399;
TIMSK |= (1<<OCIE1A);
TCCR1B |= (1<<WGM12) | (1<<CS12) | (1<<CS10);  // jetzt läuft der Timer
Der Compare-Interrupt sollte also ausgelöst werden. Vielleicht gehst du erst einmal einen Schritt zurück und prüfst, ob der Interrupt tatsächlich ausgeführt wird. Am einfachsten ist es, wenn du einfach einen freien IO-Pin in der ISR toggelst, am besten noch mit angeschlossener LED.

Nach meiner Meinung stimmt die Berechnung des Compare-Wertes.
Interrupt-Zeit = 14,7456MHz/(1024*(1+OCRA1))

Also am besten erst mal testen, ob der Timer richtig läuft und die ISR richtig aufgerufen wird.

Grüße,
Dirk
 
Ähm, ja, irgendwie stehe ich im Wald gerade.

Ich habe ein kleines Programmchen geschrieben, wie unten:

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

volatile int counter = 0;
#define BaudRate 9600UL

void timer1_init (void);
void usartInit (void);
void usartFlush (void);
void usartSendC (unsigned char data);

ISR (TIMER1_COMPA_vect) {
	counter++;
	usartSendC (counter);
}

int main (void) {

	timer1_init();
	usartInit();

	unsigned char data = 0x37;
	usartSendC (data);

	sei();

	while (1) {

	}

	return 0;	
}

void timer1_init (void) {
	TCNT1 = 0; // auch Zustand nach Reset 
	TCCR1A = 0; // auch Zustand nach Reset 
	OCR1A = 14399; 
	TIMSK |= (1<<OCIE1A); 
	TCCR1B |= (1<<WGM12) | (1<<CS12) | (1<<CS10); // jetzt läuft der Timer
}



void usartSendC (unsigned char data) {

	while (!(UCSRA & (1 << UDRE)));

	UDR = data;
}

void usartInit (void) {

	// Konfiguration des USARTs der MCU
	uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*BaudRate) - 1);

	UBRRH = (uint8_t) (ubrr>>8);
 	UBRRL = (uint8_t) (ubrr);

	UCSRB = (1 << RXEN) | (1 << TXEN);
	UCSRC = (1<<URSEL) | (1 << UPM1) | (1 << UCSZ1 )| (1 << UCSZ0); 

	usartFlush();
}

void usartFlush (void) {
	do
  {
		UDR;
  }
  while (UCSRA & (1 << RXC));
}

Also absolut minimalistisch. Kompiliert, geflasht, HTerm geöffnet und eingestellt "alle 1000ms NewLine". Und siehe da, es geht genau so wie es soll.

Irgendwie kann ich es mir nicht erklären, was da abläuft, beim besten Willen nicht. Werde es dann mit dem ersten Programm ausprobieren.

Nachtrag: Die switch-case Anweisung im ersten Beispiel ist natürlich Schrott. Eine MCU rechnet ja mit HEX, nicht mit DEC, wenn ich 30 Sekunden brauche, soll der Zähler auf 0x1E stehen und nicht auf 30...

Danke & Grüsse
Heinrich
 
Ich habe es nun endlich rausgefunden, was da los war und warum der Bus lahmgelegt wurde:

-> Ich initialisiere USART mit demgesetzten RXCIE-Bit. Ist ja an um für sich ok, man sollte aber vielleicht auch einen ISR dafür schreiben.
-> Die Hauptschleife wird ja innerhalb einer Sekunde sehr oft durchlaufen, deswegen wird die Botschaft auch entsprechend oft gesendet.

Grüsse
Heinrich
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)