Problem bei einfachen Lauflicht :-(

#2785028
Lesenswert?

Hallo,

ich habe bis gestern gedacht, ich kann mal schnell nebenbei ein 
Lauflicht programmieren. Doch leider wurde mir nach längerer Fehlersuche 
eines besseren belehrt.

Das Licht sollte einfach nur nach rechts laufen. Das tut es auch mehr 
oder weniger, aber jeden LED blinkt nur kurz auf statt für 1sec zu 
leuchten. Das lustige an der Sach ist aber wenn ich über ledra oder 
ledla alle LEDs blinken lasse bzw. aktivieren Funktioniert es.
Kann mir bitte jemand helfen? Ich finden den Fehler leider nicht.

AVR Atmega8
Internen Quarz
AVR Studio 6
LEDS über BC639 an:
PB6
PB7
PD5
PD6
PD7
PB0

das wäre der Sourcecode:
------------------------------------------------------------------------ 
---
#include <avr/io.h>
#include <util/delay.h>
#define F_CPU 1000000

unsigned char ledl1 = 0;
unsigned char ledl2 = 0;
unsigned char ledl3 = 0;
unsigned char ledr1 = 0;
unsigned char ledr2 = 0;
unsigned char ledr3 = 0;
unsigned char ledla = 0;
unsigned char ledra = 0;



void ausgabe(void)
{
  if (ledl1 == 1)
  {
    PORTB = PORTB | (1<<PD0);
  }
  else
  {
    PORTB = PORTB &~ (1<<PB0);
  }

  if (ledl2 == 1)
  {
    PORTD = PORTD | (1<<PD7);
  }
  else
  {
    PORTD = PORTD &~ (1<<PD7);
  }


  if (ledl3 == 1)
  {
    PORTD = PORTD | (1<<PD6);
  }
  else
  {
    PORTD = PORTD &~ (1<<PD6);
  }

  if (ledr1 == 1)
  {
    PORTD = PORTD | (1<<PD5);
  }
  else
  {
    PORTD= PORTD &~ (1<<PD5);
  }
  if (ledr2 == 1)
  {
    PORTB = PORTB | (1<<PB7);
  }
  else
  {
    PORTB = PORTB &~ (1<<PB7);
  }

  if (ledr3 == 1)
  {
    PORTB = PORTB | (1<<PB6);
  }
  else
  {
    PORTB = PORTB &~ (1<<PB6);
  }

  if (ledla == 1)
  {
    PORTB = PORTB | (1<<PB0);
    PORTD = PORTD | (1<<PD7);
    PORTD = PORTD | (1<<PD6);
  }
  else
  {
    PORTB = PORTB &~ (1<<PB0);
    PORTD = PORTD &~ (1<<PD7);
    PORTD = PORTD &~ (1<<PD6);
  }

  if (ledra == 1)
  {
    PORTD = PORTD | (1<<PD5);
    PORTB = PORTB | (1<<PB7);
    PORTB = PORTB | (1<<PB6);
  }
  else
  {
    PORTD = PORTD &~ (1<<PD5);
    PORTB = PORTB &~ (1<<PB7);
    PORTB = PORTB &~ (1<<PB6);
  }

}

int main(void)
{


DDRB = DDRB | (1<<PB0)| (1<<PB6)| (1<<PB7); // Ausgänge
DDRD = DDRD | (1<<PD5)| (1<<PD6)| (1<<PD7); // Ausgänge
PORTD = 0x1F; //Pullups für Eingänge aktiviren



    while(1 == 1)
 {
  ledl1=0;
  ledl2=0;
  ledl3=0;
  ledr1=0;
  ledr2=0;
  ledr3=0;
  ausgabe();
  _delay_ms(1000);

  ledl1=0;
  ledl2=1;
  ledl3=0;
  ledr1=0;
  ledr2=0;
  ledr3=0;
  ausgabe();
  _delay_ms(1000);

  ledl1=0;
  ledl2=0;
  ledl3=1;
  ledr1=0;
  ledr2=0;
  ledr3=0;
  ausgabe();
  _delay_ms(1000);

  ledl1=0;
  ledl2=0;
  ledl3=0;
  ledr1=1;
  ledr2=0;
  ledr3=0;
  ausgabe();
  _delay_ms(1000);


  ledl1=0;
  ledl2=0;
  ledl3=0;
  ledr1=0;
  ledr2=1;
  ledr3=0;
  ausgabe();
  _delay_ms(1000);

  ledl1=0;
  ledl2=0;
  ledl3=0;
  ledr1=0;
  ledr2=0;
  ledr3=1;
  ausgabe();
  _delay_ms(1000);
    }
}
------------------------------------------------------------------------ 
--
Besten Dank!

PS: Ich würde fast darauf wetten, dass es ein peinlicher Fehler ist :-)
Gast #2785096
Lesenswert?

