Problem mit Interrupt Programmierung

Maik15

Neues Mitglied
06. Sep. 2009
55
0
0
Sprachen
Hallo ich bin es mal wieder

Nach dem ich das Programmieren für ein paar Monate ruhen lassen musste geht es jetzt mal wieder weiter.

Es geht immer noch um einen Datenlogger zum Aufzeichnen von Strom und Spannungswerte.

Mein Programm ist soweit fertig (hoffe ich zumindest)
Und die Funktionen (Unterprogramme) haben einzeln auch funktioniert.
Allerdings hab ich trotzdem noch 3 Fehler die ich mir nicht erklären kann.

Hier mal ein Ausschnitt aus dem Programm.
Code:
// init Interrupt für Stopp Taster
// -------------------------------
	
	MCUCR = (1 << ISC01)								// Fallenden Flanke von INT0 auswerten
	GIMSK = (1 << INT0)								// Interrupt von INT0 aktivieren


// Wenn Interrupt für Stopp ausgelöst wird dann
// --------------------------------------------
	ISR (INT0_vect)										// Interrupt Vektorvariable vom Externem Eingang 0 PortD-2)
		{
			cli();										// alle Interrupts deaktivieren			
		
			Aktiv = 0;									// Aktiv zurücksetzen
			Zustand = ~0x04;							// Zustand = Stopp
			PortB_OUT();								// LED's setzen
			_delay_ms (100);							// 100ms Warten (entprellen des Stopptasters)

			sei();										// Interrupt's freigeben
		}


// init Interrupt für Timer
// ------------------------
	cli();												//alle Interrupts sperren um 16Bit Register zu beschreiben
		
	TCCR1A = 0x00;										//keine PWM und keine Interrupt Ausgabe
	TCCR1B = Vorteiler;						//(0A...0D) Compare Modus (vergleich mit Sollwert) & Vorteile 1024

	OCR1AH = Byte1;							// 16 Bit Compare Register A die 8 höheren Bits (Vergleichswerte Regiser)
	OCR1AL = Byte0;							// 16 Bit Compare Register A die 8 Niedrigeren (Vergleichswerte Regiser)
	
	sei();												// alle Interrups wieder freigeben 

	TIMSK1 |= (1<< OCIE1A); 							// Compare Interrupt (Vergleicher Interrupt) aktivieren
//----------------------------------------------------------------------------------------------------
// Wenn Timer Interrupt auslöst dann ausführen
// -------------------------------------------
	ISR (TIMER1_COMPA_vect)								// Interrupt Vektorvariable vom Timer1 Compare
		{
			Time = Time + 1;							// Time um 1 erhöhen

			if (Time == Durchlauf)						// Time = die Anzahl wie oft der Interrupt Durchlaufen werden soll
				{										
					Aufnahme = 1;						// Merker für Aufnahmen setzen
					Time 	 = 0;						// Time zurücksetzen
				}
		}

Zur Erklärung:
Es gibt 2 Interrupt Aufrufe.
Der 1. ist ein Timer Interrupt für das Abtasten der Kanäle.
Der 2. ist ein Externer Interrupt zum Stoppen der Aufnahme.

1.Fehler:
../main_Datenlogger.c:416: error: expected ';' before 'GIMSK'
Code:
	MCUCR = (1 << ISC01)								// Fallenden Flanke von INT0 auswerten
	GIMSK = (1 << INT0)								// Interrupt von INT0 aktivieren
Setze ich aber ";" dann kommen 4 weitere Fehler


Fehler 2 und 3:
../main_Datenlogger.c:450: error: static declaration of '__vector_13' follows non-static declaration

../main_Datenlogger.c:450: error: previous declaration of '__vector_13' was here

Code:
	ISR (TIMER1_COMPA_vect)								// Interrupt Vektorvariable vom Timer1 Compare
		{
			Time = Time + 1;							// Time um 1 erhöhen

			if (Time == Durchlauf)						// Time = die Anzahl wie oft der Interrupt Durchlaufen werden soll
				{										
					Aufnahme = 1;						// Merker für Aufnahmen setzen
					Time 	 = 0;						// Time zurücksetzen
				}
		}

