Forum: Mikrocontroller und Digitale Elektronik Atmega8 PORTB


von Rafael S. (rafi)


Angehängte Dateien:

Lesenswert?

Hallo ihr da draußen,

ich habe mich in den letzten Tagen etwas mit dem Atmega8 und der C- 
Programmierung beschäftigt. Bin also nicht so lange dabei!

Folgendes:
Ich habe 5 Taster und 5 LEDs. Jede LED wird von einem Taster ein und 
wieder ausgeschaltet. Dabei wird die LED beim Einschalten langsam hoch 
gedimmt. Das hochdimmen erfolgt über SoftPWM und wird in einer ISR 
realisiert.
Hardware:
Atmega8 auf einem MyAVR- Board.
Habe die Taster am PORTD und die LEDs am PORTC angeschlossen.

NUN zum Problem:
das Programm funktioniert soweit... nur wenn ich die LEDs an den PortB 
hänge, dann bleiben diese nicht an... sie gehen nach loslassen des 
Tasters wieder aus... das Phenomen habe ich am PORTC nicht. Nach 
loslassen des Tasters bleiben die LEDs auch an....

Frage => ist an dem PORTB etwas was ich nicht berücksichtige ??

Der Code ist nur für eine LED... den Rest habe ich 
übersichtlichkeitshalber ausgeblendet.

Danke im Voraus!!!
Gruß
Rafael

von Karl H. (kbuchegg)


Lesenswert?

1
        pwmlaufvar0++;
eine Variable die 'unsigned char' ist, kann nicht unbegrenzt hochzählen. 
Irgendwann ist der Wert 255 erreicht, dann erfolgt beim nächsten 
Increment ein Überlauf und der Wert wird wieder zu 0.

Du hast da ein bischen viele Variablen in deinem Programm. Damit jagst 
du dich nur selbst ins Boxhorn.
Du brauchst:
genau eine Variable für den PWM-Counter
genau eine Variable für jede Led.


Am Port B ist programmtechnisch nichts besonderes. Er verhält sich wie 
jeder andere Port auch.
1
volatile unsigned char led1Brightness;
2
volatile unsigned char led2Brightness = 64;
3
4
ISR (TIMER0_OVF_vect)
5
{
6
  static unsigned char pwmCounter;
7
8
  pwmCounter++;   // gewollter Überlauf nach 255
9
10
  if( pwmCounter <= led1Brightness && led1Brightness != 0 )
11
    PORTB |= ( 1 << PB0 );
12
  else
13
    PORTB &= ~( 1 << PB0 );
14
15
  if( pwmCounter <= led2Brightness && led2Brightness != 0 )
16
    PORTB |= ( 1 << PB1 );
17
  else
18
    PORTB &= ~( 1 << PB1 );
19
}

Die Helligkeit steuerst du ausschliesslich über die Variable 
'led1Brightness'. Willst du die LED abschalten, dann weisst du der 
Variablen einfach eine 0 zu und gut ists. Mit deinen diversen Lauf und 
Stopp Variablen schiesst du dir nur selber ins Knie, weil du den 
Überblick verlierst, wie welche Variable wann stehen muss, damit was 
passiert. Variablen sind gut. Aber zu viele Variablen auf ein Problem 
werfen ist auch nicht das Gelbe vom Ei.

Ich hab dir doch schon mal gezeigt, wie man so eine Tastenauswertung 
inklusive Dimmung macht. Warum benutzt du das denn nicht? Alles was du 
brauchst, das ist eine weitere Variable, die als Vorgabevariable 
fungiert. In die schreibst du den Helligkeitswert, auf den die LED 
hindimmen soll. Von diesem Vorgabewert ausgehend wird dann genau diese 
'led1Brightness' aus verändert. Willst du die LED auf einen Schlag auf 
einen Wert setzen (wie zb 0) dann schreibst du den neuen Wert dann eben 
nicht nur in diesen Vorgabewert sondern zusätzlich auch nach 
led1Brightness
1
     if( Taste gedrückt und hochdimmen )
2
       led1Vorgabe = 255;   // nur dimmen
3
4
     if( Taste gedrückt und ausschalten )
5
     {
6
       led1Vorgabe = 0;    // dimmen auf 0
7
       led1Brightness = 0; // aber die LED auch gleich auf 0 setzen
8
                           // -> effektiv wird hier also nicht gedimmt, sondern
9
                           // die LED geht sofort aus.
10
     }
