Guten Morgen,
in meinem Projekt sollen verschiedene Zeiten mit dem Timer0 des Atmega32
gehandelt werden. Nun ist es so, dass wenn ich die globale
Interruptfreigabe aktiviere (sei();) mein Programm sich genau an dieser
Stelle aufhängt - sprich, es wird nicht weiter ausgeführt.
Kommentiere ich sei(); aus, läuft das Programm ganz normal bis zum Ende.
Die ISR ist meiner Ansicht nach korrekt, wobei hier lediglich drei
Variablen hochgezählt werden. Die Deklaration der Variablen in der ISR
sind alle volatile uint8_t !
Anbei einmal der Code der main:
Ich übersehe bestimmt irgendwas, komme aber seit ein paar Tagen nicht
drauf. Vielleicht hat mir jemand von euch einen Tipp? :)
Danke im Voraus für die Hilfe!
Gruß
Stefan
Stefan S. schrieb:> Ich übersehe bestimmt irgendwas, komme aber seit ein paar Tagen nicht> drauf. Vielleicht hat mir jemand von euch einen Tipp? :)
Ja. Die Endlosschleife fehlt ... Der AVR fährt ja ständig in den Reset
(sobald das Hauptprogramm einmal durch ist). Trivialste Grundlage.
Empfehlung: AVR-Tutorial machen!
Viel Erfolg
i hab von C keine Ahnung (echte Programmierer meiden C :) )
aber laeuft es mit einer leeren Interruptroutine ?
was ist mit dem Stackpointer ???
vlG & viel erfolg
Charly
Hi Michael,
dass die while(1) derzeit fehlt ist mir schon klar. Das hat aber den
Grund, dass die erste LCD-Ausgabe einen Startbildschirm darstellt,
welcher für 2sec nach dem Einschalten angezeigt wird. Anbei nochmals der
Code, diesmal mit einer Wartezeit, welche mit der ISR generiert bzw.
verglichen wird. Hier also nochmals der Codeabschnitt, welcher so nicht
funktioniert (auf dem LCD wird überhaupt nichts angezeigt, die SPI wird
bei Verwendung von "sei();" auch nicht initalisiert (Keine Zeichen auf
dem LCD während der Initialisierung)
Anbei der zu verwendende Code:
[c]
#include "dogm163_spi.h"
#include "ADC_conf.h"
#include "mydefs.h"
#include "timer_config.h"
#include <avr/interrupt.h>
FILE lcd_str = FDEV_SETUP_STREAM(write_char, NULL, _FDEV_SETUP_WRITE);
//------- Interrupt Service Routine für Timer0 -----------------
ISR(TIMER0_COMP_vect)
{
sysTime++;
LCD_refreshTime++;
LCD_startTime++;
}
int main()
{
// ------------------ Initialisierungen -------------------------
adc_init(); // ADC initialisieren
SPI_Init(); // SPI initialisieren
display_init(); // LCD initialisieren
set_contrast (11); // LCD Kontrast setzen
stderr = &lcd_str;
// ------------------------- I/O Funktionen ---------------------
DDRD = 0x20;
//-------------------- Interruptparameter ------------------------
OCR0 = 125; // Compare Register mit Wert für Interrupt bei
10ms blegen - 0% Fehler
TIMSK |= (1<<OCIE0); // Timer 0 Output Compare Interrupt
freigeben
TCCR0 |= (1<<CS00) | (1<<CS01); // Mode: Normal, Timer 0 Takt: CLK /
64
TIFR |= (1<<OCF0); // Output Compare Flag
sei(); // globale Interruptfreigabe
// -------------------------- Hauptprogramm ---------------------
// ------------------------ Startbildschirm ---------------
PORTD |= LCD_backLightOn; // Hintergrundbeleuchtung ein
clear_home();
set_cursor(0);
set_doubleheight (0);
fprintf(stderr, "LDO V_Regulator");
set_cursor(16);
fprintf(stderr, "Version 1.0");
while(LCD_startTime < LCD_startWait) { } // Wartezeit 2sec
[c/]
die Zeile mit "_delay_ms()" aus dem ersten Code war nur zum Testen!
Sorry, wenn das jetzt Verwirrung stiftet.
@ Charly:
die ISR ist ja nicht leer. In der Routine werden nur drei Variablen
inkrementiert, welche dann wieder zur Überprüfung der
Startbildschirmzeit hergenommen werden.
Viele Grüße
Stefan
Hi Michael,
dass die while(1) derzeit fehlt ist mir schon klar. Das hat aber den
Grund, dass die erste LCD-Ausgabe einen Startbildschirm darstellt,
welcher für 2sec nach dem Einschalten angezeigt wird. Anbei nochmals der
Code, diesmal mit einer Wartezeit, welche mit der ISR generiert bzw.
verglichen wird. Hier also nochmals der Codeabschnitt, welcher so nicht
funktioniert (auf dem LCD wird überhaupt nichts angezeigt, die SPI wird
bei Verwendung von "sei();" auch nicht initalisiert (Keine Zeichen auf
dem LCD während der Initialisierung)
Anbei der zu verwendende Code:
die Zeile mit "_delay_ms()" aus dem ersten Code war nur zum Testen!
Sorry, wenn das jetzt Verwirrung stiftet.
Also nochmal das Problem zusammengefasst:
1) setze ich sei(); vor die LCD Ausgabe, wird mein Display nicht mehr
initialisiert und es wird nichts angezeigt!
2) setze ich sei(); nach der LCD Ausgabe, funktioniert soweit die Init
des LCDs und es wird auch der entspr. Text ausgegeben. Allerdings hängt
er sich dann an der while-schleife auf....!
@ Charly:
die ISR ist ja nicht leer. In der Routine werden nur drei Variablen
inkrementiert, welche dann wieder zur Überprüfung der
Startbildschirmzeit hergenommen werden.
Viele Grüße
Stefan
Hast du die Variablen mit volatile gekennzeichnet? Ansonsten optimiert
er dir deine while Schleife auf eine Endlosschleife, da sich die
Variablen nicht innerhalb der While ändern können...
das
TCCR0 |= (1<<CS00) | (1<<CS01); // Mode: Normal, Timer 0 Takt: CLK /
64
reicht nicht.
Es muss auch der Timer auf CTC-Mode eingestellt werden. siehe Datasheet!
Hi Thomas,
die Variablen sind als "volatile" deklariert, da sonst die main ja nicht
mitbekommt, dass sich diese ändern. Die Optimierung hab ich im
AVR-Studio für die Tests ausgeschalten.
Das WGM01-Bit im TCCR0 hab ich tatsächlich vergessen zu setzen, macht
aber leider auch keinen Unterschied bezüglich der nicht vorhanden
Funktion :( Irgendwo spuckt mir die globale Interruptfreigabe rein und
ich find es nicht. Nur alle Zeiten mit Delays aufzuziehen kommt nicht in
Frage :)
Ich schreib den Code jetzt mal auf ein Minumum zusammen und deklariere
alle verwendeten Variablen in der main.c (und nicht über Header). Ich
weiß, dass das keinen Unterschied machen sollte, aber eventuell geht mir
ja noch ein Licht auf ;)
Für weitere Ideen bin ich immer dankbar.
Viele Grüße
Stefan
Kann es sein, dass der Overflow-Interrupt ausgelöst wird, wenn der Timer
Compare auslöst? Das würde ich mal genau im Datenblatt nachlesen. Wenn
für den Overlow-Interrupt kein gültiger Handler definiert ist, wird ein
Reset ausgelöst.
Grüße,
Peter
Wird noch irgendein anderer Interrupt eingeschaltet? Wenn der bei sei()
aufgibt, dann wird möglicherweise ein Interrupt ausgelöst, für den es
keinen Handler gibt.
Bleibt die Programmausführung eigentlich bei sei() stehen, oder macht
der Controller einen Reset?
Edit zu meinem vorherigen Post: Der Overflow-Interrupt ist ja nicht
sichtbar bzw. absichtlich eingeschaltet.
Der Timer muss auf CTC gestellt werden, wie MitLeser bereits geschrieben
hat. Nur dann ist OCR0 der TOP-Wert.
Also
TCCR0 |= (1<<CS00) | (1<<CS01) | (1<<WGM01);
Das würde aber nur ein falsches Timing erklären, nicht den genannten
Effekt.
Ist der richtige Prozessor definiert?
Grüße,
Peter
>Ich würde keine LCD-Operation in der ISR ausführen!>Evtl. gibt es dort auch Delayschleifen welche Programausführung>stören...
ISR(TIMER0_COMP_vect)
{
sysTime++;
LCD_refreshTime++;
LCD_startTime++;
}
@sven: Welche LCD-Operationen denn? Das sind nur drei normale Variablen.
Huch... kaum ist man 10min beim Spülen schon wieder jede Menge Postings.
Versuche mal alles zu beantworten...
@ Peter
Das Programm bleibt stehen, es gibt keinen Reset (würde man an der
erneuten Init des SPI bzw. des Displays sehen). Der Overflow ist, wie du
sagst, nicht aktiviert, daher dürfte auch kein Handler nötig sein. Zum
Testen hab ich trotzdem einen leeren Handler geschrieben, bringt aber
keine Veränderung.. :/
Es ist der korrekte Prozessertyp sowie die richtige Taktfrequenz
eingetragen. Ich kann mir nur vorstellen, dass sei(); sich mit
irgendeiner anderen Funktion in die Quere kommt. Ich hab das Programm
Schritt für Schritt im Simulator ablaufen lassen. Er springt korrekt in
jede Funktion, führt sie aus und kehrt nach main zurück. Bei sei(); ist
dann Ende der Fahnenstange.
@ Sven
Ich muss sehen wie ich die ganzen LCD-Ausgaben (Menüs) später handle um
möglichst wenig Zeit und Rechenleistung zu verbraten. Klar kann ich die
erste Ausgabe auch in die ISR packen, aber es ist, wie gesagt, nur ein
Startbildschirm, der ein einziges Mal aufgerufen werden soll.
Ich hab heute abend noch etwas Zeit. Werde die Interruptgeschicht ohne
die adc_init und die Displaygeschichte probieren. Hab noch ein paar
Status-LEDs auf meinem Projekt und werde die für die Ausgabe
missbrauchen.
Danke euch für das rege Feedback. Werde weiter berichten....! :)
Gruß
Stefan
Stefan S. schrieb:> @ Charly:> die ISR ist ja nicht leer. In der Routine werden nur drei Variablen> inkrementiert, welche dann wieder zur Überprüfung der> Startbildschirmzeit hergenommen werden.
ja das hab i schon gesehen, soviel ahnung hab i dann doch von C
ich meinte du sollst eine 'leere' ISR 'einbauen' dh.
an der ISR Adresse steht ein iret
kannste mal von der 'minimalversion' den hexfile posten ?
was ist mit den SP ?
vlG
Charly
> Schritt für Schritt im Simulator ablaufen lassen. Er springt korrekt in> jede Funktion, führt sie aus und kehrt nach main zurück. Bei sei(); ist> dann Ende der Fahnenstange.
Umso wichtier, dass du
* vollständigen Code postest.
Und zwar auch die Funktionen, die du bisher nicht gezeigt hast.
Also ADC_init, spi_init und all die anderen
* in deine main() eine Hauptschleife einbaust, in der sich die
Programmausführung dann fängt.
Guten Abend zusammen,
melde mich leider etwas später als geplant aber ich hab den Fehler
gefunden!
Zuersteinmal lag es nicht an sei(); , sondern am
Inititialisierungsaufruf für meinen ADC, also meine Mainfunktion
"adc_init();) !
Dieser sieht wie folgt aus (ADC_config.h):
1
voidadc_init(void)
2
{
3
4
ADMUX=(1<<REFS0);// 5V externe Rev
5
6
ADCSRA=(1<<ADPS1)|1<<ADPS2// Frequenzteiler von 64
7
|(1<<ADIE)// Interrupt am Ende der Wandlung aktivieren
8
|(1<<ADEN)// ADC einschalten
9
|(1<<ADSC);// 1 Wandlung zur Init durchführen
10
11
}
Ich Hirsch führe am Schluss der Initialisierung eine einzige Wandlung
des ADC0 durch, aber im Hauptprogramm warte ich nicht auf das Ende der
Wandlung (Interruptflag bei Beendigung der Wandlung)!!
Das sieht man sehr schön hier bei den Initalisierungen (main.c):
Nehme ich die "Initialisierungswandlung" raus bzw. warte ich auf das
entsprechende Flag nach der adc_init(); geht das ganze wunderbar! Was
mir allerdings noch unklar ist, ist der Effekt, dass wenn ich sei(); an
eine andere Position im Programmcode verschoben habe, das ganz bis
dorthin "funktioniert" hat. Wohl ein unglückliches Zusammenspiel.......
!?
Ich danke allen, die sich bei dem Thema beteiligt haben und wie
Karl-Heinz gesagt hat: besser mal den ganzen Code posten! :)
Viele Grüße
Stefan
p.s die Codekommentare müssen noch angepasst werden, stimmen gerade
nicht ganz zu den Registerzuständen....
Stefan S. schrieb:> Dieser sieht wie folgt aus (ADC_config.h):>> [c]> void adc_init(void)> {>> ADMUX = (1<<REFS0); // 5V externe Rev>> ADCSRA = (1<<ADPS1) | 1<<ADPS2 // Frequenzteiler von 64> | (1<<ADIE) // Interrupt am Ende der Wandlung aktivieren
Man gibt NIEMALS einen Interrupt frei, für den man keine ISR hat.
NIEMALS!
Denn sobald mit einem sei die Interrupt Behandlung global freigegeben
wird, wird die ISR aufgerufen. Ob du sie selber implementiert hast oder
nicht.
Nur: für den Fall, dass du sie nicht selber implementiert hast, kommt
die gcc-Default Routine zum Einsatz, welche macht: den Prozessor
resetten.
> entsprechende Flag nach der adc_init(); geht das ganze wunderbar! Was> mir allerdings noch unklar ist, ist der Effekt, dass wenn ich sei(); an> eine andere Position im Programmcode verschoben habe, das ganz bis> dorthin "funktioniert" hat. Wohl ein unglückliches Zusammenspiel.......> !?
Nicht wirklich.
Ist alles erklärbar.
Und genau aus dem Grund hatte ich auch nach komplettem Code gefragt. Ich
wollte den durchsuchen ob du irgendwo einen Interrupt freigibst für den
du keine ISR hast. Denn wenn nach einem sei() seltsame Dinge passieren,
hat man mit der Hypothese einer fehlenden ISR eine 95%
Trefferwahrscheinlichkeit.
Hallo Karl-Heinz,
mir ist inzwischen schon klar was du meinst. Ich war gedanklich einfach
auf der falschen Baustelle, nämlich ausschließlich bei den Timern in
Verbindung mit der globalen Interruptfreigabe, unterwegs und hab die
Geschichte mit der ADC Initialisierung vollkommen vergessen.
Wie gesagt, danke nochmals an alle, die sich der Sache angenommen haben
:) Hoffe, es wird weiterhin keine solchen blöden Fehler geben ;)
Gruß
Stefan
Stefan S. schrieb:> Zuersteinmal lag es nicht an sei();
Deine Feststellung rundet dies schöne Beispiel für eine fehlgeschlagene
Thread-Titel-Auswahl ab. Gerade eine der wichtigsten Funktionen der libc
als Schuldigen auszumachen, tztztz...