Ich hab keine Ahnung was der mit '__vector_13' meint
Und beim Testprogramm war das so OK.

Das mit dem Stop Taster hab ich noch nicht getestet gehabt.
Aber der Timer war wirklich mal OK gewesen.

Vielleicht kann mir ja jemand einen Tipp geben.
Ach ja ich verwende einen ATmega644.

gruß
Maik
 
Hi,

ich hab mal wieder von C keinen Schimmer :D
Aber Vector 13 ist wohl dein Interrupt-Vector ...
Siehe Datenblatt vom Mega644 ...
10.1 Interrupt Vectors in ATmega644

Table 10-1. Reset and Interrupt Vectors
Vector No. - - - Program Address(2) - - - Source - - - Interrupt Definition
...
13 - - - $0018 - - - TIMER1_CAPT - - - Timer/Counter1 Capture Event
...
einmal über die vordefinierten Label und einmal selber dran rumgeschraubt ?
Doppelt definiert ?

../main_Datenlogger.c:450: error: static declaration of '__vector_13' follows non-static declaration

../main_Datenlogger.c:450: error: previous declaration of '__vector_13' was here
steht da ja auch irgendwie :D

Gruß
Dino
 
Ja aber das die beiden Fehler beziehen sich auf die gleiche Zeile.

Aber ich werde es noch mal mit der Testdatei überprüfen vielleicht ist ja beim Kopieren was schief gegangen.

Aber ich glaube es eigentlich nicht.

gruß
Maik
 
Hi Maik,

Ja aber das die beiden Fehler beziehen sich auf die gleiche Zeile.
das Problem ist, wenn du nur Fragmente reinstellst hat man keinen Bezug
zu den Zeilennummern der Fehlermeldungen. Alles ein wenig schwierig :eek:
Man weiß nicht, welche Zeile jetzt 450 oder 416 oder ... ist.
Am besten mal das gesamte Teil reinstellen und dazu dann die Meldungen
die genau bei dem Quelltext aufgetreten sind.

Aber ich werde es noch mal mit der Testdatei überprüfen vielleicht ist ja beim Kopieren was schief gegangen.

Aber ich glaube es eigentlich nicht.
Nochmal alles durchsehen ... hört sich nach Arbeit an :rolleyes:

Gruß
Dino
 
Mann ich geil wenn man seine Eigenen Fehler findet.

Die Interrupt's müssen Außerhalb von Main sein

Code:
// Interrupt's
// -----------
// Wenn Interrupt für Stopp ausgelöst wird dann
// --------------------------------------------
	ISR (INT0_vect)										// Interrupt Vektorvariable vom Externem Eingang 0 PortD-2)
		{
			cli();										// alle Interrupts deaktivieren			
		
			Aktiv = 0;									// Aktiv zurücksetzen
			Zustand = ~0x04;							// Zustand = Stopp
			PortB_OUT();								// LED's setzen
			_delay_ms (100);							// 100ms Warten (entprellen des Stopptasters)

			sei();										// Interrupt's freigeben
		}

// Wenn Timer Interrupt auslöst dann ausführen
// -------------------------------------------
	ISR (TIMER1_COMPA_vect)								// Interrupt Vektorvariable vom Timer1 Compare
		{
			Time = Time + 1;							// Time um 1 erhöhen

			if (Time == Durchlauf)						// Time = die Anzahl wie oft der Interrupt Durchlaufen werden soll
				{										
					Aufnahme = 1;						// Merker für Aufnahmen setzen
					Time 	 = 0;						// Time zurücksetzen
				}
		}

Die ";" gehören selbst verständlich hinter die Zuweisungen:!:
Und die Register heißen beim ATmega644 ja auch nicht MCUCR und GIMSK sondern EICRA und EIMSK :)
Aber so ist es halt wenn man lieber ein Deutsches Tutorial liest als ein Englisches Datenblatt.

