LED blinken lassen per Taster

#1568053
Lesenswert?

Ich möchte gerne eine LED blinken lassen, sollange der Taster gedrückt 
ist:
1
    if(!(PINB & 0x01))                // Wenn Taste PortB.0 auf HIGH
2
      {
3
        PORTC |= (1 << PC0);        // LED an PB0 umschalten
4
        _delay_ms (200);
5
        PORTC &= ~(1 << PC0);        // LED an PB0 umschalten
6
        _delay_ms (200);
7
      }

Kann man das irgendwie eleganter lösen?
So in etwa das man in einer Zeile definiert das sich der letzte Zustand 
ändern soll.
#1568114
Lesenswert?

Magnetus schrieb:
> Ups.... Mist...
>
>
1
> while(1)
2
> {
3
>   if(!(PINB & 0x01))                // Wenn Taste PortB.0 auf HIGH
4
>     {
5
>       PORTC ^= (1 << PC0);        // LED an PB0 umschalten
6
>       _delay_ms (200);
7
>     }
8
>   PORTC &= ~(1 << PC0);        // LED an PB0 ausschalten (high-aktiv)
9
>   //PORTC |= (1 << PC0);        // LED an PB0 ausschalten (low-aktiv)
10
> }
11
>

Das wird allerdings ein kurzes 'Blinken' wenn die Taste gedrückt wird. 
Ich bezweifle, dass man das sehen wird. Kein Mensch kann eine LED, die 
nur µs auf 'aus' geht, von einer durchgehend leuchtenden LED 
unterscheiden :-)
Gast #1568141
Lesenswert?

Ok... noch ne Korrektur:
1
while(1)
2
{
3
  if(!(PINB & 0x01))                // Wenn Taste PortB.0 auf HIGH
4
    {
5
      PORTC ^= (1 << PC0);        // LED an PB0 umschalten
6
      _delay_ms (200);
7
    }
8
  else
9
    {
10
      PORTC &= ~(1 << PC0);        // LED an PB0 ausschalten (high-aktiv)
11
      //PORTC |= (1 << PC0);        // LED an PB0 ausschalten (low-aktiv)
12
    }
13
}

Solange die if-Bedingung erfüllt ist, wird die LED im 1/5 Sekunden Takt 
getoggled. Wenn nicht erfüllt, wird sie halt ausgeschaltet.

Die Endlosschleife hab ich drumrum gesetzt, damit hier überhaupt eine 
wiederkehrende Aktion ausgeführt werden kann.
#1568176
Lesenswert?

Die LED leuchtet ständig bei gedrückter Taste.
1
  if(!(PINB & 0x01))                // Wenn Taste PortB.0 auf HIGH
2
    {
3
      PORTC ^= (1 << PC0);        // LED an PC0 umschalten
4
      _delay_ms (200);
5
    }
6
PORTC = 0;

So gehts aber:
1
    if(!(PINB & 0x01))                // Wenn Taste PortB.0 auf HIGH
2
      {
3
        PORTC |= (1 << PC0);        // LED an PC0 umschalten
4
        _delay_ms (200);
5
        PORTC &= ~(1 << PC0);        // LED an PC0 umschalten
6
        _delay_ms (200);
7
      }
8
PORTC = 0;
#1568197
Lesenswert?

Manfred W. schrieb:
> Die LED leuchtet ständig bei gedrückter Taste.
>
1
>   if(!(PINB & 0x01))                // Wenn Taste PortB.0 auf HIGH
2
>     {
3
>       PORTC ^= (1 << PC0);        // LED an PC0 umschalten
4
>       _delay_ms (200);
5
>     }
6
> PORTC = 0;
7
>

Logisch.
Von Magnetus gabs ja auch noch ein Update, welches das Problem behebt.
Im Übrigen solltest du tatsächlich verstehen, warum es da überhaupt ein 
Problem gibt.

