Forum: Compiler & IDEs Newbie-Fragen zum Programmcode (entplellen)


von Markus (Gast)


Lesenswert?

Hey Leute,
bin noch ein echter Newbie in Sachen µC. Nach dem Lauflichter und 
solchen Scherzen, wollte ich mir folgenden Programmcode von Peter 
Danneger zum entprellen mal nachvollziehen.
Leider habe komme ich an einigen Stellen nicht wirklich weiter. Unter 
dem Code stehen einige Fragen die IHR mir mit Sicherheit beantworten 
könnt.

Bin über jeden Kommentar dankbar! Ihr braucht euch nicht genötigt fühlen 
gleich alle Fragen zu beantworten (sind doch mehr geworden als ich 
dachte).

DANKE!!
1
/************************************************************************/
2
/*                                                                      */
3
/*                      Not so powerful Debouncing Example              */
4
/*                      No Interrupt needed                             */
5
/*                                                                      */
6
/*              Author: Peter Dannegger                                 */
7
/*                                                                      */
8
/************************************************************************/
9
// Target: ATtiny13
10
 
11
#include <avr/io.h>
12
#define F_CPU 9.6e6
13
#include <util/delay.h>
14
 
15
 
16
#define debounce( port, pin )                                         \
17
({                                                                    \
18
  static uint8_t flag = 0;     /* new variable on every macro usage */  \
19
  uint8_t i = 0;                                                      \
20
                                                                      \
21
  if( flag ){                  /* check for key release: */           \
22
    for(;;){                   /* loop ... */                         \
23
      if( !(port & 1<<pin) ){  /* ... until key pressed or ... */     \
24
        i = 0;                 /* 0 = bounce */                       \
25
        break;                                                        \
26
      }                                                               \
27
      _delay_us( 98 );         /* * 256 = 25ms */                     \
28
      if( --i == 0 ){          /* ... until key >25ms released */     \
29
        flag = 0;              /* clear press flag */                 \
30
        i = 0;                 /* 0 = key release debounced */        \
31
        break;                                                        \
32
      }                                                               \
33
    }                                                                 \
34
  }else{                       /* else check for key press: */        \
35
    for(;;){                   /* loop ... */                         \
36
      if( (port & 1<<pin) ){   /* ... until key released or ... */    \
37
        i = 0;                 /* 0 = bounce */                       \
38
        break;                                                        \
39
      }                                                               \
40
      _delay_us( 98 );         /* * 256 = 25ms */                     \
41
      if( --i == 0 ){          /* ... until key >25ms pressed */      \
42
        flag = 1;              /* set press flag */                   \
43
        i = 1;                 /* 1 = key press debounced */          \
44
        break;                                                        \
45
      }                                                               \
46
    }                                                                 \
47
  }                                                                   \
48
  i;                           /* return value of Macro */            \
49
})
50
 
51
/*
52
   Testapplication
53
 */
54
int main(void)
55
{
56
  DDRB  &= ~(1<<PB0);   
57
  PORTB |=   1<<PB0;  
58
  DDRB  |=   1<<PB2;  
59
  DDRB  &= ~(1<<PB1);  
60
  PORTB |=   1<<PB1;  
61
  DDRB  |=   1<<PB3; 
62
  for(;;){    
63
    if( debounce( PINB, PB1 ) )
64
      PORTB ^= 1<<PB2;    
65
    if( debounce( PINB, PB0 ) )
66
      PORTB ^= 1<<PB3;   
67
  }
68
}
1.Was bedeutet das static vor der dem uint8_t flag=0 gleich am Anfang 
der Funktion debounce? Kann die Variable den Zustand vielleicht 
automatisch ändern?? Sonst würde in der ersten if-Abfrage immer nur der 
erste Teil des Programmcodes verwendet werden können.
2.Welche Auswirkungen hat das break in der Funktion debounce? Wird die 
Funktion unterbrochen und der aktuelle Wert den i hat zurück gegeben? 
Ach ja, warum steht vor dem Rückgabewert i kein return am ende der 
Funktion?
3. Bei der Funktion _delay_us (98); dachte ich das ich nur auf die 
folgende Randbedingung achten muss: maximal mögliche Delay-Zeit: 
262,14ms/F_CPU in MHz.  D.h. bei dem ATmega8 (interner Takt 
1MHz---262,14ms/1MHz=262,14ms)kann ich einfach _delay_ms(25) angeben 
wenn ich 25ms warten möchte.
4.Was bedeutet das ^= in der main-Funktion?
5.Was passiert, wenn Eine Taste dauernd gedrückt wird? Toggelt der 
Ausgang dann?
Puh, das reicht für den Anfang.
Danke für eure Hilfe!!
Markus