Code:
// init Interrupt für Stopp Taster
// -------------------------------
	cli();												//alle Interrupts sperren um 16Bit Register zu beschreiben
	
	EICRA &= (1 << ISC01);								// Fallenden Flanke von INT0 auswerten	
//	MCUCR |= (1 << ISC01);								// Fallenden Flanke von INT0 auswerten

	EIMSK &= (1 << INT0); 	 							// Interrupt von INT0 aktivieren	
//	GIMSK |= (1 << INT0); 	 							// Interrupt von INT0 aktivieren


// init Interrupt für Timer
// ------------------------
		
	TCCR1A = 0x00;										//keine PWM und keine Interrupt Ausgabe
	TCCR1B = Vorteiler;						//(0A...0D) Compare Modus (vergleich mit Sollwert) & Vorteile 1024

	OCR1AH = Byte1;							// 16 Bit Compare Register A die 8 höheren Bits (Vergleichswerte Regiser)
	OCR1AL = Byte0;							// 16 Bit Compare Register A die 8 Niedriegeren (Vergleichswerte Regiser)
	
	sei();												// alle Interrups wieder freigeben 

	TIMSK1 |= (1<< OCIE1A); 							// Compare Interrupt (vergleicher Interrupt) aktivieren

gruß
Maik
 
Nochmal alles durchsehen ... hört sich nach Arbeit an :rolleyes:

Na ja ich hab nur das mit denn Interrupts noch mal durchgesehen.
Das gesamte Programm hat im Augenblick etwas über 1300 Programmzeilen.

Das meiste davon ist aber das Programm mit für das beschreiben von dem USB-Stick.

Ist es eigentlich schwierig eine eigene Headerdatei anzulegen wo das Programm zum Stick beschreiben drin ist.

Das würde das ganze Programm bedeutend übersichtlicher machen.

Leider finde ich dazu nix im Forum
Ist aber auch nicht so wichtig erstmal muss es funktionieren und jetzt kann ich es wenigstens mal in die Hardware laden.

gruß
Maik
 
Hi Maik,

na das hört sich doch gut an ;)

Die Interrupt's müssen Außerhalb von Main sein
ist ja auch nur ne "normale" Subroutine :D und die sind normalerweise außerhalb
(hinter) der Hauptroutine ;)

Und die Register heißen beim ATmega644 ja auch nicht MCUCR und GIMSK sondern EICRA und EIMSK :)
Aber so ist es halt wenn man lieber ein Deutsches Tutorial liest als ein Englisches Datenblatt.
Das kenn ich irgendwo her :rolleyes: Hatte ich mal mit nem Mega48 und der
seriellen. Da heißen die auf einmal irgendwas mit Null drin obwohl es nur eine
Serielle gibt. Fiese Nettigkeiten :eek: :p

Das gesamte Programm hat im Augenblick etwas über 1300 Programmzeilen.
nettes Stück Arbeit :eek: :)

Denn mal auf gutes Gelingen ...

Gruß
Dino
 
Hallo ich bin es mal wieder.
Und leider macht mir mein Timer Interrupt echt das leben schwer.

Ich hatte ihn schon mal soweit das alles ging aber die Engestellen Compare Werte ergaben keinen Sinn.
Und das obwohl die Zeiten OK waren.

Ich hab dann noch mal etwas mit dem Quarz und denn Fuse Bit rumgespielt.

Anschließend hab ich einen neuen µC kaufen dürfen.

Jetzt ist es wieder ähnlich.
Aber die Fusebit fasse ich jetzt erst mal nicht an.
Das müsste nämlich eigentlich passen.

Meine Hardware ist ein ATmega644 mit 12MHz
Und ich will Zeiten von 10ms bis zu 10min einstellen können.

Zum Testen hab ich fast alles entfernt was nicht gebraucht wird.
Aber selbst beim Simulieren hängt er manchmal in der ISR fest.

