C Anfängerproblem mit Interrupt

AVRuser

Neues Mitglied
20. Apr. 2011
217
0
0
Niedersachsen
Sprachen
  1. BascomAVR
  2. ANSI C
Hallo Leute,

ich fange gerade mit C an, zuvor habe ich nur mit Bascom programmiert...

Ein einfaches Blinkprogramm habe ich berreits erfolgreich gecoded und getestet,
jetzt wollte ich es über den Overflow-Interrupt des Timer0 versuchen,
allerdings tut sich nichts(LED bleibt aus).

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

uint16_t cnt;

ISR (TIMER0_OVF_vect) {
	cnt = cnt + 1;
	if (cnt > 100) {
		cnt = 0;
		PORTD ^= (1<<PD7);
	}
}
 
int main(void) {
	
	DDRD = 0xFF;
	PORTD = 0xFF;
 
	TCCR0A = (1<<CS01); 
	TIMSK0 |= (1<<TOIE0);
  
	sei();
 
	while(1){}
}
  
#define TIMER0_OVF_vect

Das Compilieren und flashen funktioniert, meine Entwicklungsumgebung ist
AVRstudio/AVRgcc mit dem STK500.
Hardware-defekte kann ich vollständig auschließen.

Da alle Leds aus sind (nicht über das 0xFF wundern - die Leds sind Low-active)
kann ich da von ausgehen dass das Programm richtig anläuft...

Wäre schön wenn mal jemand draufschauen könnte!

Gruß und Dank im Vorraus:

AVRuser
 
Hallo AVRuser,

definiere die Variable "cnt" als volatile uint8_t. Wenn du nur bis 100 zählst, benötigst du kein uint16_t.

Ich gehe jetzt einfach mal davon aus, dass die Systemtaktfrequent 16MHz ist. Dann ist die Periodendauer für das Toggeln der LED gut 10ms, also zu schnell für das menschliche Auge.


Interessant wäre, welchen Mikrocontroller du verwendest, denn erst so kann man die Register-Konfiguration überprüfen.

Dirk :ciao:
 
Hallo Dino,

ich verwende einen Atmega88-10PU, die Quarzfrequenz beträgt 8MHz.

8Mhz / 8prescaler / 256bisoverflow / 100counts = 39.06Hz

Durch das toggeln nochmal geteilt - also ca. 20Herz...

müsste man zumindest irgentwas erkennen können,
ich hoffe ich hab richtig gerechnet...

Die Variable hab ich nur vosorglich größer gewählt, sollte aber doch
eigl. keinen Unterschied machen (außer Speicherverbrauch) oder?

PS: Danke für die schnelle Antwort!:)

Gruß:
AVRuser
 
Hallo AVRUser,

ich bin zwar nicht Dino ... ;)


Du verwendest ein falsches Register. Die Prescalerbits sind im Register TCCR0B, nicht im Register TCCR0A.

Richtig wäre also:

TCCR0B |= 1<<CS01; // Timer Start, Prescaler 8


Entferne noch #define TIMER0_OVF_vect, dieses ist bereits in iomx8.h definert.

Du kannst natürlich uint16_t in der ISR verwenden, verwende für Variablen, die in ISRs vorkommen immer "volatile". In deinem Fall volatile uint16_t cnt;


Dirk :ciao:
 
...doch noch was:

Das Prog läuft jetzt zwar, aber die Frequenz stimmt nicht-

rechnerisch: müssten es ca. 48,8281Hz sein,
gemessen: ca. 244,14

Hat jemand ne Idee?

Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 8000000UL

volatile uint16_t cnt;

ISR (TIMER0_OVF_vect) {
	cnt = cnt + 1;
	if ((cnt > 40) || (cnt = 40)) {
		cnt = 0;
		PORTD ^= (1<<PD7);
	}
}
 
int main(void) {
	
	DDRD = 0xFF;
	PORTD = 0xFF;
 
	TCCR0B |= (1<<CS01); 
	TIMSK0 |= (1<<TOIE0);
  
	sei();
 
	while(1){}
}

Gruß:
AVRuser
 
Hallo AVRuser,
...doch noch was:

Das Prog läuft jetzt zwar, aber die Frequenz stimmt nicht-

rechnerisch: müssten es ca. 48,8281Hz sein,
gemessen: ca. 244,14

Hat jemand ne Idee?

bevor ich nachrechne, schau dir erst einmal die ISR an, speziell dieses:

Code:
    if ((cnt > 40) || ([B]cnt = 40[/B]))

Der Fehler wird oft gemacht. Der Ausdruck (cnt = 40) ist immer wahr. Dies ist eine Zuweisung. Der Vergleich geht so (cnt == 40).

Besser schreibst du hier
Code:
  if (cnt >= 40)
  {
  // ...
  }

Um den Fehler zu vermeiden, kann man bei den Bedingungen auch die Reihenfolge umkehren:
(Beispiel)
Code:
  if (40 == cnt)
Vergisst man hier nämlich ein "=", dann beschwert sich der Compiler (der linken Seite kann nichts zugewiesen werden), und es fällt auf :)

Dirk :ciao:
 
mmh - jetzt sind es 6,10Hz...
 
PS: Kennst du noch andere/bessere Tutorials zu AVRgcc als das von µC-net?

Das Tutorial ist schon ganz gut (findet man übrigens nicht nur bei mikrocontroller.net). Ansonsten kenne ich keins. Ich würde hier so vorgehen: learning-by-doing. Nehme dir eine Aufgabe vor (wie hier zum Beispiel mit dem Interrupt und der blinkenden LED) und suche im Internet nach Lösungen und Hilfe. Dadurch lernst du und irgendwann geht alles wie von alleine :D

