Hallo Zusammen,
ich bin relativ neu in der Mikrocontroller-Welt und wollte deswegen ein
kleines Programm zum Verständnis der Timer und Interrupts schreiben.
Nach intensivem Studium des Datasheets komme ich aber hier leider nicht
weiter. Das Problem:
Am gesammten Port C meines Atmega32 hängen 8 LEDs (LOW Aktiv PC0-PC7):
Der Sinn des folgenden Programms sollte einfach sein die LED an PC0
mithilfe des 8-Bit Counters im CTC-Mode zum Blinken zu
bringen.(Geschwindigkeit war mir erstmal egal).
Wenn ich das Programm jedoch starte leuchten alle LEDs an Port C auf und
blinken auch nicht. Was mache ich falsch? Ich vermute, dass das Programm
erst gar nicht in die ISR springt. Ist die Timer Initialisierung falsch?
Gruß
Benni
c kann bei der if-Abfrage nie "1" sein, weil Du c "0" setzt und danach
das Bitkomplement bildest. c ist also zum Zeitpunkt der Abfrage immer
0xff oder "0", jedoch nie "1".
> int main(int argc, char **argv)
BTW:
Fällt mir grad so auf: Was soll der Blödsinn mit argc und argv denn da?
main kann bei einem Mikrocontroller nicht woandersher aufgerufen werden
und hat daher keine Parameter. Da kommt einfach ein "void" in die
Klammer!
Hi Johannes,
danke für die beiden Tipps!
Der "int main(int argc, char **argv)" Kram kam wohl von der
Auto-Vervollständigen-Funktion von eclipse.
Der Fehler mit der zweiten If Abfrage ist mir auch schon aufgefallen...
Habe beides korrigiert, aber leider hat sich an dem Problem nichts
geändert!
Ich suche weiter..
Danke aber trotzdem!
Gruß
Benni
Benjamin D. wrote:
> Der "int main(int argc, char **argv)" Kram kam wohl von der> Auto-Vervollständigen-Funktion von eclipse.
Aha...
> Der Fehler mit der zweiten If Abfrage ist mir auch schon aufgefallen...> Habe beides korrigiert, aber leider hat sich an dem Problem nichts> geändert!WAS hast Du korrigiert? Schick doch mal den Code, wie er jetzt
aussieht. Vielleicht haste das ja "verschlimmbessert"...
Sag mal, warum machst Du es so kompliziert? c kann genau zwei Zustände
annehmen, 0 und FF. Sowas kann man in dem Fall besser mit if...else
erschlagen und nicht mit zwei if hintereinander.
Allerdings ist die Umschalterei so eh unsinnig. Die Variable c ist
überflüssig. Schreib die ISR mal um zu
1
ISR(TIMER0_COMP_vect)
2
{
3
PORTC^=1<<PC0;//PortC.0 umschalten
4
}
Das sollte genau das machen, was Du erreichen willst und ist absolut
"idiotensicher" (und kürzer)...
Da das Ergebnis immer noch das Selbe ist (Alle LED's leuchten permanent)
heißt das doch eigentlich, dass die ISR aus irgendeinem Grund erst gar
nicht ausgeführt wird, oder?
Woran könnte das liegen? Müssen bestimmte FUSE BITS gesetzt werden um
Interrupts ausführen zu können? Ist nicht doch vielleicht die Timer
Initialiserung falsch?
Gruß
Benni
BTW:
Hast Du die Möglichkeit, die LED (oder von mir aus auch eine andere LED)
an den OC0-Pin zu hängen? Wenn ja, dann mach das mal. Schließlich hast
Du den Pin ja schon auf toggeln konfiguriert. Wenn sich da auch nichts
tut, dann läuft irgendwas nicht richtig.
Naja, wenn er den Mega32 nicht grad übertaktet, sollte selbst bei der
maximalen Frequenz von 16 MHz eine "Blinkfrequenz" von ca. 30 Hz
rauskommen, was eigentlich zumindest noch als Flimmern wahrzunehmen sein
sollte...
Hallo zusammen,
danke für eure zahlreichen Hilfen! Ich habe das Problem endlich gelöst.
Es lag alles nur an der von mir verwendeten Enwicklungsumgebung!
Ich benutzte das auf dieser Seite vorgestellte AVR-Plugin für Eclipse
http://www.mikrocontroller.net/articles/AVR_Eclipse
den folgenden Hinweis habe ich jedoch übersehen:
WARNUNG: Bei mir funktionierten Timer-Interrupts mit dem Plugin nicht
(die jedoch tadellos mit der WinAVR Makefile fuktionierten). Vielleicht
habe ich nur eine Option übersehen, seid aber auf der Hut. Wenn ihr
Unregelmäßigkeiten bei IRQs feststellt, versucht's erstmal ohne das
Eclipse-Plugin (bevor ihr stundenlang an eurem Code und euch selbst
zweifelt :-) ).
Habe mich dann nach Alternativen umgeguckt und bin hier fündig geworden:
http://sourceforge.net/projects/avr-eclipse
Damit funktioniert alles einwandfrei!
Vielen Dank vorallen an Johannes
Gruß
Benni
Eine Lichtkette besteht aus 8 Luchtdioden.Diese werden von einem
Mikrocontroller des Typs AVR ATMega8 angesteuert.Sie müssen verschiedene
Aufgaben zur Programmierung des eingebetteten Prozessors lösen.Die
Lichtkette sollzeitlich hochgenaueLichtwechsel ausführen.Sie benötigen
dazu eine Zeitbasisvon 500ms.Initialisieren den Timer0 so,dass
genaueinmal aller 500ms eine Interrupt SERVICE ROUTINE nebenläufig
aufgerufen wird.Die Quarzfrequenz beträgt 0.032768 MHZ.
kann jemand die aufgaben lösen?Das wäre dankbar.
void initTimer0()
{
Hallo an alle,
ich weiß jetzt nicht ob ich hier einfach mein problem reinschreiben
darf,aber es trifft genau dasselbe Thema, deswegen denke ich, kann es
nicht so verkehrt sein...
also ich habe auch den Atmega32, läuft mit 8 MHz, und möchte mit dem
16-bit-timer (Timer1) und einer Interrupt-service-routine Wartezeiten
erzeugen.
Hier mein Code:
1
#include<avr/io.h>
2
#include<stdint.h>
3
#include<avr/interrupt.h>
4
5
unsignedinti;
6
7
// Initialisierung für TimerWarte (16-bit-Timer/Counter1)
unsignedintADWert=300;/*Wert soll eigendlich vom AD-Wandler kommen,aber zu testzwecken, habe ich einen festen wert zugewiesen */
44
45
if(ADWert>220){
46
i=300;
47
}
48
49
}
50
}
Der Timer soll mit 100 Hz einen Interrupt erzeugen. Dies habe ich mit
dem Prescaler = 64 und Dem Vergleichsregister OCR1A = 1250 realisiert
(CPU läuft mit 8 MhZ)
In der ISR soll dann ein pwm-signal => OCR2 = 0x71 anliegen bis i = 0
ist.
i wird in der ISR runtergezählt. i ist zuständig für die Länge der
Wartezeit. je höher der Wert desto länger ist die Wartezeit, in meinem
Fall sind das 3 sekunden.
Nach diesen 3 sekunden soll dann das andere pwm-signal (also OCR2 =
0x9F) ausgegeben werden.
Mein Problem ist allerdings, dass OCR2 immer 0x9F ist und bleibt.
Ich hoffe jemand sieht den fehler im Quelltext, ich finde meinen Fehler
nicht, ich vermute allerdings, dass ein Fehler in der ISR und deren
deklaration liegt.
also ich bin für jeden Hinweis dankbar,
und sorry, wenn es falsch war bein Problem ist diesen alten Beitrag
reinzuschrieben.
viele Grüße aus Bochum
Greg
Greg01 schrieb:
> also ich bin für jeden Hinweis dankbar,
Dein i wird nie 0 werden.
Grund: In der Hauptschleife wird immer wieder auf 300 gesetzt, da ja
ADWert immer größer als 220 ist.
So sehr sich die ISR auch abmüht, kaum hat sie i um 1 verringert, setzt
die Hauptschleife es sofort wieder auf 300
Weiter hab ich nicht geschaut.
Edit: i volatile zu machen ist sowieso eine gute Idee.
Hallo,
vielen Dank für die Hinweise, mit diesen funktioniert es jetzt.
Allerdings möchte ich jetzt mein Programm so verändern, dass nur beim
ersten Start des Programms das erste pwm-signal 2 sekunden anliegt und
es dann auf das zweite umspringt.
Ich verstehe jetzt nur nicht, wo ich dann i = 200 (für 2 sekunden das
erste pwm-signal) festlegen muss,damit es nicht immer i-- überschreibt.
also nochmal ein quelltext, ein bisschen verändert:
1
#include<avr/io.h>
2
#include<stdint.h>
3
#include<avr/interrupt.h>
4
5
unsignedinti;
6
7
// Initialisierung für TimerWarte (16-bit-Timer/Counter1)
DDRD|=(1<<PD7);//OC2 (Pin 21) als PWM-Ausgang setzen
22
i=200;
23
}
24
25
//Interrupt-service- Routine
26
ISR(TIMER1_COMPA_vect){//Compare Match A - Vector
27
if(i>0){
28
i--;
29
OCR2=0x71;//PWM-Signal
30
}
31
else
32
OCR2=0x9F;//Anderes PWM-Signal
33
}
34
35
intmain(void){
36
37
timer_warte_initial();
38
timer2_initial();
39
40
while(1){}
41
42
}
ich dachte, indem ich timer2_initial() vor die while-schleife setze,
wird i nur einmal auf 200 gesetzt und die ISR- zählt dann bis 0 runter
und wechselt dann auf das 2.pwm-signal. Das funktioniert aber nicht, das
pwm-signal bleibt immer auf OCR2= 0x71 stehen.
kan mir bei diesem Problem nch jemand helfen?
vielen Dank wie immer für die Unterstützung,
Greg