Code:
//****************************************************************************************************
// Initialiesierung
#define F_CPU 1000000UL									// Taktrate (12MHz) festlegen
#include <avr/io.h>       								// Datei für Ein und Ausgänge  
#include <stdlib.h>										// Standart LIB
#include <util/delay.h>									// Ersetzt durch delay.c
#include <string.h>       								// Stingfunktionen
#include <stdio.h>        								// Standardfunktionen
#include <avr/interrupt.h>								// Datei für Interrupt



//****************************************************************************************************
//*****																							 *****
//*****									Variablenbereich										 *****
//*****																							 *****
//****************************************************************************************************
//								***Variablen für main***
//								------------------------
char Aufnahme = 0;										// Merker für die Aufnahme (wird vom Timer gesetzt)
//----------------------------------------------------------------------------------------------------
//								***Variablen für Timer***
//								-------------------------
unsigned char Timerwert;								// Abtastzeit
unsigned int  Durchlauf;								// Variablen für Timer Wie Timer durchlaufzähler
unsigned int  Time;										// Zähler für die Anzahl der Timerdurchläufe
unsigned char Vorteiler; 								// Vorteiler für Interrupt
unsigned char Byte1; 									// Vergleichswert für Timerinterrupt (höhes Byte)
unsigned char Byte0;									// Vergleichswert für Timerinterrupt (nidriges Byte)

//----------------------------------------------------------------------------------------------------


//****************************************************************************************************
//*****																							 *****
//*****										Funktionen deklarieren								 *****
//*****																							 *****
//****************************************************************************************************

// 								***Funktionen zur PORT Ein und Ausgabe***
// 								-----------------------------------------
void PortD_OUT(void);									// Daten am PortD ausgeben
unsigned char PortD_IN(char);							// Daten am PortD einlesen


//****************************************************************************************************
//*****																							 *****
//*****										Interrupt											 *****
//*****																							 *****
//****************************************************************************************************

// 								***Wenn Timer Interrupt auslöst dann ausführen***
// 								-------------------------------------------------
ISR (TIMER1_COMPA_vect) 					// Interrupt Vektorvariable vom Timer1 Compare 
	{ 
		Time = Time + 1; 					// Time um 1 erhöhen 
		
		if (Time == Durchlauf) 				// Time = die Anzahl wie oft der Interrupt Durchlaufen werden soll 
			{ 
				Aufnahme = 1; 				// Merker für Aufnahmen setzen 
				Time = 0; 					// Time zurücksetzen
			 } 
 	}



//****************************************************************************************************
//*****																							 *****
//*****										Hauptprogramm										 *****
//*****																							 *****
//****************************************************************************************************
int main (void) 
	{
		DDRA = 0xBA;									// PortA PIN 0, 2, 6 als Eingang
														// PortA alle anderen Pins als Ausgang 
		
		DDRB = 0xFF;									// PortB alle Pins als Ausgang

		DDRC = 0xFF;									// PortC alle Pins als Ausgang
//----------------------------------------------------------------------------------------------------

//								***Timereinstellung vornehmen***
//								--------------------------------
Timerwert = 1;
	switch (Timerwert)
		{	
			//Zeiteinstellung = 0	Pausen-Zeit = 0
			case 0:	Durchlauf = 0xFF;					// immer Messung starten
					break;

			// Zeiteinstellung = 1	Pausen-Zeit = 10ms
			case 1:	Durchlauf = 1;						// 1 x 10ms
					Vorteiler = 0x0A;					// Vorteiler = 8
					Byte1     = 0x00;
					Byte0     = 0xBE;	
					break;

			// Zeiteinstellung = 2	Pausen-Zeit = 50ms				
			case 2:	Durchlauf = 1;						// 1 x 50ms
					Vorteiler = 0x0A;					// Vorteiler 8
					Byte1     = 0x25;					// Vergleichswert 9505
					Byte0     = 0x21;
					break;

			// Zeiteinstellung = 3	Pausen-Zeit = 100ms	
			case 3:	Durchlauf = 1;						// 1 x 100ms
					Vorteiler = 0x0A;					// Vorteiler 8
					Byte1     = 0x4A;					// Vergleichswert =19010
					Byte0     = 0x42;
					break;

			// Zeiteinstellung = 4	Pausen-Zeit = 1s	


			case 4:	Durchlauf = 1;						// 1 x 1s	
					Vorteiler = 0x0C;					// Vorteiler = 256
					Byte1     = 0x17;					// Vergleichswert = 5909
					Byte0     = 0x15;
					break;
		}

// 								***init Interrupt für Timer***
// 								------------------------------	
	cli();												//alle Interrupts sperren um 16Bit Register zu beschreiben
	
	TCCR1A = 0x00;										//keine PWM und keine Interrupt Ausgabe
	
	TCCR1B = Vorteiler;									//Compare Modus & Vorteile setzen
//								Vergleichs- Regiser setzen
	OCR1AH = Byte1;										// 16 Bit Compare Register A obere  8 Bits 


	OCR1AL = Byte0;										// 16 Bit Compare Register A untere 8 Bits
	
	sei();												// alle Interrups wieder freigeben 

	TIMSK1 |= (1<< OCIE1A); 							// Compare Interrupt aktivieren
	
// ****************************************************************************************************
// *****						Hauptschleife zum messen der Signale		   					  *****
// ****************************************************************************************************

	while (1)
		{
			if (Aufnahme == 1)									// Wenn Datenlogger aufnehmen soll
				{
					cli();												//alle Interrupts sperren um 16Bit Register zu beschreiben

					Aufnahme = 0;

					PORTD = 0xFF;
				//	_delay_ms(1); 								// 100µs Pause	
					PORTD = 0x00;
				
					sei();												// alle Interrups wieder freigeben 

				}
		}

	return 0;
	}