11
12
     // hochdimmen notwendig?
13
     if( led1Brightness < led1Vorgabe )
14
       led1Brightness++;
15
16
     // runterdimmen notwendig?
17
     // da in diesem Programm nicht runter gedimmt wird
18
     // kann das auch entfallen
19
//     if( led1Brightness > led1Vorgabe )
20
//       led1Brightness--;
21
22
     _delay_ms( 10 );

: Bearbeitet durch User
von Rafael S. (rafi)


Lesenswert?

Hallo Karl Heinz,
danke für deine schnelle Antwort!:) und für die Hilfe!!!!

Ja ich gebe zu, dass ich zu viele Variablen in dem Code habe. Ist mein 
erstes Programm :)
Es fällt mir noch ein wenig schwer auf den Punkt genau zu denken und dem 
entsprechend die Programme zu schreiben. Man verrennt sich oft und 
schnell in seinen eingenen Gedanken.... und dann wirds immer 
komplizierter!
Die Kunst hierbei denke ich ist es so einfach wie möglich aber effektiv 
zu programmieren... das werde ich noch viel üben müssen!


Ich werde mir deine Nachricht zu Brust nehmen und alles ausprobieren!


Karl H. schrieb:

> ISR (TIMER0_OVF_vect)
> {
>   static unsigned char pwmCounter;
>
>   pwmCounter++;   // gewollter Überlauf nach 255
>
>   if( pwmCounter <= led1Brightness && led1Brightness != 0 )
>     PORTB |= ( 1 << PB0 );
>   else
>     PORTB &= ~( 1 << PB0 );
> }

Eine Frage dazu noch :

Soll die Zeile:
if( pwmCounter <= led1Brightness && led1Brightness != 0 )
nicht so heißen
if( pwmCounter <= led1Brightness && led1Vorgabe != 0 )?

Danke!!!!!
Gruß
Rafael

von Rafael S. (rafi)


Lesenswert?

Hallo noch einmal,


Rafael S. schrieb:

> Soll die Zeile:
> if( pwmCounter <= led1Brightness && led1Brightness != 0 )
> nicht so heißen
> if( pwmCounter <= led1Brightness && led1Vorgabe != 0 )?


Ich denke diese Frage hat sich erübrigt!
Es hat gerade "klick" gemacht!!! :)


Gruß
Rafel

von Karl H. (kbuchegg)


Lesenswert?

Rafael S. schrieb:

> Eine Frage dazu noch :
>
> Soll die Zeile:
> if( pwmCounter <= led1Brightness && led1Brightness != 0 )
> nicht so heißen
> if( pwmCounter <= led1Brightness && led1Vorgabe != 0 )?


Nein.
An dieser Stelle geht es darum, wie hell die LED sein soll. Das hat 
nichts mit irgendwelchen 'Vorgaben' oder dergleichen zu tun. Schmeiss 
die Dinge nicht durcheinander. Das eine ist die Relaisierung einer 
bestimmten Helligkeit unabhängig davon wo der Wert für die Helligkeit 
her kommt. Das ist das, worum es bei der PWM geht. Das andere ist das 
Dimmen - also das gezielte variieren dieser Helligkeit. 2 
unterschiedliche Themenkreise.
Man könnte natürlich die ganze Dimmung hin zu einem Vorgabewert 
ebenfalls in der Timer-ISR unterbringen. Trotzdem ist es vernünftig das 
immer noch als eigenständigen Mechanismus anzusehen.

: Bearbeitet durch User
von Rafael S. (rafi)


Lesenswert?

Guten Morgen Karl Heinz,

ich habe mir am Freitag noch dein Code zur Tastenbetätigung aus dem 
anderen Thread angeschaut und habe aufgrund dessen eine einfache LED Ein 
und Ausschaltung mit einem Taster realisieren wollen.

Beitrag "atmega8 led dimmen ohne PB1, PB2 (OC1A, OC1B)"

Leider klappt es nicht mit der Ausschaltung.

Taster0Vorher = taster0;

// Hauptschleife
while(1)
{

Taster0Jetzt = taster0;

   if( Taster0Jetzt != Taster0Vorher )
   {
    Taster0Vorher = Taster0Jetzt;
      if(!Taster0Jetzt) 
{ 
LED0_ON;
}    }
return 0;
}