>
> So gehts aber:
>
>
1
>     if(!(PINB & 0x01))                // Wenn Taste PortB.0 auf HIGH
2
>       {
3
>         PORTC |= (1 << PC0);        // LED an PC0 umschalten
4
>         _delay_ms (200);
5
>         PORTC &= ~(1 << PC0);        // LED an PC0 umschalten
6
>         _delay_ms (200);
7
>       }
8
> PORTC = 0;
9
>

womit wir wieder am Anfang wären :-)
#1568229
Lesenswert?

Manfred W. schrieb:

> Ja, weil die Schleife nie verlassen wird bei gedrückter Taste.

Welche Schleife?
Da ist keine Schleife!

Ein 'if' ist eine bedingte Verzweigung aber keine Schleife.

ALso noch mal die Frage:
Warum 'blinkt' in diesem Beispiel die LED nicht bei gedrückter Taste?
1
  ...
2

3
  while( 1 ) {
4
    if(!(PINB & 0x01))                // Wenn Taste PortB.0 auf HIGH
5
    {
6
      PORTC ^= (1 << PC0);        // LED an PC0 umschalten
7
      _delay_ms (200);
8
    }
9
    PORTC = 0;
10
  }

arbeite das Programm mit dem Finger auf den Programmzeilen durch und 
spiele Computer.

(Tatsächlich blinkt die LED schon. Aber sie ist 200ms auf ein und ein 
paar µs auf aus. Zu kurz auf aus, als das man das sehen könnte. Mit 
einem Oszi würde man das allerdings detektieren können. Von daher ist 
die Aussage 'blinkt nicht' nicht zu halten. "Ergibt kein sichtbares 
blinken" würde die Sache eher beschreiben. Aber wir wollen jetzt keine 
Haare spalten)
#1568252
Lesenswert?

Manfred W. schrieb:
>
> Weil sich der Status von PortC nie ändert.

Wenn das tatsächlich deine Antwort ist (die vorher noch anders gelautet 
hat), dann kann ich nur sagen:
Such dir ein anderes Hobby. Du hast offenbar nicht das Zeug, das man 
benötigt um zu programmieren. Das ist nichts Schlechtes und auch nicht 
abwertend gemeint. Viele Leute haben nicht das Zeug dazu. Sie können es 
einfach nicht. Das ist so, wie manche Männer beim Bund beim Marschieren 
einfach nicht den Schritt halten können.
Deswegen ist man nicht dumm oder so etwas.
Programmieren ist ganz einfach nicht das, was dir liegt oder jemals 
liegen könnte. Du wirst es immer nur als Qual empfinden.
Gast #1569077
Lesenswert?

Nunja wenn man bestimmte Controller zugrunde legt, dann geht schon dass 
man Bits "togglen" kann egal welchen Zustand sie vorher hatten, aber 
welchen Zustand soll denn der Blinker bekommen wenn die Taste nicht 
länger gedrückt wird?

Bei neueren Atmels bewirkt ein Schreiben einer logischen 1 auf den "PIN" 
Port dass selbiger Ausgang den Zustand wechselt.

Nachdem hier nicht bekannt ist in welcher Umgebung sich das ganze 
abspielt bleibt wohl nur das konventionelle Setzen von 0/1.

Aber das alles steht ja schon in dem Artikel den Karlheinz in der 1. 
Antwort genannt hat.
Persönliche Seite #1572082
Lesenswert?

Kryptik schrieb:
1
int main(void)               // besser "void main(void)" (siehe unten)
2
{
3
  DDRC = 0xFF                // Hier fehlt ein Semikolon
4

5
  while(1)
6
  {
7
    if(PINB != 0xFF)
8
    {
9
      PORTC = 0;
10
      _delay_ms(255);        // Sowas macht man nicht mit Delay
11
      PORTX = 255;           // PORTX gibt es sicherlich nicht.
12
      _delay_ms(255);
13
    }
14
    PORTC = 0xFF;            // PORTC ist bereits 0xFF, also sinnlose Zeile
15
  }
16
return 0;                    // Main wird nie Verlassen also sinnlos.
17
}