Was ich auch nicht verstehe ist das wenn ich die Taktfrequenzen
#define F_CPU 1000000UL

mit 12MHz angeben entsprechend dem Quarz.
Dann läuft das Gesamtprogramm extrem langsam.
Und gerade beim Ossilustkopieren hab ich gesehen das der Signalverlauf von dem Takt Invertiert ist, wenn ich 12MHz einstelle.

Seit heute hab ich auch die Warnung weiß aber nicht was das ausgelöst hat.
c:/programme/winavr-20090313/lib/gcc/../../avr/include/util/delay.h:90:3: warning: #warning "Compiler optimizations disabled; functions from <util/delay.h> won't work as designed"

Kann mir vielleicht jemand helfen?
Ich vermute mal das ich einen Fehler in der Zuweisung vom TCCR1B Register hab.
Bin mir aber nicht sicher.
Aus den zwei Bits WGM12 und 13 werde ich nicht so recht schlau.
Kennst sich jemand damit aus?

gruß
Maik
 
Hallo Maik,

ich habe mal nachgerechnet und komme irgendwie nicht auf deine Werte. Als Beispiel nehme ich mal folgende Einstellung:

Code:
case 2:
Durchlauf = 1; // 1 x 50ms
Vorteiler = 0x0A; // Vorteiler 8 
Byte1 = 0x25; // Vergleichswert 9505 
Byte0 = 0x21; break;
Den Timer1 konfigurierst du also wie folgt:

TCCR1A = 0;
TCCR1B = 0b00001010; // 0x0A = 0b00001010 bessere Schreibweise: TCCR1B = (1<<WGM12) | (1<<CS11);
OCR1A = 0x2521; // OCR1A = 9505;

Wenn du TCCR1B betrachtest, stellst du hier nicht nur den Prescaler ein, sondern setzt auch das Bit WGM12. Da WGM10=0 WGM11=0 und WGM13=0 sind, arbeitet der Timer 1 im Mode 4, dem CTC Mode (Clear Timer on Compare). Das heisst, der Timer läuft bis zum ComparewertA (OCR1A) und wird dann auf 0x0000 zurückgesetzt.

Ich komme im oberen Beispiel nicht auf 50ms Comparetime, der Timer läuft hierfür viel zu schnell:

Timer Mode 4: CTC (Clear Timer on Compare)
Prescaler: 8
clk = 1/12MHz = 83,333ns
tclk = 8*clk = 666,666ns