Wir fragen also am Anfang ab, ob sich der Zustndand der Taste verändert 
hat. Wenn ja.. sie ist also nun gedrückt worden Signalzustand des 
Eingangs geht von "1" auf "0", dann wird "Taster0Vorher" auch eine "0" 
zugewiesen. Ist der Taster immer noch gedrückt, also auf "0", dann wird 
die LED eingeschaltet.

Wenn ich nun nach der Einschaltbedingung die Ausschaltbedingung 
schreibe, dann wird die LED nie angehen, weil sie direkt wieder 
ausgeschaltet wird.

if (Taster0Vorher == Taster0Vorher)
  {
  Taster0Vorher=1;
  LED0_OFF;
  }

Meine Frage ist... wie bekomme ich es hin, dass die LED anbleibt, aber 
mit wiederholtem Tastetdruck wieder ausgeht ?


Sorry für diese Amateurfragen! Aber ich stehe da iwie auf dem Schlauch!

Danke im Voraus! :)

Gruß
Rafael

von Stefan F. (Gast)


Lesenswert?

Suche mal den Artikel zum Thema "Tastenentprellung". Das steht, wie  es 
geht.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Stefan U. schrieb:
> Suche mal den Artikel zum Thema "Tastenentprellung". Das steht, wie  es
> geht.

In PeDas 'Komfort' Routine gibt es dafür 'get_key_short' und 
'get_key_long', welches zwischen kurzen und langen Tastendrücken 
unterscheidet. Du kannst also das von anderen Geräten gewohnte Verhalten 
bauen, das ein kurzer Tastendruck die LED an und ausschaltet, während 
ein langer Tastenddruck die Dimmerfunktion steuert.

https://www.mikrocontroller.net/articles/Entprellung#Timer-Verfahren_.28nach_Peter_Dannegger.29
Zugegeben, die Routine erscheint beim ersten Anschauen komplizierter als 
nötig, wenn sie aber einmal implementiert ist, läuft sie zuverlässig und 
komfortabel.

von Rafael S. (rafi)


Lesenswert?

Hallo zusammen,

Danke für die schnelle Antwort! :)

Stefan U. schrieb:
> Suche mal den Artikel zum Thema "Tastenentprellung". Das steht,
> wie  es
> geht.

Werde mich dem jetzt direkt annehmen!

Matthias S. schrieb:
> Stefan U. schrieb:

> In PeDas 'Komfort' Routine gibt es dafür 'get_key_short' und
> 'get_key_long', welches zwischen kurzen und langen Tastendrücken
> unterscheidet.

Ebenfalls danke füe die Anktwort!
Die Superroutine von PeDas kenne ich bereits, aber ich muss erstmal die 
Basics verstehen :) Da steige ich noch nicht so gut durch!
Bin ja ein blutiger Anfänger :D

Gruß
Rafael

von Karl H. (kbuchegg)


Lesenswert?

Rafael S. schrieb:

> Die Superroutine von PeDas kenne ich bereits, aber ich muss erstmal die
> Basics verstehen :) Da steige ich noch nicht so gut durch!
> Bin ja ein blutiger Anfänger :D

Diese Tastenerkennung und Entprellung ist eine der wenigen Codestücke, 
von denen ich jedem zugestehe, dass er sie einfach verwenden kann, ohne 
zu verstehen wie er funktioniert.
Oder kannst du selbst eine performante Wurzel-Funktion schreiben? 
Trotzdem würdest du ohne Hemmungen einen Phytagoras programmieren.

von Karl H. (kbuchegg)


Lesenswert?

Rafael S. schrieb:
> Wenn ich nun nach der Einschaltbedingung die Ausschaltbedingung
> schreibe, dann wird die LED nie angehen, weil sie direkt wieder
> ausgeschaltet wird.
>
> if (Taster0Vorher == Taster0Vorher)
>   {
>   Taster0Vorher=1;
>   LED0_OFF;
>   }
>
> Meine Frage ist... wie bekomme ich es hin, dass die LED anbleibt, aber
> mit wiederholtem Tastetdruck wieder ausgeht ?

Du musst anfangen Dinge voneinander zu trennen!

Das eine ist die Erkennung einer Tastenbetätigung.

Punkt

Das andere ist, was diese Betätigung auslöst.

Punkt.