Hallo,


au weia ! :p :rolleyes:
Das sagt mir ... ich schreibe zu viel :flute:

:D ich denke nicht, dass sich deswegen hier jemand "beschwert" ;)

Dirk :ciao:
 
... jetzt sind es jedenfalls 6,10Hz...
 
Hier nochmal der aktuelle Code:
Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 8000000UL

volatile uint16_t cnt;

ISR (TIMER0_OVF_vect) {
	cnt = cnt + 1;
	if (cnt > 39) {
		cnt = 0;
		PORTD ^= (1<<PD7);
	}
}
 
int main(void) {
	
	DDRD = 0xFF;
	PORTD = 0xFF;
 
	TCCR0B |= (1<<CS01); 
	TIMSK0 |= (1<<TOIE0);
  
	sei();
 
	while(1){}
}

Ich hab mal nachgerechnet, das verhält sich so als hätte ich einen Prescaler von 64,
aber eigl hab ich doch 8 eingestellt!?

Meine Quelle für den Prescaler(AVR-GCC-Tutorial):
TCCR1B Timer/Counter Control Register B Timer 1
Bit 7 6 5 4 3 2 1 0
Name ICNC1 ICES1 - WGM13 WGM12 (CTC1) CS12 CS11 CS10
R/W R/W R/W R R R/W R/W R/W R/W
Initialwert 0 0 0 0 0 0 0 0

ICNC1 (Input Capture Noise Canceler (4 CKs) Timer/Counter 1

oder auf Deutsch Rauschunterdrückung des Eingangssignals.
Wenn dieses Bit gesetzt ist und mit dem Input Capture Signal gearbeitet wird so werden nach der Triggerung des Signals mit der entsprechenden Flanke (steigend oder fallend) am Input Capture Pin ICP jeweils 4 Messungen mit der CPU-Frequenz des Eingangssignals abgefragt. Nur dann, wenn alle 4 Messungen den gleichen Zustand aufweisen gilt das Signal als erkannt.

ICES1 (Input Capture Edge Select Timer/Counter 1)

Mit diesem Bit wird bestimmt, ob die steigende (ICES1=1) oder fallende (ICES1=0) Flanke zur Auswertung des Input Capture Signals an Pin ICP heran gezogen wird.

CTC1 (Clear Timer/Counter on Compare Match Timer/Counter 1)

Wenn dieses Bit gesetzt ist, so wird nach einer Übereinstimmung des Datenregisters TCNT1H/TCNT1L mit dem Vergleichswert in OCR1H/OCR1L das Datenregister TCNT1H/TCNT1L auf 0 gesetzt.
Da die Übereinstimmung im Takt nach dem Vergleich behandelt wird, ergibt sich je nach eingestelltem Vorteiler ein etwas anderes Zählverhalten:
Wenn der Vorteiler auf 1 gestellt, und C der voreingestellte Vergleichswert ist, dann nimmt das Datenregister, im CPU-Takt betrachtet, folgende Werte an:
... | C-2 | C-1 | C | 0 | 1 |...
Wenn der Vorteiler z. B. auf 8 eingestellt ist, dann nimmt das Datenregister folgende Werte an:
... | C-2, C-2, C-2, C-2, C-2, C-2, C-2, C-2 | C-1, C-1, C-1, C-1, C-1, C-1, C-1, C-1 | C, 0, 0, 0, 0, 0, 0, 0 |...
In der PWM-Betriebsart hat dieses Bit keine Funktion.

CS12, CS11, CS10 (Clock Select Bits)

Diese 3 Bits bestimmen die Quelle für den Timer/Counter:

CS12 CS11 CS10 Resultat
0 0 0 Stopp, Der Timer/Counter wird angehalten.
0 0 1 CPU-Takt
0 1 0 CPU-Takt / 8
0 1 1 CPU-Takt / 64
1 0 0 CPU-Takt / 256
1 0 1 CPU-Takt / 1024
1 1 0 Externer Pin T1, fallende Flanke
1 1 1 Externer Pin T1, steigende Flanke

Wenn als Quelle der externe Pin T1 verwendet wird, so wird ein Flankenwechsel auch erkannt, wenn der Pin T1 als Ausgang geschaltet ist.
 
Ich hab mal nachgerechnet, das verhält sich so als hätte ich einen Prescaler von 64,
aber eigl hab ich doch 8 eingestellt!?

Ist das Fusebit CKDIV8 programmiert?
Wenn ja, beträgt der Systemtakt 1MHz und nicht 8MHz.

(Ausgeliefert wird der Mikrocontroller mir der Systemtaktquelle interner RC-Oszillator 8MHz und programmiertem CKDIV8. Der Systemtakt beträgt dann also 1MHz.)

Dirk :ciao:
 
Hattest recht, Dirk: lag nur an den Fuses...:eek:
Jetzt frag ich mich nur wie es zu so einem dummen Anfängerfehler kommen konnte,:confused:
da der µC schon andersweitig benutzt wurde und ich als erstes immer die Fuses
korrigiere (ext. Takt und kein Clockdiv8, etc.)...
Hab die Vermutung, dass ich versehentlich die default- einstellungen vom Avrstudio
geflash hab, da ich vorher nicht ausgelesen habe und mich erst noch and die Version6
gewöhnen musste...

Wie auch immer: Vielen Dank für deine Hilfe!:)
 

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