Der CTC Mode ist schon soweit richtig. Schau dir doch mal das Tool AVR-Timer-Calculator bei und im Forum an, das hilft dir bei der Berechnung von Prescaler und Comparewert für eine gegebene fclk und gegebene CompareTime.

Deine globalen Variablen definiere als "volatile uint8_t MaineVariable;".

Stelle im AVR Studio unter Project Options/General neben dem Device auch folgendes ein:

Frequency: 12000000Hz
Optimizations: -Os

Mein Text ist ein bisschen durcheinander, sorry, ich hoffe du blickst da durch :rolleyes:.

Gruß,
Dirk
 

Anhänge

  • timer_maik.png
    timer_maik.png
    23,3 KB · Aufrufe: 5
Danke für die Antwort.

Deinen Link kenne ich und das Tool hab ich anfangs genutzt um die Werte zu berechnen.

Aber das stimmte bei mir alles nicht.
Dann hab ich angefangen solange die Werte zu verstellen bis es stimmte.

Aber das wundert mich halt auch.
Im Augenblick ist für 10ms
Code:
// Zeiteinstellung = 1 Pausen-Zeit = 10ms 
case 1: Durchlauf = 1; // 1 x 10ms 
Vorteiler = 0x0A; // Vorteiler = 8 
Byte1 = 0x00; 
Byte0 = 0xBE;
das "Richtige" Einstellung.

Aber bei 12MHz müssten das nur 0,126ms sein.
der Controller müsste schon mit 152kHz betrieben werden.
Damit das lauf Taschenrechner 10ms sind.

Aber es sind 10ms oder meine Ossi... geht vorkommen falsch.

Bei denn Fuse Bit kann man doch auch nix falsch machen.
Da stellt man doch bloß ein das man mehr als 8MHz Verwendet und die max. Wartezeit zum einschwingen.

Die Optimizations stelle ich von Hand immer auf -00;
Mit denn anderen Einstellungen hab ich schon die ein oder andere schlechte Erfahrung gemacht.

Brauche ich überhaupt das
#define F_CPU 1000000UL
oder kann das raus.

mfg
Maik
 
Hi Maik,

Bei denn Fuse Bit kann man doch auch nix falsch machen.
Da stellt man doch bloß ein das man mehr als 8MHz Verwendet und die max. Wartezeit zum einschwingen.
für deinen Mega644 steht im Datenblatt ...
7.2.1 Default Clock Source
The device is shipped with internal RC oscillator at 8.0MHz and with the fuse CKDIV8 programmed, resulting in 1.0MHz system clock. The startup time is set to maximum and time-out period enabled. (CKSEL = "0010", SUT = "10", CKDIV8 = "0"). The default setting ensures that all users can make their desired clock source setting using any available programming interface.
Also wird der Takt durch 8 geteilt. Das macht bei 12MHz Quarz einen
CPU-Takt von 1,5MHz wenn du die Fuse CKDIV8 nicht umstellst.

Also stell mal die CKDIV8 um und es läuft mit dem vollen Quarztakt.

Ich hab dann noch mal etwas mit dem Quarz und denn Fuse Bit rumgespielt.

Anschließend hab ich einen neuen µC kaufen dürfen.

Jetzt ist es wieder ähnlich.
Aber die Fusebit fasse ich jetzt erst mal nicht an.
Das müsste nämlich eigentlich passen.
normalerweise passen die nicht ;)
Ich glaube, da ist mal ne FAQ mit Erklärungen zu den Fuses fällig ;)

Gruß
Dino
 
Danke das war das was gefehlt hat.

Wo ich das gelesen hab komm es mir plötzlich wieder bekannt vor.
Danke nochmal.

Anscheint gibt es bei mir noch ein Problem beim Vorteiler von 256,
da weicht die Berechung etwas ab.
Aber mit einem Vorteiler von 1024 bekomm ich eine Sekund gut hin.

Danke nochmal

gruß
Maik
 

Ü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)