Forum: Compiler & IDEs Newbie in C / AVR Taste entprellen


von Kai S. (kahrl)


Lesenswert?

Hallo User,

ich versuche mich seit ein paar Tagen in die Welt der AVRs 
einzuarbeiten, leider kann ich noch nicht wirklich viel in C. Habe mir 
schon einige Toturials angesehen und ein kleines Erfolgserlebnis mit dem 
ATtiny2313 gehabt.

Ich habe ein Programm geschrieben, welches einen Ausgang (PB7) schaltet 
wenn Taster_1 (PD0) gedrückt wird und ihn löscht wenn Taster_2 (PD1) 
gedrückt wird. Funktioniert soweit.

Nun hab ich das ganze erweitert um Taste_3 (PD2) diese schaltet ein, und 
bein nächsten drücken wieder aus. Nun stehe ich aber vor dem Problem der 
Tasten-Prellung. Ich habe mir die Code-Schnipsel hier von der Seite 
"gemopst" weiß leider nicht wie ich diesen nun richtig in mein Programm 
einbinde. Ich hoffe Ihr könnt mir weiter helfen...

1
#include <avr/io.h>
2
3
#include <util/delay.h>    
4
#include <avr/delay.h>
5
6
7
#define F_CPU 8000000UL
8
9
10
11
// Einschalten
12
13
void ein (void)              // "ein" ist eine freie Bezeichnung der Routine
14
15
  {
16
    PORTB = (1<<PB7);        // Schaltet PB7 auf HIGH (5V)
17
    return 0;
18
  }
19
20
21
// Ausschalten            
22
23
void aus (void)              // "aus" ist eine freie Bezeichnung der Routine
24
25
  {
26
    PORTB = (0<<PB7);        // Schaltet PB7 auf LOW (0V)
27
    return 0;
28
  }
29
30
31
// Funktion Entprellung
32
33
34
void entprellung( volatile uint8_t *port, uint8_t maske ) 
35
  
36
  {
37
      uint8_t   port_puffer;
38
      uint8_t   entprellungs_puffer;
39
 
40
      for( entprellungs_puffer=0 ; entprellungs_puffer!=0xff ; ) 
41
    
42
    {
43
    
44
      entprellungs_puffer<<=1;
45
        port_puffer = *port;
46
        _delay_us(150);
47
      if( (*port & maske) == (port_puffer & maske) )
48
        entprellungs_puffer |= 0x01;
49
    
50
    }
51
  }
52
53
54
55
// Hauptschleife
56
57
int main (void)              // "main" Bezeichnet die Hauptschleife
58
59
  {
60
    int x=0;            // "int"=Integer (Vermutlich Ganzzahl)
61
                    // "x" freie Variable hat Wert 0
62
    DDRD  = 0x7F;          // DDRD  als Eingang PD0-PD6
63
    PORTD = 0x7F;          // PORTD Pullups einschalten PD0-PD6
64
    
65
    DDRB  = 0xFF;          // DDRB  als Ausgang PB0-PB6
66
67
    while(1)             // Soviel wie tu.. mach was..
68
      
69
    {
70
71
      if (!(PIND & (1<<PD0)))    // Guck ob PD0 High ist, und wenn es nicht so ist*
72
        ein();          // geh zur "ein" Schleife
73
74
      if (!(PIND & (1<<PD1)))   // Guck ob PD1 High ist, und wenn es nicht so ist*
75
        aus();          // geh zur "aus" Schleife
76
77
78
    entprellung ( &PIND, (1<<PD2) );     // ggf. Prellen abwarten 
79
                       
80
81
      if (!(PIND & (1<<PD2)))    // Guck ob PD2 High ist, und wenn es nicht so ist
82
        if (x)  {x=0;ein();}  // --> Guck ob x=0 ist/war, wenn ja geh zur "ein" Schleife
83
          else        // --> oder
84
            {x=1;aus();}  // --> Guck ob x=1 ist/war, dann geh eben zur "aus" Schleife
85
                    // * Das (!) ist eine Negation, daher "wenn nicht"
86
    
87
    
88
    }                
89
      return 0;          // Fang von vorne an, bei "main"
90
  }

von Karl H. (kbuchegg)


Lesenswert?

Hol dir von hier
http://www.mikrocontroller.net/articles/Entprellung

zumindest das Debounce Makro vom Peter Danegger.

Noch besser funktionieren die Komfortroutinen weiter unten im Artikel. 
Die machen so ziemlich alles, was das Herz begehrt.

von Kai S. (kahrl)


Lesenswert?

