Forum: Compiler & IDEs Tasterentprellung + LED blinken (timer)


von Marcel (Gast)


Lesenswert?

Hi zusammen, folgendes Programm ist sozusagen mein erster Gehversuch mit 
avr-gcc (ich komme eher aus der anwendungsentwicklung von PCs):

http://rafb.net/p/x9GtzP51.html

Das Programm läuft nicht so wie ich es mir dachte.
(Bei tastendruck soltle die led blinken bei erneuten tastendruck sollte 
sie aufhöhren)

es passiert aber nach einem tastendruck nix...

würde ich die led nur mit timer und interuppt blinken lasen geht das 
einwandfrei...

würde ich meinen code nach tastendruck (mit entprellung) die led 
an/ausschalten lassen geht das auch 1a

nur alles zusammen funktioniert nicht :/

was mache ich falsch?

MfG Marcel

von Karl H. (kbuchegg)


Lesenswert?

Dein Compiler kann nicht erkennen, dass die Änderung an der Variablen 
status in der ISR zum tragen kommt.
Für ihn sieht es so aus, als ob die ISR Funktion nie aufgerufen würde 
(der Compiler weiß nicht, dass die ISR automatisch aufgerufen wird)

Daher macht es für ihn auch keinen Sinn eine Variable zu beschreiben, 
die nirgendwo abgefragt wird. Wenn der Optimizer den ganzen Zugriff 
nicht überhaupt rauswirft, so versucht der Compiler zumindest die Zeit 
dafür einzusparen, indem er die Variable status in main() in einem 
Register hält. -> Die Änderung landet nie wirklich im Speicher.

volatile int status;

behebt dieses.

von Marcel (Gast)


Lesenswert?

Danke für deine Antwort, ich habe oben die variable status global 
folgendermaßen deklariert: volatile int status;

aber es tut sich immernoch nichts :/

MfG

von Gast (Gast)


Lesenswert?

Naja, für die Variable count gilt natürlich sinngemäß das gleiche.

von Marcel (Gast)


Lesenswert?

ok hab beide als volatile int gemacht, bringt aber nix (status war ja 
vorher der interrupt routine bekannt, das war also nicht das problem)

led bleibt immernoch, liegt der fehler vllt. woanders?

MfG

von Karl H. (kbuchegg)


Lesenswert?

Ich hol das Programm mal hierher.
Das ist doch Unsinn, da immer auf eine externe Website gehen zu müssen, 
wenn man ein Programm studieren soll
1
#define F_CPU 1000000
2
 
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
 
7
int status = 0;
8
float count;
9
 
10
inline uint8_t debounce(volatile uint8_t *port, uint8_t pin) {
11
    if (! (*port & (1 << pin)))       {
12
        /* Pin wurde auf Masse gezogen, 100ms warten */
13
        _delay_ms(100);
14
        if ( ! (*port & (1 << pin)) ) {
15
        /* Anwender Zeit zum Loslassen des Tasters geben */
16
            _delay_ms(100);
17
            return 1;
18
        }
19
    }
20
    return 0;
21
}
22
 
23
int main(void) {
24
  // Prescaler = FCPU/1024
25
  TCCR0|=(1<<CS02)|(1<<CS00);
26
 
27
  //Enable Overflow Interrupt Enable
28
  TIMSK|=(1<<TOIE0);
29
 
30
  //Initialize Counter
31
  TCNT0=0;
32
 
33
  count=0;
34
 
35
  DDRD = 0xff;
36
  DDRA = 0x00;
37
  PORTA = 0xff;
38
 
39
  sei();
40
 
41
  while(1) {
42
    if(debounce(&PINA, PA0))
43
      status ^= 1;
44
  }
45
}
46
 
47
ISR(TIMER0_OVF_vect) {
48
  //This is the interrupt service routine for TIMER0 OVERFLOW Interrupt.
49
  //CPU automatically call this when TIMER0 overflows.
50
 
51
  count++;
52
  if((count == 4) && status) {
53
    PORTD ^= (1 << PD6);
54
    count=0;
55
  }
56
}

von Karl H. (kbuchegg)


Lesenswert?

Also: count muss nicht volatile sein.
Es finden keine gmeinsamen Zugriffe aus main() und der ISR statt. Damit 
istr volatile kein Problem.

Aber float ist ein unglücklicher Datentyp für einen Zähler.
Laut Theorie kann zwar ein float bis zu einer bestimmten Zahl alle 
ganzen Zahlen exakt abbilden, ob das aber auch gilt, wenn gerechnet wird 
weiß ich nicht. Meine Hand drauf verwetten würde ich nicht.
Das mindeste was ich tun würde ist

   if((count >= 4) && status) {

Wenn bei der ganzen Inkrementiererei count zu 4.0000001 wird, dann 
funktioniert diese Variante immer noch, während der Vergleich auf exakt 
4 fehl schlägt.

status sollte auch ein 8-Bit Typ sein, also zb ein

unsigned char status

damit atomarer Zugriff garantiert ist.

Abgesehen davon ist mir nichts mehr aufgefallen

von Marcel (Gast)


Lesenswert?

Danke nun klappt es, der Code sieht folgendermaßen aus:



#define F_CPU 1000000

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile int count;
volatile int status;

inline uint8_t debounce(volatile uint8_t *port, uint8_t pin) {
    if (! (*port & (1 << pin)))       {
        /* Pin wurde auf Masse gezogen, 100ms warten */
        _delay_ms(100);
        if ( ! (*port & (1 << pin)) ) {
        /* Anwender Zeit zum Loslassen des Tasters geben */
            _delay_ms(100);
            return 1;
        }
    }
    return 0;
}

int main(void) {
  // Prescaler = FCPU/1024
  TCCR0 = (1<<CS02) + (1<<CS00);

  //Enable Overflow Interrupt Enable
  TIMSK|=(1<<TOIE0);

  //Initialize Counter
  TCNT0=0;

  count=0;
  status=0;

  DDRD = 0xff;
  DDRA = 0x00;
  PORTA = 0xff;

  sei();

  while(1) {
    if(debounce(&PINA, PA0))
      status ^= 1;
  }
}

ISR(TIMER0_OVF_vect) {
  //This is the interrupt service routine for TIMER0 OVERFLOW Interrupt.
  //CPU automatically call this when TIMER0 overflows.

  count++;
  if((count >= 4) && status) {
    PORTD ^= (1 << PD6);
    count=0;
  }
}


ich habe jetzt integer zum zaehlen genommen, ist ja sowieso 
sinnvoller...

jedenfalls bei count >= 4 funktioniert es, bei count == 4 funktioniert 
es nicht.

Warum zum Teufel?! Es ist ein Integer, der kann doch genau 4 sein...

verstehe ich nicht.


Danke bisher

MfG Marcel

von Karl H. (kbuchegg)


Lesenswert?

Marcel schrieb:

> Warum zum Teufel?! Es ist ein Integer, der kann doch genau 4 sein...

Können schon. Aber er muss nicht.

Wenn die ISR count hochzählt und status nicht gesetzt ist, dann wird 
count auch nie auf 0 zurückgesetzt sondern zählt hoch und zählt hoch 
....

1
ISR(TIMER0_OVF_vect)
2
{
3
  count++;
4
5
  if( count == 4 ) {
6
    count = 0;
7
8
    if( status ) {
9
      PORTD ^= (1 << PD6);
10
    }
11
  }
12
}

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.