von Sven P. (Gast)


Lesenswert?

Hier ein paar Ansätze zum selbstständigen Durchdenken:
> 1.Was bedeutet das static vor der dem uint8_t flag=0 gleich am Anfang
> der Funktion debounce?
Schau mal in ein C-Buch :-)

> 2.Welche Auswirkungen hat das break in der Funktion debounce?
Schau mal in ein C-Buch.

> Ach ja, warum steht vor dem Rückgabewert i kein return am ende der
> Funktion?
'debounce' ist garkeine Funktion, sondern Textersatz, auch 'Makro' 
genannt.

> 3. Bei der Funktion _delay_us (98); dachte ich das ich nur auf die
> folgende Randbedingung achten muss: maximal mögliche Delay-Zeit:
> 262,14ms/F_CPU in MHz.
Das dachten viele vor dir auch. Lies nochmal genauer nach.

> 4.Was bedeutet das ^= in der main-Funktion?
Schau mal in ein C-Buch oder in eine Operatorentabelle.


Ich möchte dir damit nicht halbherzig etwas an den Kopf knallen, versteh 
das bitte nicht falsch. Aber ich bin mir sicher, du bist in der Lage, 
die ersten vier Fragen nun selbst zu beantworten.

von Markus (Gast)


Lesenswert?

Hallo Sven,
haben noch mal gegoogelt:) Mit dem Vorsatz static behält die Variable 
ihren Wert wenn die Funktion erneut aufgerufen wird.
So weit so gut!
Sie wird ein mal ganz am Anfang mit 0 definiert. Wie sieht es denn mit 
der ersten if-Abfrage in der Funktion aus. Zunächst mal stört mich das 
da kein gleich steht wie z.B. if(flag==1) nach was fragt die 
if-Anweisung ab?

Eigentlich müsste die if-Abfrage negativ sein, weil sich der Zustand von 
flag sonst nicht ändert. Nur in dem else Teil der Abrage wird der 
Variablen Flag eine 1 zugeschrieben.

Wäre für ein paar mehr Infos dankbar!!
Markus

von Sven P. (Gast)


Lesenswert?

Markus schrieb:
> Hallo Sven,
> haben noch mal gegoogelt:) Mit dem Vorsatz static behält die Variable
> ihren Wert wenn die Funktion erneut aufgerufen wird.
Jein, so erklärt man es mitunter.
'static' bewirkt globales Verlinken. Deine statische Variable 
funktioniert eigentlich wie eine globale Variable (die du am 
Programmanfang vereinbarst), die aber trotzdem nur dort sichtbar ist, wo 
du sie vereinbart hast.


> Sie wird ein mal ganz am Anfang mit 0 definiert. Wie sieht es denn mit
> der ersten if-Abfrage in der Funktion aus. Zunächst mal stört mich das
> da kein gleich steht wie z.B. if(flag==1) nach was fragt die
> if-Anweisung ab?
Schau mal in ein C-Buch, dort steht, was in C wahr, und was falsch ist.

von Markus (Gast)


Lesenswert?

OK! Also:
1= wahr
0=falsch

Man kann für die erste if-Abfrage auch schreiben
if(flag==1) //oder??!!
Und eine 1 liegt an wenn der Taster nicht betätigt ist (wegen den 
PULL-down)

Im Prinzip verstehe ich das Programm, glaube ich. Mit dem Flag wird 
gespeichert wie der Zustand des Eingangs war. Danach wird zunächst 
geprüft ob das Signal toggelt. Und erst wenn ein sicher Zustand anliegt 
wird geschaltet, aber es bleiben einfach noch immer viel zu viele von 
meinen Fragen offen!!

Bevor ich den Code verwende möchte ich genau wissen wie alles 
funktioniert und nicht einfach Sachen zusammen basteln und hoffen das 
alles klappt.

Gruß Markus

von Markus (Gast)


Lesenswert?

Ahh, sorry wegen dem PULL-Up meine ich nicht PULL-down!!!
Markus

von Markus (Gast)


Lesenswert?

Was ist mit dem ^= ? Ich weiß das es die Funktin eines Exklusiv-ODER 
hat. Aber ich verstehe einfch nicht wie das zusammen passt!

Und warum braucht es kein return vor dem i am Ende der Funktion?

Wäre echt super wenn du mal was konkretes dazu schreiben würdest!!
Markus

von Sven P. (Gast)