Das sind 2 verschiedene Dinge! Solange du nicht sicher genug bist, 
solltest du die Dinge strikt voneinander trennen.

Du erkennst eine Tastenbetätigung (richtigerweise) so:
1
  betaetigt = 0;
2
  Taster0Vorher = taster0;
3
4
  // Hauptschleife
5
  while(1)
6
  {
7
    Taster0Jetzt = taster0;
8
    if( Taster0Jetzt != Taster0Vorher ) {
9
      Taster0Vorher = Taster0Jetzt;
10
      betaetigt = 1;
11
    }
12
13
    // die Variable 'betaetigt' sagt dir jetzt, ob es einen
14
    // auszuwertenden Tastendruck gegeben hat oder nicht.
15
16
    ....
17
18
    _delay_ms( 10 );
19
  }

Das ist das eine. Jetzt wissen wir, ob eine Taste gedrückt wurde oder 
nicht.

Das andere ist, was mit diesem Tastendruck geschehen soll. Er soll eine 
LED schalten. D.h. wenn die LED nicht leuchtet, dann soll sie 
eingeschaltet werden und wenn sie leuchtet dann soll sie ausgeschaltet 
werden.
1
  betaetigt = 0;
2
  Taster0Vorher = taster0;
3
4
  // Hauptschleife
5
  while(1)
6
  {
7
    Taster0Jetzt = taster0;
8
    if( Taster0Jetzt != Taster0Vorher ) {
9
      Taster0Vorher = Taster0Jetzt;
10
      betaetigt = 1;
11
    }
12
13
    // die Variable 'betaetigt' sagt dir jetzt, ob es einen
14
    // auszuwertenden Tastendruck gegeben hat oder nicht.
15
16
    if( betaetigt ) {
17
      betaetigt = 0;
18
      if( IS_LED_ON() )
19
        LED_OFF();
20
      else
21
        LED_ON();
22
    }
23
24
    delay_ms( 10 );
25
  }

man sieht hier schon: das eine hat mit dem anderen im Grunde nichts zu 
tun, ausser das die Umschaltung der LED durch die Taste ausgelöst wird. 
Das Umschalten selbst ist aber recht unspezifisch von der Taste 
abhängig. Das könnte genausogut bei einer Temperaturüber- bzw. 
unterschreitung passieren, oder wenn eine Drehzahl zu hoch wird, oder 
.... was auch immer. Irgendetwas triggert das Umschalten der LED (oder 
eines Motors oder eines Relais). Abhängig ist der jeweils zu schaltende 
Zustand (Ein oder Aus) von nichts anderem als von dem Zustand in dem die 
LED (Motor, Relais, ...) jetzt gerade ist. Wenn der Zeitpunkt zur 
Umschaltung da ist, dann wird einfach nachgesehen: wie steht es um die 
LED (Motor, Relais, ...) jetzt gerade, welches ist der jetzige Zustand 
und je nachdem wird in den jeweils anderen Zustand geschaltet.

Um zu wissen, wie die LED jetzt gerade steht, kannst du eine weitere 
Variable benutzen, oder du siehst ganz einfach am entsprechenden Portpin 
nach. Niemand sagt, dass man an einem Port-Ausgangspin nicht auch 
nachsehen darf, wie der Ausgangspinn gerade steht
1
    if( PORTC & ( 1 << PC1 ) )   // steht der Pin auf 1?
2
      PORTC &= ~( 1 << PC1 );    //  -> ja tut er. auf 0 schalten
3
    else
4
      PORTC |= ( 1 << PC1 );     //  -> nein, tut er nicht. auf 1 schalten

Wenn du nur 1 Taste hast, dann kann man natürlich die Variable 
'betaetigt' wieder los werden, zumal die davon abhängige OPeration jetzt 
nicht so umfangreich ist.
1
  betaetigt = 0;
2
  Taster0Vorher = taster0;
3
4
  // Hauptschleife
5
  while(1)
6
  {
7
    Taster0Jetzt = taster0;
8
    if( Taster0Jetzt != Taster0Vorher ) {
9
      Taster0Vorher = Taster0Jetzt;
10
11
      // Taste wurde betätigt, die LED PC0 in den anderen Zustand schalten
12
      if( PORTC & ( 1 << PC0 ) )
13
        PORTC &= ~( 1 << PC0 );
14
      else
15
        PORTC |= ( 1 << PC0 );
16
    }
17
18
    _delay_ms( 10 );
19
  }