Btw: Was für ein Prozessor?
#1572086
Lesenswert?

Christian H. schrieb:

> int main(void)               // besser "void main(void)" (siehe unten)
> {

nicht ganz.
int main ist schon richtig.
So ist das im C-Standard vorgeschrieben, und so sollte man das auch 
machen. Im C Standard gibt es ein paar erlaubte Formen für main(). Sie 
unterscheiden sich in den Argumenten. Gemeinsam ist ihnen aber allen, 
dass sie einen int retournieren.
Wenn in einem freestanding Environment der Returnwert keinen Sinn macht, 
dann weiß das der Compiler, der auch um die Sonderrolle von main weiß 
und baut sich das entsprechend zurecht.
Persönliche Seite #1572121
Lesenswert?

@Karl heinz Buchegger:

Klar, kann man beides machen.
In einem PC-Programm ist "int main(void)" aber auch nicht 100%ig 
korrekt. Es müsste "int main(int argv, char **argc)" heißen, obwohl 
viele Compiler auch was anderes annehmen.

Ich mache es aber trotzdem bei einem µP so, da damit erkennbar ist, dass 
main keine Rückgaben hat. Dass der Compiler auch die andere Variante 
versteht und dann alles unnötige Weboptimiert, ist löblich.

Das ist in diesem Fall aber nur Kosmetik. Ansonsten stimmt ich Dir zu.
#1572207
Lesenswert?

Christian H. schrieb:
> @Karl heinz Buchegger:
>
> Klar, kann man beides machen.

Nein.
Der springende Punkt ist:
man kann eben nicht.
Der Returnwert von main() ist immer int!

Wenn einzelne Compiler void main() akzeptieren, bedeutet das noch lange 
nicht, dass es deswegen korrekt ist.

> In einem PC-Programm ist "int main(void)" aber auch nicht 100%ig
> korrekt.

doch, ist es

> Es müsste "int main(int argv, char **argc)" heißen, obwohl
> viele Compiler auch was anderes annehmen.

Im C-Standard steht explizit, welche Formen von main() erlaubt sind.
Wenn du mir nicht glaubst, dann lies im Standard nach.
Diese, und nur diese, Formen von main sind richtig.
Anders als bei anderen Funktionen steht es dir als Programmierer nicht 
zu, dich darüber hinwegzusetzen. In einem freestanding Environment wirst 
du damit durchkommen, weil main im Regelfall nie retourniert. Hast du 
aber ein Runtimesystem, so schreibt dir dieses vor, wie es den Aufruf 
machen wird und es liegt nicht in deiner Macht dies zu ändern. Der 
Compiler kennt aber sowohl den Aufruf als auch die Argumentliste in 
deinem main und kann das anpassen.
Persönliche Seite #1572246
Lesenswert?

Karl heinz Buchegger schrieb:
> Im C-Standard steht explizit, welche Formen von main() erlaubt sind.

Kommt drauf an, welchen Standard du meinst. In C99, ist das korrekt 
(habe gerade nachgeschaut).
Ich kenne aber noch die älteren Standards (hatte mit K&R angefangen). In 
C90/C95 war "void main()", soweit ich auf die Schnelle sehen kann, noch 
in Ordnung (oder gar einfach "main()").

Einigen wir uns darauf, dass ich teilweise noch nach pre-C99 
programmiere.
Da ich zur Zeit C nur für µP nutze (und das auch nicht intensiv), ist 
mir das wohl noch nicht aufgefallen.
#1572257
Lesenswert?

Christian H. schrieb:

> Kommt drauf an, welchen Standard du meinst. In C99, ist das korrekt
> (habe gerade nachgeschaut).
> Ich kenne aber noch die älteren Standards (hatte mit K&R angefangen). In
> C90/C95 war "void main()", soweit ich auf die Schnelle sehen kann, noch
> in Ordnung (oder gar einfach "main()").

OK. Jetzt gehen wir in Haarspalterein, drum wird das auch mein letzter 
Beitrag zum Thema:
Nein, in keinem ISO Standard war void main() je erlaubt.
Zu K&R Zeiten gab es noch keinen Standard und es herrschte Wildwuchs. 
Dann kamen die Microsoft Compiler, die in ihren Dokubeispielen überall 
void main() benutzten. Von da an war void main() nicht mehr zu halten 
und verbreitete sich rasend schnell, obwohl es schon längst einen 
Standard gab.
Gast #1572280
Lesenswert?

Ich kenne aber noch die älteren Standards (hatte mit K&R angefangen). In
C90/C95 war "void main()", soweit ich auf die Schnelle sehen kann, noch
in Ordnung (oder gar einfach "main()").

war es nicht so das ein main() ebend kein void main() sondern ein int 
main() bedeutet hat?
Mir mar so ewas in erinnerung das jede variable( funktion ) ohne 
Datentyp als int angenommen wird (worden ist).
#1573627
Lesenswert?

Ich konnte das Problem inzwischen mit Hilfe von einigen Leuten hier so 
lösen:
1
  cntTicks++;
2
  if(cntTicks == nFireTime)                  // Ist Variable <nFireTime> mal 10ms
3
  {
4
    repeatFire ^= 0x01;                      // Wechselt PortC.0 nach Zeit von 0 auf 1
5
    cntTicks = 0;
6
  }
Das ganze läuft nun als Timer Interrupt und wird daher permanent 
getoggelt.

Mein problem zur Zeit ist jedoch immer noch, das ich nicht weiß wie ich 
das Togglen nur bei gedrückter Taste in zusammenhang mit meiner 
Portbeschaltung auslöse.

Wie ich schon in einem anderen Beitrag gepostet habe, wird anhand einer 
Tabelle ein Eingang einen bestimmten Ausgang zugeordnet:
1
#define NR_KONFIGS    9
2
#define NR_KEYS      6
3

4
uint8_t KonfigPattern[NR_KONFIGS][NR_KEYS] PROGMEM =
5
  {
6
    {LED0,LED1,LED2,LED3,LED4,LED5},          // Konfiguration 0
7
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 1
8
    {LED0,LED0,LED4,LED1,LED3,LED5},          // Konfiguration 2
9
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 3
10
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 4
11
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 5
12
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 6
13
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 7
14
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 8
15
   };

Aufgerufen wird das ganze dann per Tastendruck:
1
  while(1)
2
  {
3
    Summe = 0;
4

5
    if(!(KEY_PIN & 0x01))                  // Wenn Taste PortB.0 auf HIGH
6
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][0]);
7
    if(!(KEY_PIN & 0x02))                  // Wenn Taste PortB.1 auf HIGH