Lesenswert?

Markus schrieb:
> Wäre echt super wenn du mal was konkretes dazu schreiben würdest!!
Dann lernste aber nix.

> Was ist mit dem ^= ? Ich weiß das es die Funktin eines Exklusiv-ODER
> hat. Aber ich verstehe einfch nicht wie das zusammen passt!
Mach dich mal schlau darüber, was eine Bitmaske ist. Dann wirds dir wie 
Schuppen von den Augen fallen.

> Und warum braucht es kein return vor dem i am Ende der Funktion?
Es ist keine Funktion, sondern ein Makro!
Dort, wo du es verwendest ('aufrufst'), wird ganz primitiver Textersatz 
vorgenommen: Statt 'debounce' steht der Rumpf des Makros dort.
Nun ist das ganze Makro ein Ausdruck. Das ist zugegebenermaßen etwas 
hässlich und GCC-spezifisch, aber naja.

Informiere dich mal über den Kommaoperator, dann denk mal über folgendes 
nach:
1
int x, y;
2
x = 1, 2, 3;
3
y = (1, 2, 3);

Ist zwar nicht das gleiche, dürfte dir aber einen wichtigen Anstoß 
geben.

von Peter D. (peda)


Lesenswert?

Markus schrieb:
> Und warum braucht es kein return vor dem i am Ende der Funktion?

Ein Return würde die Funktion verlassen, in der das Macro expandiert 
wird (d.h. in der der Textersatz stattfindet).
In diesem Fall würde also das Main verlassen werden.

Ein Macro kann aber trotzdem einen Wert haben, den man zuweisen kann:

"The last thing in the compound statement should be an expression 
followed by a semicolon; the value of this subexpression serves as the 
value of the entire construct."

http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html


Peter

von Haderlump (Gast)


Lesenswert?

Static:
In  C werden Variable, die innerhalb von Funktionen declariert werden, 
vom Compiler, bzw. dessen erzeugten Programmcode auf dem Stack erzeugt.
Das bedeutet natürlich beim Verlassen der Funktion, dass diese Variable 
wieder gelöscht wird. (der nächste Funktionsaufruf benutzt ja wieder 
diesen Stackbereich).
Will man haben, dass der Wert der Variablen beimn nächsten Aufruf wieder 
verfügbar ist, benutzt man das Wort static. Jetzt reserviert der 
Compiler Speicherplatz im Ram exclusiv für diese Variable, und wird 
nicht von irgend einem anderen Programmteil überschrieben.
Diese Variable ist deshalb aber noch nicht global, also von anderen 
Funktionen aufrufbar.

PORTB ^= 1<<PB2; ist glichbedeutend mit PORTB = POTRB  ^ 1<<PB2;

vergleichbar wäre z.B.  a += 5   ->  a = a +5

ist also quasi eine abgekürzte Schreibweise.

Grundsätzlich zu Tastaturabfragen:

Der Prozessor fragt ein Port immer zu einem bestimmten Zeitpunkt ab, 
also genau dann, wenn der Befehl kommt. Wenn man also auf einen 
Tastendruck wartet, muss man diesen Port immer wieder abfragen. Ändert 
sich nun etwas am Port, so wird das Programm wohl darauf mit irgend 
einer Aktion reagieren. Diese Aktionen sind in der Regel in ein paar 
Sekundebruchteilen abgehandelt, danach wird wieder der Port abgefragt um 
eine neue Aktion zu starten.
Wenn die Taste immer noch gedrückt ist, was wohl meist der Fall ist, 
würde diese Aktion erneut ausgeführt werden.
Um dies zu vermeiden, wird dann in einer Schleife gewartet, bis die 
Taste wieder losgelassen wird. Erst nach erneutem Drücken wird dann 
wieder di Aktion ausgelöst.

Übrigens Swen
Der Hinweis: "schau mal in ein Buch" ist nicht gerade Hilfreich. Da 
können wir dieses Forum dann gleich zu machen.
Man kann Markus ja wirklich nicht nachsagen, dass er von uns ein 
Programm geschrieben haben will.
Und C mit seinen kryptischen Abkürzungen ist ja nicht gerade leichte 
Kost.
Oft weiß man als Anfänger eben nicht, wo man am beesten im Buch sucht.
Manche Bücher sind auch nicht für Anfänger geschrieben, wenigstens hat 
man manchmal den Eindruck. Da werden oft Fachwörter gebrauht, die ein 
Anfänger einfach noch nicht weiß.

von Michael H. (michael_h45)


Lesenswert?

