Forum: Mikrocontroller und Digitale Elektronik Tastenanschläge zählen in c (ATMEGA32)


von MicroDave (Gast)


Lesenswert?

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

von SF (Gast)


Lesenswert?

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

von MicroDave (Gast)


Lesenswert?

Hey Danke für die schnelle Antwort!

Hier ist mein Code:

#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>

volatile int32_t a = 0;
ISR(INT0_vect)
  {
   a=a+1;
  }

int main(void)

{
  DDRB |= (1<<PB4);

  DDRD &= ~(1<<PD2);
  PORTD |= (1<<PD2);

  MCUCR |= (1<<ISC01) | (1<<ISC00);
  GICR |= (1<< INT0);
  sei();

if(a==1)
{
  PORTB |= (1<<PB4);
}

while(1);
}

von SF (Gast)


Lesenswert?

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.

von MicroDave (Gast)


Lesenswert?

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?

von Modernator (Gast)


Lesenswert?

1
int main(void){
2
  DDRB |= (1<<PB4);
3
4
  DDRD &= ~(1<<PD2);
5
  PORTD |= (1<<PD2);
6
7
  MCUCR |= (1<<ISC01) | (1<<ISC00);
8
  GICR |= (1<< INT0);
9
  sei();
10
11
  if(a==1)
12
  {
13
    PORTB |= (1<<PB4);
14
  }
15
16
  while(1) {
17
    //hier sollte der "a"-Vergleich stehen!
18
  } //ENDLOSSCHLEIFE
19
}

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!

von MicroDave (Gast)


Lesenswert?

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??

von Karl H. (kbuchegg)


Lesenswert?

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.

von MicroDave (Gast)


Lesenswert?

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;
}

}

von Karl H. (kbuchegg)


Lesenswert?

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
int main(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.

von Peter D. (peda)


Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.