mikrocontroller.net

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


Autor: Marcel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Marcel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Gast (Gast)
Datum:

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

Autor: Marcel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
#define F_CPU 1000000
 
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
 
int status = 0;
float count;
 
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;
 
  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;
  }
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Marcel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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 
....

ISR(TIMER0_OVF_vect)
{
  count++;

  if( count == 4 ) {
    count = 0;

    if( status ) {
      PORTD ^= (1 << PD6);
    }
  }
}

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.