Hallo Karl, und danke für die schnelle Antwort.

Auf der Seite hänge ich schon den halben Vormittag, ich weiß leider 
nicht wie ich das in meinen Code einbinden muss. Wie gesagt ich bin 
absoluter neuling in Sachen C. Deswegen habe ich mir erstmal für die 
"void entprellung..." von dort entschieden.


[Zitat]
zumindest das Debounce Makro vom Peter Danegger.

Noch besser funktionieren die Komfortroutinen weiter unten im Artikel.
Die machen so ziemlich alles, was das Herz begehrt.
[Zitatende]

Das mag sein, nur kann ich damit noch weniger anfangen...

Was mir helfen würde ist eine kurze Erklärung wie ich was und wo in 
meinen Code einbinden muss, damit ich es auch verstehe. Am liebsten wäre 
es mir, wenn man mir erklärt ob und was am obigen Code falsch ist und 
was man warum ändern muss.

Danke.

von Karl H. (kbuchegg)


Lesenswert?

Kai S. schrieb:
> Hallo Karl, und danke für die schnelle Antwort.
>
> Auf der Seite hänge ich schon den halben Vormittag, ich weiß leider
> nicht wie ich das in meinen Code einbinden muss. Wie gesagt ich bin
> absoluter neuling in Sachen C. Deswegen habe ich mir erstmal für die
> "void entprellung..." von dort entschieden.

Dort ist doch ein komplettes Beispiel!

Machs doch anders rum:
Übernimm das Beispiel so wie es ist.
Passe die Pinbelegung auf deine an, kompilier es und bring es zum 
laufen.
Und dann baust du deinen Code dort ein.

Deine 2 Funktionen und 3 Abfragen hast du doch in 0 komma nix dort 
eingebaut. Für dich ist erst mal nur das interessant, was in den 
Beispielen in der main() Funktion steht. Dort kann man sich ansehen, wie 
das jeweils verwendet wird.

> [Zitat]
> zumindest das Debounce Makro vom Peter Danegger.
>
> Noch besser funktionieren die Komfortroutinen weiter unten im Artikel.
> Die machen so ziemlich alles, was das Herz begehrt.
> [Zitatende]
>
> Das mag sein, nur kann ich damit noch weniger anfangen...

Die Routine ist so trickreich, dass es ok ist, wenn man nicht versteht 
wie sie funktioniert. Das ist eine der wenigen Ausnahmen, bei denen ich 
es als für in Ordnung befinden würde.

> Was mir helfen würde ist eine kurze Erklärung wie ich was und wo in
> meinen Code einbinden muss, damit ich es auch verstehe.

Auch dort ist ein komplettes Beispiel.

> Am liebsten wäre
> es mir, wenn man mir erklärt ob und was am obigen Code falsch ist und
> was man warum ändern muss.

Dein Hauptproblem ist, dass dein Code für die ABfrage von PD2 nicht das 
implementiert, was du haben willst.
Dein Code macht:
  * wenn die Taste gedrückt IST, dann schalte den Eingang um
Du willst aber machen:
  * wenn die Taste gedrückt WIRD, dann schalte um

Im ersten Fall detektierst du ob der Pegel des Tasteneingangs low ist, 
und so eine gedrückte Taste anzeigt. Das ist: Wenn die Taste gedrückt 
IST

Im zweiten Fall musst du aber feststellen, ob sich der Pegel des 
Tasteneingangs verändert hat, gegenüber dem Zeitpunkt an dem du zuletzt 
nachgesehen hast. Hat sich der Pegel nicht verändert, dann ist an der 
Taste auch nichts passiert. Die Taste ist immer noch gedrückt oder nicht 
gedrückt. Hat sich der Pegel aber verändert, dann ist die Taste entweder 
gedrückt oder losgelassen worden.

Die Funktion entprellung macht das aber nicht. Die stellt nur sicher 
(soll sicherstellen), dass der Pegel konstant ist. Was du dann mit dem 
Pegel weiter machst, ist dein Bier.

von Kai S. (kahrl)


Lesenswert?

Hallo Karl,

ich bekomme beim Compilieren immer folgende Meldung:


Build started 24.1.2011 at 12:44:24
avr-gcc  -mmcu=attiny2313 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char 
-funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT 
Entprellt2313.o -MF dep/Entprellt2313.o.d  -c  ../Entprellt2313.c
../Entprellt2313.c:18:2: warning: #warning kein F_CPU definiert
../Entprellt2313.c: In function 'main':
../Entprellt2313.c:119: error: 'TCCR0' undeclared (first use in this 
function)
../Entprellt2313.c:119: error: (Each undeclared identifier is reported 
only once
../Entprellt2313.c:119: error: for each function it appears in.)
make: *** [Entprellt2313.o] Error 1
Build failed with 3 errors and 1 warnings...