Haderlump schrieb:
> Übrigens Swen
vvvvvvvvvvvvvvvvvvv
> Der Hinweis: "schau mal in ein Buch" ist nicht gerade Hilfreich. Da
Ach bitte...
Der TO hat einfach mal gefragt, ohne vorher einen Finger krumm zu 
machen, sondern will sich das vorkauen lassen.
Ganz einfach daran zu erkennen, dass er nach Svens Aufforderung doch 
mal eine Suchmaschine bemüht und sich die ersten Antworten 
zusammengesucht hat.

Davor nicht.

> können wir dieses Forum dann gleich zu machen.
Dazu braucht man ja eigentlich nichts sagen...
Für dich trotzdem: Es gibt Fragen von Faulheit und von Unwissenheit 
motiviert gestellt. Hier geht es überwiegend um erstere.

> Man kann Markus ja wirklich nicht nachsagen, dass er von uns ein
> Programm geschrieben haben will.
Das hat Peter schon erledigt.
> Oft weiß man als Anfänger eben nicht, wo man am beesten im Buch sucht.
Na gaaanz vorne. Wo denn sonst??
Jedes Buch dieser Art hat eine Sektion für die Grundlagen. Wenn ich mich 
gar nicht auskenne, sind Grundlagen doch wohl das erste, oder?

> Manche Bücher sind auch nicht für Anfänger geschrieben, wenigstens hat
> man manchmal den Eindruck. Da werden oft Fachwörter gebrauht, die ein
> Anfänger einfach noch nicht weiß.
Dann schlägt man eben diese auch wieder nach! So viel 
Konzentrationsspanne wird doch wohl noch aufbringbar sein.

Das ist mühsam? Ja, richtig. Aber genau so geht lernen!
Nur weil man etwas mal gehört oder gesagt bekommen hat, bleibt es noch 
lange nicht so im Gedächtnis wie ein unter Konzentration selbst 
erarbeitetes Wissen.

von Sven P. (Gast)


Lesenswert?

Ich bin ja bereit, jedem was zu erklären, so gut ich kann. Deshalb auch 
prophylaktisch mein Hinweis, dass meine Antwort nicht halbherzig gedacht 
war, sondern den TO zum Lernen motivieren sollte.

Aber nachzufragen, was '^=' ist, ist schon etwas...verwirrend. Ich hab 
ja auch einen ganzen Stapel an C-Büchern gebraucht, bis ich glücklich 
wurde. Aber allen gemeinsam war, dass die Operatoren so ziemlich das 
Erste waren, was erklärt wurde.

Also nix für Ungut. Offenbar hats ja funktioniert, eine Reihe von Fragen 
hat der TO sich nun selbst beantworten können.

von Markus (Gast)


Lesenswert?

Hallo an ALLE!!
Zunächst einmal möche ich Peter und Haderlump danken!!
Jetzt ist mir endlich klar was der Unterschied zwischen einer Funktion 
und eines Marcos ist!! Der Unterschied zwischne static und globaler 
Variable ist nun auch klar!!
Endlich mal Beiträge die mich wirklich voran bringen!

Und nun zu den Kritikern. Wenn in dem Betreff steht "Newbie-Fragen zum 
Programmcode (entplellen)" dann ist denke ich klar das es auch mal 
leichte Fragen auftauchen!! Deswegen steht da ja NEWBIE!!
Dann möchte ich noch klar machen das man als Newbie sich nicht gleich 
zig c-Bücher zulegt. Ich habe gerade mal eins (Helmut Erlenkötter, C 
Programmieren von Anfang an) und da steht dieser Operator leider nicht 
drin!

Nun zu den Lenmethoden. Um die Grundlegenden Sachen zu lernen ist es 
sinnvoll sich erst mal Programme von "den alten Hasen" anzusehen. So 
verhindere ich das ich mir irgendetwas falsch aneigne. Ich glaube nicht 
das das bei irgendeinem am Anfang anders war!! Manchmal kann es einfach 
ungemein helfen wenn einem einfach etwas vorgesagt wird!! Auch wenn es 
bei dem ein oder anderen lange her ist und er sich nicht mehr dran 
erinnernt will. Von fremdem Programmcode konnte ich bis jetzt mehr 
lernen als aus irgendwelchen Büchern!! Mir geht es hier darum den 
geschriebenen Code zu verstehen!! Das ist für mich der erste Schritt zu 
eigenen anspruchsvollen Programmen. Einfach nur kopieren und bei Fehlern 
nicht wissen was los ist, ist nicht mien Ziel!
OK, mit dem static habe ich es mir etwas leicht gemacht. Das gebe ich 
zu.