Dämlichster (Troll-)Fehler wo gibt!!!

Bei ausgabe() schaltest Du deine Wunsch-Led ein und unten bei der 
letzten if-clause setzt Du beide Ports wieder auf aus. Ausnahme: Es 
werden alle LEDs ein- oder ausgeschaltet.

Ab in die Ecke und schämen!!!
#2786274
Lesenswert?

Klar kenn ich die shift-operatoren. Wenn man sich den Code an sieht, 
dann sieht man auch, dass ich ihn zum setzten der Ausgänge nehme :-)
Er ist aber wegen Zusatzfunktionen (nicht online) leider ungeeignet.
Und wenn die Hardware schon fertig ist, kann man nicht einfach 
irgendwelche Pins tauschen :-)

Aber ich hatte recht, es war ein sehr peinlicher und einfacher Fehler. 
X+2 Augen sind halt immer besser als nur zwei :-)

Danke für den Hinweis
#2786450
Lesenswert?

Du könntest doch wenigstens die ganzen (unsigned char) durch eine 
einzige ersetzen, bei der jedes Bit für eine LED steht. Dann brauchst Du 
im Hauptprogramm auch nicht (gefühlte) 500 Schreibzugriffe, sondern nur:
1
unsigned char value;
2
while (1) {
3
  value=0b000001;
4
  do {
5
    ausgabe();
6
    _delay_ms(1000);
7
    value=value<<1;
8
  }
9
  while (value<=0b100000);
10
}

Nur so als Denkanstoß. Wie die ausgabe() Funktion umgeschrieben werden 
muss, kannst Du Dir sicher selbst denken.
#2787932
Lesenswert?

R. Schmidt schrieb:

> Und wenn die Hardware schon fertig ist, kann man nicht einfach
> irgendwelche Pins tauschen :-)

Das ist richtig.
Aber man kann sich zb in einem, nein 2, Arrays die jeweils an den ports 
auszugebenden Werte ablegen und dann ganz einfach in ausgabe() in die 
Arrays indizieren um den Wert zu erfahren, der ausgegeben werden soll.
Dann spart man sich einen Großteil dieser if - else kette
Gast #2791037
Lesenswert?

Ich bin zwar auch Anfänger, aber da musste auch ich schlucken. 
Kompliziert.
Wie es der Zufall so will, habe ich vor 2 Tagen auch ein Lauflicht 
gemacht.
Mein Code ist extrem simpel da er erstmal zum testen war, man kann noch 
etwas optimieren.
Das ganze läuft auf einem Attiny 44 mit internem Takt. Das einzigste was 
Du tun musste ist die Pinausgänge festlegen und Pinnamen entsprechend 
Deines Avr ändern.

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
  DDRA = (1 << PA0) | (1 << PA1) | (1 << PA2) | (1 << PA3) | (1 << PA5) 
| (1 << PA7);
  DDRB = (1 << PB0) | (1 << PB1) | (1 << PB2);

    while(1)
    {
    PORTA |= (1 << PA0); _delay_ms(70);
  PORTA &= ~((1 << PA0));
  PORTA |= (1 << PA1); _delay_ms(70);
  PORTA &= ~((1 << PA1));
  PORTA |= (1 << PA2); _delay_ms(70);
  PORTA &= ~((1 << PA2));
  PORTA |= (1 << PA3); _delay_ms(70);
  PORTA &= ~((1 << PA3));
  PORTB |= (1 << PB0); _delay_ms(70);
  PORTB &= ~((1 << PB0));
  PORTB |= (1 << PB1); _delay_ms(70);
  PORTB &= ~((1 << PB1));
  PORTB |= (1 << PB2); _delay_ms(70);
  PORTB &= ~((1 << PB2));
  PORTA |= (1 << PA7); _delay_ms(70);
  PORTA &= ~((1 << PA7));
  PORTA |= (1 << PA5); _delay_ms(70);
  PORTA &= ~((1 << PA5));

  PORTA |= (1 << PA7); _delay_ms(70);
  PORTA &= ~((1 << PA7));
  PORTB |= (1 << PB2); _delay_ms(70);
  PORTB &= ~((1 << PB2));
  PORTB |= (1 << PB1); _delay_ms(70);
  PORTB &= ~((1 << PB1));
  PORTB |= (1 << PB0); _delay_ms(70);
  PORTB &= ~((1 << PB0));
  PORTA |= (1 << PA3); _delay_ms(70);
  PORTA &= ~((1 << PA3));
  PORTA |= (1 << PA2); _delay_ms(70);
  PORTA &= ~((1 << PA2));
  PORTA |= (1 << PA1); _delay_ms(70);
  PORTA &= ~((1 << PA1));

}
}