Woran kann das liegen?

von Kai S. (kahrl)


Lesenswert?

Gut, für den ATiny muß man wohl TCCR0B schreiben, hab ich grad gelesen. 
Nun Compiliert er mit nur einer Warnung.

Build started 24.1.2011 at 12:50:03
avr-gcc  -mmcu=attiny2313 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char 
-funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT 
Entprellt2313.o -MF dep/Entprellt2313.o.d  -c  ../Entprellt2313.c
../Entprellt2313.c:18:2: warning: #warning kein F_CPU definiert
avr-gcc -mmcu=attiny2313 -Wl,-Map=Entprellt2313.map Entprellt2313.o 
-o Entprellt2313.elf
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature 
Entprellt2313.elf Entprellt2313.hex
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" 
--change-section-lma .eeprom=0 --no-change-warnings -O ihex 
Entprellt2313.elf Entprellt2313.eep || exit 0
avr-objdump -h -S Entprellt2313.elf > Entprellt2313.lss

von Karl H. (kbuchegg)


Lesenswert?

Kai S. schrieb:

> ich bekomme beim Compilieren immer folgende Meldung:

Ah. ok
An deinen Prozessor musst du die Registernamen schon anpassen.

> ../Entprellt2313.c:18:2: warning: #warning kein F_CPU definiert

Stell im AVR-Studio in den Project Options deine Taktfrequenz ein

> ../Entprellt2313.c: In function 'main':
> ../Entprellt2313.c:119: error: 'TCCR0' undeclared (first use in this
> function)

Das Konfigurationsregister für den Timer 0, in dem die Vorteilerbits 
sind, heißt beim Tiny2313 TCCR0B.
Die Belegung und die Bedeutung der Bits ist aber identisch.

Siehe Datenblatt

von Kai S. (kahrl)


Lesenswert?

Okay, das ganze geht soweit.

Nun werde ich mir mal den Code "verinnerlichen" damit ich auch kapiere 
was da so passiert...


An dieser Stelle ersteinmal Vielen Dank für die Unterstützung!

von Karl H. (kbuchegg)


Lesenswert?

Kai S. schrieb:
> Okay, das ganze geht soweit.
>
> Nun werde ich mir mal den Code "verinnerlichen" damit ich auch kapiere
> was da so passiert...

Im einfachsten fall brauchst du nur

   get_key_press( 1<<KEY2 )

dann halt jeweils mit dem richtigen Key


   if( get_key_press( 1<<KEY2 ) )
     mach was

wird genau dann ausgeführt, wenn die Taste 1-mal gedrückt wird.
Fertig.
Einfacher gehts nicht

von Kai S. (kahrl)


Lesenswert?

Kann ich denn in so einem Code alles was nach dem letzten

"#include" bzw. schon nach dem "#endif"
und vor
"int main void"

steht in eine Datei Namens xyz.c schreiben und diese dann ganz oben 
aufrufen z.B. mit "#include <xyz.c>" oder geht das so nicht?

Wenn das ne echt dumme Frage ist, erschlag mich nicht gleich, ich 
versuche nur zu verstehen wie das Programmieren in C so von statten 
geht, was möglich ist und was nicht.

learning by doing
und wenn´s nicht geht freundlich Fragen ;-)

von Karl H. (kbuchegg)


Lesenswert?

Kai S. schrieb:

> steht in eine Datei Namens xyz.c schreiben

kannst du

> und diese dann ganz oben
> aufrufen z.B. mit "#include <xyz.c>" oder geht das so nicht?

aber nicht so.
*.c Files inkludiert man nicht

http://www.mikrocontroller.net/articles/FAQ#Ich_hab_da_mehrere_.2A.c_und_.2A.h_Dateien._Was_mache_ich_damit.3F

von Walter (Gast)


Lesenswert?

Kai S. schrieb:
> ein();          // geh zur "ein" Schleife

das ist übrigens alles mögliche, eine Funktion, Unterprogramm, Prozedur,
aber auf keinen Fall eine Schleife

von Kai S. (kahrl)


Lesenswert?

>Kai S. schrieb:
>> ein();          // geh zur "ein" Schleife

>das ist übrigens alles mögliche, eine Funktion, Unterprogramm, Prozedur,
>aber auf keinen Fall eine Schleife


OK, Danke. Ich werd das mal in meinem Text abändern..

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.