Jeder Code ist aus 'Modulen' zusammengebaut. Diese können auch manchmal 
ineinander geschachtelt sein, so wie in der letzten Version. Aber nichts 
desto trotz finden sich auch hier wieder die 2 Teilaufgaben wieder: Das 
eine ist die Erkennung eines Tastendrucks, die andere Teilaufgabe ist 
das was dieser Tastendruck auslösen soll.

: Bearbeitet durch User
von Jan H. (jan_m_h)


Lesenswert?

Karl H. schrieb:
> Diese Tastenerkennung und Entprellung ist eine der wenigen Codestücke,
> von denen ich jedem zugestehe, dass er sie einfach verwenden kann, ohne
> zu verstehen wie er funktioniert.

Was dahinter steckt ist relativ simpel, aber bei der Lösung von PeDa ist 
so viel optimiert worden, dass es wirklich schwierig wird noch 
durchzublicken, vor allem für einen Anfänger.

von Karl H. (kbuchegg)


Lesenswert?

Jan H. schrieb:
> Karl H. schrieb:
>> Diese Tastenerkennung und Entprellung ist eine der wenigen Codestücke,
>> von denen ich jedem zugestehe, dass er sie einfach verwenden kann, ohne
>> zu verstehen wie er funktioniert.
>
> Was dahinter steckt ist relativ simpel, aber bei der Lösung von PeDa ist
> so viel optimiert worden, dass es wirklich schwierig wird noch
> durchzublicken, vor allem für einen Anfänger.

Brauchst du mir nicht sagen :-)
Ich hab als ich den Code das erste mal gesehen habe, rund 40 Minuten 
gebraucht um dahinter zu steigen, was jede Anweisung macht und warum sie 
genau so und nicht anders formuliert ist. Und ich würde mich keinesfalls 
als Anfänger bezeichnen. Diese 8 parallelen horizontalen Zähler sind 
nicht so leicht zu durchschauen.
Ändert aber nichts daran, dass der Code einfach zu gut funktioniert um 
ihn aus den falschen Gründen heraus nicht zu verwenden.

von Karl H. (kbuchegg)


Lesenswert?

Karl H. schrieb:

> Um zu wissen, wie die LED jetzt gerade steht, kannst du eine weitere
> Variable benutzen,


Das wirst du zum Beispiel dann benutzen, wenn du am Portpin keinen 
eindeutigen Zustand ablesen kannst. Du willst die LED ja vielleicht 
dimmen und dann kannst du aufgrund der PWM vom aktuellen Zustand des 
Portpins selber nichts ableiten. Der kann ja, je nachdem zu welchem 
Zeitpunkt du innerhalb des PWM Zykluses nachsiehst, 0 oder 1 sein. Also 
wirst du dir hier eine weitere Variable zu hilfe nehmen. Nennen wir sie 
ganz einfach 'led1Zustand'. Wenn die Variable 1 ist, dann soll das 
bedeuten, dass die LED leuchtet (auch wenn sie gerade erst hochdimmt) 
und wenn sie 0 ist, dann soll das bedeuten, dass die LED auf jeden Fall 
nicht leuchtet.


Also wirst du schreiben
1
  Taster0Vorher = taster0;
2
3
  // Hauptschleife
4
  while(1)
