Hi,
ich hab ein glaub ich relativ einfaches Problem, welches ich aber
irgendwie nicht gelöst bekomme. Also ich löse mit einem Taster (an PD2
angeschlossen) die ISR aus. Nun möchte ich das ich bei jedem durchlauf
dieser Routine um 1 hochgezählt wird. Also auf Deutsch ich möchte die
Tastenanschläge von PD2 zählen und diese in einer Variable an die main
übergeben? Entprellt hab ich den Taster und in die ISR komm ich
auch(klappt mit einem anderen Programm super)!
Kann irgendwer helfen??
MfG
Ohne deinen Code zu kennen, gibt es leider zu viel unbekanntes, als das
man deine Frage wirklich beantworten könnte.
Wo liegt denn dein konkretes Problem?
Kannst du die Tastenanschläge nicht zählen? Weil eventuell zu viele
gezählt werden, Dann funktioniert dein entprellen nicht richtig!
Oder Zählst du zu wenige Tastenanschläge? Auch dann würde ich auf deine
Entprellung tippen.
Oder schaffst du es nicht, die richtig gezählte Anzahl aus der ISR an
das Hauptprogramm zu übermitteln?
Für letzteres würde man eine globale Variable verwenden, die allerdings
volatile deklariert werden muss, damit es vernünftig klappt.
Außerdem musst du, wenn die Variable größer als 1 Byte ist, dafür
sorgen, das der Zugriff auf die Variable im Hauptprogramm nicht durch
die ISR unterbrochen werden kann. Also am besten kurz vorher die
Interrupts sperren und danach freigeben:
http://www.mikrocontroller.net/articles/Interrupt#Interruptfeste_Programmierung
Das erste, was mir aufgefallen ist, ist, das a als int32_t deklariert
ist. Muss das sein? Der Atmel ist ein 8-Bit Prozessor. 32Bit
Additionen/Vergleiche sind für einen 8-Bitter recht aufwendig. Erwartest
du wirklich 2.14 Billionen Tastendrücke? Ich würde a auch nicht als int
sondern als unsigned int deklarieren.
Dann fiel mir auf, das du im Code überhaupt keine Entprellung hast! Ein
real existierender Taster prellt aber immer! Ein Tastendruck prellt
etliche male nach, so das du diesen einen Tastendruck 10, 20mal zählst.
Ist ist deshalb nicht besonders klug den Taster direkt einen Interrupt
auslösen zu lassen. Besser ist es den Taster innerhalb eines
periodischen Timerinterrupts abzufragen, oder falls du keine
zeitkritische Anwendung im Sinn hast, diesen mit der Warteschleifen
Methode abzufragen.
Entprellung: http://www.mikrocontroller.net/articles/Entprellung
Dann ist natürlich auch sofort klar weshalb dein Code nicht
funktioniert:
1
if(a==1)
2
{
3
PORTB |= (1<<PB4);
4
}
Aufgrund des Prellen ist es sehr unwahrscheinlich das a genau zu dem
einen und einzigen Zeitpunkt, wo du a abfragst den Wert 1 hat. Der
Vergleich wird also niemals true!
Außerdem ist die Position des Vergleichs schlecht gewählt. Er müsste in
der while schleife sein und ist leider auch nicht mit cli()/sei()
interruptfest gestaltet.
Also entprellt ist die Taste mit mit na schönen 100nF Kapazität!
Ist der Zähler sonst in Ordnung so? also müsste a um 1 erhöht werden
wenn ich die Taste drücke?
Deine Code ist falsch. Du prüfst am Anfang genau einmal, ob die Anzahl
der Tastendrücke stimmt, danach gehst Du in eine Endlosschleife und dein
Hauprprogramm steht still.
Prüfe die Anzahl der Tastendrücke am Besten innerhalb der
Endlosschleife!
Aber wenn ich in die ISR springe, was er durch Tastendruck ja macht,
läuft er die main doch von vorne durch oder nicht? das heißt er müsste
den wert von a doch wieder neu vergleichen!?! oder versgteh ich das
falsch??
MicroDave schrieb:> Aber wenn ich in die ISR springe, was er durch Tastendruck ja macht,> läuft er die main doch von vorne durch oder nicht?
Das wäre aber fatal.
Nein.
Ein Interrupt unterbricht die momentane Programmausführung, bei dir die
while-Schleife.
Nach Beendigung der ISR geht es genau dort weiter, wo der Interrupt
unterbrochen hat. Genau das ist ja der Sinn eines Interrupts: Das
normale Hauptprogramm arbeitet vor sich hin. Plötzlich tritt ein
Ereignis auf, welches von der ISR kurzfristig behandelt wird und danach
macht das Hauptptogramm weiter als ob nichts passiert wäre.
Du bastelst an deinen Projekten ja auch dort weiter wo du aufgehört hast
wenn die Unterbrechung "Mittagessen" vorbei ist und fängst nicht
jedesmal wieder von vorne an.
Oh man stimmt! Sorry das wär ja sonst sowas wie ein Reset. Also ich habe
jetzt mal meine Code etwas verändert! Ich will ja die Variable a wieder
zurückgeben, aber irgendwie geht das nicht so wie ich mir das vorstelle.
Er soll bei Tastendruck die Variable a toggeln und diesen neuen Wert an
die do-while Schleife übergeben. Steh voll aufm Schlauch!
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
volatile int8_t a;
ISR(INT0_vect)
{
a ^= 1;
}
int main(void)
{
DDRB |= (1<<PB4);
DDRD &= ~(1<<PD2);
PORTD |= (1<<PD2);
MCUCR |= (1<<ISC01) | (1<<ISC00);
GICR |= (1<< INT0);
sei();
do
{
PORTB |= (1<<PB4);
}
while(a==1);
while(1)
{
return a;
}
}
MicroDave schrieb:> Oh man stimmt! Sorry das wär ja sonst sowas wie ein Reset. Also ich habe> jetzt mal meine Code etwas verändert! Ich will ja die Variable a wieder> zurückgeben,
zurückgeben an wen?
Dein Programm ist schon im Hauptprogramm, da ist nichgts mehr, an das du
einen Wert zurückgeben könntest!
1
intmain(void)
2
{
3
DDRB|=(1<<PB4);
4
5
DDRD&=~(1<<PD2);
6
PORTD|=(1<<PD2);
7
MCUCR|=(1<<ISC01)|(1<<ISC00);
8
GICR|=(1<<INT0);
9
sei();
10
11
while(1){
12
if(a>1)
13
PORTB|=(1<<PB4);
14
}
15
}
Du solltest wirklich mit einfacheren Dingen als mit Interrupts anfangen,
wenn dir das Verständnis dessen was hier passiert Schwierigkeiten macht.
Karl heinz Buchegger schrieb:> Du solltest wirklich mit einfacheren Dingen als mit Interrupts anfangen,> wenn dir das Verständnis dessen was hier passiert Schwierigkeiten macht.
Voll zustimm, das ist für Dich mehrere Nummern zu groß.
Also erstmal:
- LED an,
- LED blinken mit Delay,
- LED blinken mit Timer,
- LED blinken mit Timerinterrupt,
- LED mit Taste an/aus,
- LED mit Taste toggle
- 2 LEDs mit 2 Tasten toggle
Dann bist Du bereit.
Peter