So, jetzt muss ich aber noch mal zu einer meiner eigentlichen Fragen 
zurück kehren.

3. Bei der Funktion _delay_us (98); dachte ich das ich nur auf die
folgende Randbedingung achten muss: maximal mögliche Delay-Zeit:
262,14ms/F_CPU in MHz.  D.h. bei dem ATmega8 (interner Takt
1MHz---262,14ms/1MHz=262,14ms)kann ich einfach _delay_ms(25) angeben
wenn ich 25ms warten möchte.

Das müsste doch soweit stimmen, oder nicht?! Da ich später mal 
Zeitkritische Sachen programmieren möchte würde ich das noch gerne 
wissen. (Ich weiß das man für Zeitkritische Prozesse mit Timern und 
Interrupt programmiern sollte, aber so weit bin ich noch nicht)

Danke für Eure Hilfe!
Markus

von Sven P. (Gast)


Lesenswert?

Markus schrieb:
> Und nun zu den Kritikern. Wenn in dem Betreff steht "Newbie-Fragen zum
> Programmcode (entplellen)" dann ist denke ich klar das es auch mal
> leichte Fragen auftauchen!! Deswegen steht da ja NEWBIE!!
Selbsterniedrigung ist aber der falsche Weg. Du bist gewiss nicht doof.


> Dann möchte ich noch klar machen das man als Newbie sich nicht gleich
> zig c-Bücher zulegt. Ich habe gerade mal eins (Helmut Erlenkötter, C
> Programmieren von Anfang an) und da steht dieser Operator leider nicht
> drin!
Mag ja sein (auch wenn ich das kaum glauben mag), aber du bist gewiss 
nicht doof. Ich würde wetten, mit zwei Minuten Nachdenken hättest du 
deine Operatoren gefunden.


> Nun zu den Lenmethoden. Um die Grundlegenden Sachen zu lernen ist es
> sinnvoll sich erst mal Programme von "den alten Hasen" anzusehen. So
> verhindere ich das ich mir irgendetwas falsch aneigne.
Naja, dann würde ich mir die Entprell-Methode, die du da ausgegraben 
hast, schnell wieder abgewöhnen. Sie funktioniert zwar und sieht hübsch 
aus, ist aber weder portabel noch sonderlich Zeit- oder 
Speichereffizient.

> 3. Bei der Funktion _delay_us (98); dachte ich das ich nur auf die
> folgende Randbedingung achten muss: maximal mögliche Delay-Zeit:
> 262,14ms/F_CPU in MHz.  D.h. bei dem ATmega8 (interner Takt
> 1MHz---262,14ms/1MHz=262,14ms)kann ich einfach _delay_ms(25) angeben
> wenn ich 25ms warten möchte.
>
> Das müsste doch soweit stimmen, oder nicht?! Da ich später mal
> Zeitkritische Sachen programmieren möchte würde ich das noch gerne
> wissen. (Ich weiß das man für Zeitkritische Prozesse mit Timern und
> Interrupt programmiern sollte, aber so weit bin ich noch nicht)
Ich habe dich bereits darauf hingewiesen: *Lerne lesen!*
Und jetzt komm bitte nicht nochmal mit Newbie, Anfänger, schwierig und 
so weiter. Die gesuchte Information steht genau eine Zeile weiter.


> Danke für Eure Hilfe!
Bitte.

von Markus (Gast)


Lesenswert?

Ich hoffe das hier liest noch jemand:)
Habe mir den Code noch mal gut angesehen. Ich glaube ich weiß nun wies 
funktioniert, aber ich brauche in einem Punkt noch eine Bestätigung 
damit ich wirklich sicher sein kann.

Da es sich um beim Makro um einen Textersatz handelt, wird das debounce 
zwei mal aufgeraufen und es entstehen zwei Variablen namens flag (mit 
den oben beschriebenen static-Eigenschaften). Eine für den Eingang am 
PB1 und die andere für PB0.

Dann passt nämlich alles mit dem restlichen Code überein und die 
Entprellung funzt.

Ein ja oder nein als Antwort reicht aus:)

Markus

von Peter D. (peda)


Lesenswert?

Ja, jede Taste braucht ihre eigene Variable für den alten Zustand.
Deshalb mußte es auch als Macro geschrieben werden, als Inline-Funktion 
geht das nicht.


Peter

von Markus (Gast)


Lesenswert?

Alles klar! Dann hab ichs!!
Besten Dank!!

Markus

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.