5
  {
6
    Taster0Jetzt = taster0;
7
    if( Taster0Jetzt != Taster0Vorher ) {
8
      Taster0Vorher = Taster0Jetzt;
9
10
      if( led1Zustand == 0 ) {  // war die LED aus?
11
        led1Vorgabe = 255;       //   hochdimmen starten
12
        led1Zustand = 1;         //   und vermerken, dass die LED jetzt leuchtet
13
      }
14
      else {                     // nein, die LED hat schon geleuchtet
15
        led1Vorgabe = 0;         //   dimmen auf 0
16
        led1Brightness = 0;      //   aber die LED auch gleich auf 0 setzen
17
        led1Zustand = 0;         //   und vermerken, dass die LED jetzt aus ist
18
      }
19
    }
20
21
     .....

das wäre eine Möglichkeit. Eine andere wäre es, die Variable led1Vorgabe 
gleich dafür mitzubenutzen. leuchtet die LED, dann hat die ja den Wert 
255. Leuchtet sie nicht, dann hat sie den Wert 0.
1
  Taster0Vorher = taster0;
2
3
  // Hauptschleife
4
  while(1)
5
  {
6
    Taster0Jetzt = taster0;
7
    if( Taster0Jetzt != Taster0Vorher ) {
8
      Taster0Vorher = Taster0Jetzt;
9
10
      if( led1Vorgabe == 0 ) {  // war die LED aus?
11
        led1Vorgabe = 255;       //   hochdimmen starten
12
      }
13
      else {                     // nein, die LED hat schon geleuchtet
14
        led1Vorgabe = 0;         //   dimmen auf 0
15
        led1Brightness = 0;      //   aber die LED auch gleich auf 0 setzen
16
      }
17
    }
18
19
     ....

viele Wege führen nach Rom. Aber da wie dort ist der Knackpunkt die 
Unterscheidung, dass die Erkennung eines Tastendrucks und das was dieser 
beweirken soll, 2 voneinander getrennt zu sehende Dinge sind, die halt 
nur 'zufällig' über die zu erzielende Logik miteinander in dem Sinne 
verknüpft sind, dass das eine das andere auslöst.
Man kann das ganz gut daran erkennen, dass ich auch der "Beschreibung" 
der Bedingungen
1
     if( Taste gedrückt und hochdimmen )
2
       led1Vorgabe = 255;   // nur dimmen
3
4
     if( Taste gedrückt und ausschalten )
5
     {
6
       led1Vorgabe = 0;    // dimmen auf 0
7
       led1Brightness = 0; // aber die LED auch gleich auf 0 setzen
8
                           // -> effektiv wird hier also nicht gedimmt, sondern
9
                           // die LED geht sofort aus.
10
     }
den Teil 'Taste gedrückt' wie in der Mathematik als gemeinsamen Teil 
beider Bedingungen 'herausheben' kann. Und genau das will ich ja sowieso 
tun, weil es keinen Sinn macht, denselben Bedingungsteil 2 mal testen zu 
müssen. Das ist nur eine Fleissaufgabe für nichts.
1
     if( Taste gedrückt )
2
     {
3
       if( hochdimmen )
4
         led1Vorgabe = 255;   // nur dimmen
5
6
       if( ausschalten )
7
       {
8
         led1Vorgabe = 0;    // dimmen auf 0
9
         led1Brightness = 0; // aber die LED auch gleich auf 0 setzen
10
                           // -> effektiv wird hier also nicht gedimmt, sondern
11
                           // die LED geht sofort aus.
12
       }
13
     }

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Karl H. schrieb:
> Diese Tastenerkennung und Entprellung ist eine der wenigen Codestücke,
> von denen ich jedem zugestehe, dass er sie einfach verwenden kann, ohne
> zu verstehen wie er funktioniert.

Wenn man die Sache mit der Timer Initialisierung und den evtl. 
differierenden Vektornamen der Timer Overflow ISR einmal auf den MC 
angepasst hat, sehe ich das auch so. Diese beiden Punkte allerdings muss 
jeder, der die Routine anwendet, implementieren und begreifen.

: Bearbeitet durch User
von Rafael S. (rafi)


Lesenswert?

Hallo Karl Heinz,
wow... ich bin sprachlos! Tausend DANK für die HILFE!!! Du hast wirklich 
alles sehr ausführlich beschrieben. Ich werde mich direkt heute Abend an 
die Arbeit machen und mich damit ausgibig beschäftigen.
Wie du schon geschrieben hast man muss die Dinge gedanklich Trennen.
Erst schauen was der Taster macht und dann wenn "betätigt" schauen was 
er auslöst! Klingt eigentlich einfach ... aber ertmal auf die Idee 
kommen sich das genau so einfach zu machen. Das fällt mir noch nicht 
sooo einfach! Aber ich denke mit der Zeit komme auch ich dahin... :)


Also! ...üben üben üben :)


Nochmals DANKE! ;)

Gruß
Rafael

von Rafael S. (rafi)


Lesenswert?

Hi,
ich möchte ungern mit meinen Beiträgen hier euch allen vor allem dir 
Karl Heinz auf den Senkel gehen. Ich komme mir schon selbst ein wenig 
blöde vor!
Aber ich habe mir gestern Abend den Code vorgenommen und ein wenig 
probiert....