8
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][1]);
9
    if(!(KEY_PIN & 0x04))                  // Wenn Taste PortB.2 auf HIGH
10
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][2]);
11
    if(!(KEY_PIN & 0x08))                  // Wenn Taste PortB.3 auf HIGH
12
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][3]);
13
    if(!(KEY_PIN & 0x10))                  // Wenn Taste PortB.4 auf HIGH
14
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][4]);
15
    if(!(KEY_PIN & 0x20))                  // Wenn Taste PortB.5 auf HIGH
16
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][5]);
17

18
    if(nFire != 0)
19
    { 
20
      OUT_PORT = Summe | repeatFire;
21
    }
22
    else
23
    {
24
      OUT_PORT = Summe;
25
    }

In der momentanen Situation wird das Toggeln sofort ausgelöst sobald die 
Variable nFire auf 1 ist.
Was ich jedoch gerne hätte ist das der Zustand nur bei gedrückter Taste 
ausgelöst wird.

Leider komme ich da nicht ohne Hilfe weiter.
Vielleicht erbarmt sich ja jemand um Vorschläge, Tips, ...

danke!
#1573728
Lesenswert?

Karl heinz Buchegger schrieb:
> Dauerfeuer soll also dann stattfinden
>
>
>
>    wenn( ( nfire ungleich 0 ) UND ( Taste gedrückt ) )