Also wie man sieht geht es auch extrem einfach.
Gruß
Fred
Gast #2791047
Lesenswert?

Fred schrieb:
> Also wie man sieht geht es auch extrem einfach.
Genau:
1
#include <avr/io.h>
2
#include <util/delay.h>
3

4
int main(void)
5
{
6
  DDRA = 0xFF;
7
  uint16_t i;
8
  for(;;)
9
  {
10
    for(i=1;i!=(1<<8);i<<=1)
11
    {
12
      PORTA=(uint8_t)i;
13
      _delay_ms(70);
14
    }
15
  }
16
  return 0; //neaver reached
17
}

SCNR

Wie wäre es mit einem Wettbewerb: Wer schreibt das kürzeste Lauflicht?
Gast #2791054
Lesenswert?

Das ist mir klar, daß ich das ganze in einer schleife machen kann.
Ich wollte halt nur zeigen, daß seines schon extrem umständlich ist.
Auch wenn Deines schön klein ist, so finde ich es absolut 
unübersichtlich.
Zum lernen finde ich die Portnamen etc. besser.
Gast #2791056
Lesenswert?

troll schrieb:
> Wie wäre es mit einem Wettbewerb: Wer schreibt das kürzeste Lauflicht?
Ich leg dann mal vor:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
main(){DDRA=~0;char i;for(;;)for(i=0,PORTA=1;i<8;i++,PORTA<<=1,_delay_ms(70));}
Kann sein dass man noch unsigned vor den char setzen muss, hab gerade 
keinen AVR-GCC zur Hand. Mal sehen, vielleicht schlage ich Karl-Heinz ja 
dieses Mal...
Gast #2791065
Lesenswert?

Fred schrieb:
> Ich sehe schon, wie in so manchen anderen Threads wird hier alles ins
> lächerliche gezogen.
> Vielleicht sollte man mal über die Gastfunktion nachdenken.

Ich ziehe überhaupt nichts ins Lächerliche... Sei nicht so humorlos, 
kurze (und unübersichtliche) Programme in C haben eine lange Tradition. 
Siehe auch IOCC. :-)
#2791141
Lesenswert?

Die Ausgabefunktion kann man auch drastisch vereinfachen.
Und Parameterübergabe macht man nicht in globalen Variablen, sondern 
direkt:
1
#include <avr/io.h>
2
#define F_CPU   1e6
3
#include <util/delay.h>
4

5
#define LEDL1B  (1<<PB0)
6
#define LEDL2D  (1<<PD7)
7
#define LEDL3D  (1<<PD0)
8
#define LEDR1D  (1<<PD5)
9
#define LEDR2B  (1<<PB7)
10
#define LEDR3B  (1<<PB6)
11

12
void ausgabe( uint8_t val )
13
{
14
  uint8_t vald = PORTD & ~(LEDL1B | LEDR2B | LEDR3B);
15
  uint8_t valb = PORTB & ~(LEDL2D | LEDL3D | LEDR1D);
16
  if( val & 1<<0 )
17
    valb |= LEDL1B;
18
  if( val & 1<<1 )
19
    vald |= LEDL2D;
20
  if( val & 1<<2 )
21
    vald |= LEDL3D;
22
  if( val & 1<<3 )
23
    vald |= LEDR1D;
24
  if( val & 1<<4 )
25
    valb |= LEDR2B;
26
  if( val & 1<<5 )
27
    valb |= LEDR3B;
28
  PORTD = vald;
29
  PORTB = valb;
30
}
31

32
int main()
33
{
34
  DDRB = LEDL1B | LEDR2B | LEDR3B;
35
  DDRD = LEDL2D | LEDL3D | LEDR1D;
36
  
37
  for(;;){
38
    uint8_t val = 1;
39
      ausgabe( 0 );
40
    do{
41
      _delay_ms(1000);
42
      ausgabe( val );
43
      val <<= 1;
44
    }while( val != 0b1000000 );
45
  }
46
}

Peter

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