Der Code den ich auf meinen Atmega8 gebrannt habe:
1
#define F_CPU 3686400
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <stdbool.h>
5
#include <avr/interrupt.h>
6
7
#define LED0_ON PORTC |= (1<<PC0)
8
#define LED0_OFF PORTC &= ~(1<<PC0)
9
10
#define taster0 (PIND & (1<<PD0))
11
12
uint8_t Taster0Jetzt;
13
uint8_t Taster0Vorher;
14
15
 int main(void)
16
{
17
DDRC = 0xff;      // PORTC als Ausgang
18
DDRD = 0x00;      // PORTD als Eingänge
19
PORTD = 0xff;      // PullUps für PORTD
20
21
  betaetigt = 0;
22
  Taster0Vorher = taster0;
23
24
  // Hauptschleife
25
  while(1)
26
  {
27
    Taster0Jetzt = taster0;
28
    if( Taster0Jetzt != Taster0Vorher ) {
29
      Taster0Vorher = Taster0Jetzt;
30
      betaetigt = 1;
31
    }
32
33
    // die Variable 'betaetigt' sagt dir jetzt, ob es einen
34
    // auszuwertenden Tastendruck gegeben hat oder nicht.
35
36
    if( betaetigt ) {
37
      betaetigt = 0;
38
      if( IS_LED_ON() )
39
        LED_OFF();
40
      else
41
        LED_ON();
42
    }
43
44
    delay_ms( 10 );
45
  }
46
  }
Fogende Feststellung: die LED geht solange AN, solange ich den Taster 
drücke. Lasse ich den Taster los, geht sie AUS.
Ich interpretiere den Code fogendermaßen:
Das Programm wird auf den Kontroller wie oben aufgeführt gebrannt.
Taster0jetzt und Taster0Vorher sind beide HIGH "1".
Taste wird betätigt und betätigt gehalten => Taster0jetzt wird LOW.
Dadurch dass nun Taster0Jetzt != Taster0Vorher ist, läuft das Programm 
durch die if- Schleife, Taster0Vorher wird LOW, in "betaetigt" wird eine 
"1" geschrieben.
Somit wäre die Bedingung für die If- Schleife erfüllt, in der die LED 
entweder ein- bzw ausgeschaltet wird. Je nach Zustand der LED.
In unserem Fall geht die LED erstmal an.
Nun folgendes.... ich lasse den Taster los.
In diesem Moment wird taster0jetzt HIGH und Taster0Vorher ist noch auf 
LOW. Ergo... ich habe ein ungleich in der ersten IF- Schleife.

if( Taster0Jetzt != Taster0Vorher )

Jetzt wird taster0vorher HIGH und "betaetigt" ist immernoch "1".
Die Bedingung für die nächste if- Schleife ist gegeben und die LED geht 
aus.
Somit kann die LED nie mit einem Tasterdruck ein und beim nächsten 
wieder ausgeschaltet werden.
Was wird eigentlich aus der Variable "betaetigt"? Ihr wird beim ersten 
Tastendruck die 1 zugewiesen und dann bleit sie für immer aus 1? Sie 
müsste iwo wieder mit 0 beschrieben werden.?!?

Liege ich da gedanklich richtig ??

Wenn ich in der zweiten IF- Schleife noch zusätzlich den Taster abfrage, 
dann funktioniert es. Die LED wird mit eimen Tasterdruck ein und mit dem 
nächsten drücken wieder ausgeschaltet....

    if( ! Taster0Vorher && betaetigt ) {
      betaetigt = 0;
      if( IS_LED_ON() )
        LED_OFF();
      else
        LED_ON();
    }

Was ist aber mit der Variablen "betaetigt" ??

Gruß
R

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Rafael S. schrieb:
> Sie
> müsste iwo wieder mit 0 beschrieben werden.?!?

So isses. Du kannst aber die Routine ein klein wenig erweitern:
1
    if( Taster0Jetzt != Taster0Vorher ) {
2
      Taster0Vorher = Taster0Jetzt;
3
      betaetigt = 1;
4
    } else betaetigt = 0;

Dann sollte das klappen.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Rafael S. schrieb:

> Ich interpretiere den Code fogendermaßen:
> Das Programm wird auf den Kontroller wie oben aufgeführt gebrannt.
> Taster0jetzt und Taster0Vorher sind beide HIGH "1".
> Taste wird betätigt und betätigt gehalten => Taster0jetzt wird LOW.
> Dadurch dass nun Taster0Jetzt != Taster0Vorher ist, läuft das Programm
> durch die if- Schleife, Taster0Vorher wird LOW, in "betaetigt" wird eine
> "1" geschrieben.
> Somit wäre die Bedingung für die If- Schleife erfüllt, in der die LED
> entweder ein- bzw ausgeschaltet wird. Je nach Zustand der LED.
> In unserem Fall geht die LED erstmal an.
> Nun folgendes.... ich lasse den Taster los.
> In diesem Moment wird taster0jetzt HIGH und Taster0Vorher ist noch auf
> LOW. Ergo... ich habe ein ungleich in der ersten IF- Schleife.
>
> if( Taster0Jetzt != Taster0Vorher )
>
> Jetzt wird taster0vorher HIGH und "betaetigt" ist immernoch "1".
> Die Bedingung für die nächste if- Schleife ist gegeben und die LED geht
> aus.

ABgesehen davon, dass ein if technisch gesehen keine Schleife ist, ist 
die Analyse soweit richtig. Gratuliere!

> Somit kann die LED nie mit einem Tasterdruck ein und beim nächsten
> wieder ausgeschaltet werden.

Doch. du musst dur nur überlegen, ob jeder Wechsel des Tastenzustands zu 
einem betaetigt führen soll, oder nur dann wenn die Taste von 1 auf 0 
wechselt (also niedergedrueckt wurde).
Das ist aber leicht festzustellen. Wenn die Taste jetzt auf 0 ist, dann 
muss das ein Wechsel von 1 auf 0 gewesen sein. Das kann man testen und 
nur dann betaetigt auf 1 setzen wenn genau das erfüllt ist. Den anderen 
Wechsel (also das Loslassen der Taste) ignoriert man einfach. In deinem 
Programm interessiert er schlicht und ergreifend nicht.

> Was wird eigentlich aus der Variable "betaetigt"? Ihr wird beim ersten
> Tastendruck die 1 zugewiesen und dann bleit sie für immer aus 1? Sie
> müsste iwo wieder mit 0 beschrieben werden.?!?

Wird die doch.
Hier
1
    if( betaetigt ) {
2
      betaetigt = 0;

wird der Tastendruck bearbeitet, dann setzt du das Flag welches eine 
niedergedrückte Taste vermerkt, wieder zurück auf 0.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Rafael S. schrieb:

> Wenn ich in der zweiten IF- Schleife noch zusätzlich den Taster abfrage,
> dann funktioniert es. Die LED wird mit eimen Tasterdruck ein und mit dem
> nächsten drücken wieder ausgeschaltet....

Kannst du machen.
Aber denk an die Überlegung die Dinge zu trennen.
Du willst in deinem Programm das Niederdrücken einer Taste erkennen. Das 
gehört logisch gesehen in den Themenkreis 'Erkennen einer gedrückten 
Taste' und (in deinem Programm) nicht in den Themenkreis 'Was soll ein 
Tastendruck bewirken'.

Es gibt natürlich auch Fälle, bei denen man explizit zwischen 
Niederdrücken und Loslassen unterscheidet. Dann würde das in einem 
gewissen Sinne zur Auswertung gehören. Den Fall hast du aber nicht. Dich 
interessiert qquer durch dein Programm nur das Niederdrücken (was auch 
der häufigere Fall ist). Also siedelst du diese Funktionalität im 
Dunstkreis genau dieser Erkennung eines Tastendrucks an. Denn du willst 
dich nicht in weiterer Folge mit diesem technischen Detail rumschlagen. 
Wenn die Tastenerkennung nur dann 'Bescheid gibt', wenn sie ein 
Niederdrücken registriert, dann bist du happy damit. Überhaupt wenn du 
dann irgendwann einmal mehrere Tasten und je nach Kontext 
unterschiedliche Codestellen zur Bearbeitung hast.
1
    if( Taster0Jetzt != Taster0Vorher ) {   // irgendwas ist mit der Taste passiert
2
                                            // nur was? Die Taste kann niedergedrueckt
3
                                            // worden sein oder aber auch losgelassen
4
      Taster0Vorher = Taster0Jetzt;
5
      if( !Taster0Jetzt )                   // wenn es ein Niederdrücken war
6
        betaetigt = 1;                      // dann werten wir das als Betaetigung
7
    }

: Bearbeitet durch User
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.