Das "Taste gedrückt" ist das Problem.
Die wird oben schon abgefragt:
1
    if(!(KEY_PIN & 0x01))                  // Wenn Taste PortB.0 auf HIGH
2
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][0]);

Das können ja mehrere sein und vor allem auch gleichzeitig.
#1573746
Lesenswert?

Manfred W. schrieb:
> Karl heinz Buchegger schrieb:
>> Dauerfeuer soll also dann stattfinden
>>
>>
>>
>>    wenn( ( nfire ungleich 0 ) UND ( Taste gedrückt ) )
>
> Das "Taste gedrückt" ist das Problem.
> Die wird oben schon abgefragt:
>
>
1
>     if(!(KEY_PIN & 0x01))                  // Wenn Taste PortB.0 auf
2
> HIGH
3
>       Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][0]);
4
>
>
> Das können ja mehrere sein und vor allem auch gleichzeitig.

Schon.
Aber nur eine davon wird die Feuertaste sein.
Und die fragst du halt noch ein 2-tes mal ab.
#1573787
Lesenswert?

Manfred W. schrieb:
> Karl heinz Buchegger schrieb:
>> Aber nur eine davon wird die Feuertaste sein.
>>
>> Und die fragst du halt noch ein 2-tes mal ab.
>
> Im Prinzip ja, aber die kann je nach ausgewählter Konfiguration
> variieren.

Sogar dir hätte ich jetzt schon zugetraut, dass du eventuell auf die 
Idee kommen könntest, das man sich dann halt bei der jeweiligen 
Konfiguration einen Eintrag macht, der das beschreibt.
Schliesslich werden ja auch je nach Konfigration andere LEDs geschaltet


Es ist zum Haare raufen :-)
#1573824
Lesenswert?

Nicht ärgern...

In etwa so?
1
    if(!(KEY_PIN & 0x01))  &&  (nFire != 0)     // Wenn Taste PortB.0 auf HIGH und Dauerfeuer aktiv
2
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][0]) | repeatFire;
3
    if(!(KEY_PIN & 0x01))                  // Wenn Taste PortB.0 auf HIGH
4
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][0]);
Zwei Abfragen pro Taste?

Hab da eh schon herumprobiert.
#1573860
Lesenswert?

Nein, das geht ja auch nicht.
Wenn dann müßte es so heißen:
1
    if(!(KEY_PIN & 0x01))  &&  (nFire != 0)     // Wenn Taste PortB.0 auf HIGH und Dauerfeuer aktiv
2
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][0]) | repeatFire;
3
    if(!(KEY_PIN & 0x01))  &&  (nFire != 1)    // Wenn Taste PortB.0 auf HIGH und Dauerfeuer nicht aktiv
4
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][0]);
#1574165
Lesenswert?

kann man eine Definition mit einer Variable deklarieren die sich ständig 
ändert?

Denn dann würde ich das so machen:
1
#define LED0      repeatFire
2

3
uint8_t KonfigPattern[NR_KONFIGS][NR_KEYS] PROGMEM =
4
  {
5
    {LED0,LED1,LED2,LED3,LED4,LED5},            // Konfiguration 1
6
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 2
7
    {LED1,LED0,LED3,LED2,LED4,LED5},            // Konfiguration 3
8
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 4
9
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 5
10
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 6
11
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 7
12
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 8
13
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 9
14
   };
15

16
ISR(TIMER0_OVF_vect)
17
{
18
  cntTicks++;
19
  if(cntTicks >= nFireTime)                  // Ist Variable <nFireTime> mal 10ms
20
  {
21
    repeatFire ^= 0x01;                    // Wechselt PortC.0 nach Zeit von 0 auf 1
22
    cntTicks = 0;
23
  }
24
}

Dann würde bei Tastendruck der Ausgang PortC.0 auch blinken.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren