Forum: Mikrocontroller und Digitale Elektronik Lauflicht Problem mit 74hc595


von Daniel S. (Gast)


Lesenswert?

Hallo Leute,

ich hab nach dieser Seite ein Lauflicht mit 16 Leds gebaut 
http://www.protostack.com/forum/blog.php?u=2&b=35&c=1.
Funktioniert  alles soweit ganz gut. Aber nun möchte ich diese Schaltung 
auf 36 Leds erweitern. Dazu hab ich noch zusätzlich 3 74hc595er verbaut 
und verdrahtet wie zuvor.
Jedoch wenn ich jetzt die Funktionen
1
int main (void)
2
{
3
   ioinit(); //Setup IO pins and defaults
4
5
   while(1)
6
   {
7
      // Output a knight rider pattern
8
      
9
      for (int i=35;i>=0;i--)
10
      {
11
         output_led_state(_BV(i));
12
         _delay_ms(50);
13
      }
14
      for (int i=1;i<35;i++)
15
      {
16
         output_led_state(_BV(i));
17
         _delay_ms(50);
18
      }
19
   }
20
}
1
void output_led_state(unsigned int __led_state)
2
{
3
   SH_CP_low();
4
   ST_CP_low();
5
   for (int i=0;i<36;i++)
6
   {
7
      if ((_BV(i) & __led_state) == _BV(i))  //bit_is_set doesn’t work on unsigned int so we do this instead
8
         DS_high();
9
      else   
10
         DS_low();
11
      
12
13
      SH_CP_high();
14
      SH_CP_low();
15
   }
16
   ST_CP_high();
17
}

Auf jeweils 36 Leds geändert.
Jedoch bleibe jetzt alle Leds an und es tut sich gar nichts mehr.

Bitte erschlagt mich nicht wenn ich irgendwas rudimentäres übersehen 
habe!

Gruß Daniel

von Karl H. (kbuchegg)


Lesenswert?

ein unsigned int hat nur 16 Bit.

Du bräuchtest aber einen Integer, der mindestens 36 Bits umfasst, wenn 
du dein Schema beibehalten willst, das ein gesetztes Bit in einem 
Integer eine LED symbolisiert, die leuchten soll.

von blablub (Gast)


Lesenswert?

Darfst das Integer dafür nicht als Bitset nutzen. Du brauchst ja 2^36 
Kombinationen, also 36 bits. So einen Typen hast du nicht.

Nimm ein Array aus 5 8bit Typen, damit kannst du dann bis zu 40 LEDs 
ansteuern.

von Karl H. (kbuchegg)


Lesenswert?

blablub schrieb:
> Darfst das Integer dafür nicht als Bitset nutzen. Du brauchst ja 2^36
> Kombinationen, also 36 bits. So einen Typen hast du nicht.

Doch, hat er

Ein uint64_t kann das.

Nur sollte er dann vom _BV Makro Abschied nehmen.

> Nimm ein Array aus 5 8bit Typen, damit kannst du dann bis zu 40 LEDs
> ansteuern.

Das wird dann erst bei > 64 LED interessant.

von Daniel S. (Gast)


Lesenswert?

Danke für die Antworten!
Aber warum muss ich bei einem uint64_t  vom BV makro abschied nehmen?
Bzw. wie soll ich es anders lösen?

Gruß Daniel

von Karl H. (kbuchegg)


Lesenswert?

Daniel S. schrieb:
> Danke für die Antworten!
> Aber warum muss ich bei einem uint64_t  vom BV makro abschied nehmen?

weil _BV so implementiert ist
1
#define _BV(bit) (1 << (bit))

und damit wieder nur bis 16 Bit geht :-)

wenn man einen 16-Bit Einser um 20 stellen nach links schiebt, dann 
fällt das eine 1 Bit nach dem 16-mal Schieben links raus und alles wird 
zu 0.


> Bzw. wie soll ich es anders lösen?
Du könntest dir zb ein
1
#define _BV64( bit ) ( 1ULL << (bit))
machen und das stattdessen benutzen.

von Peter D. (peda)


Lesenswert?

Karl heinz Buchegger schrieb:
> Ein uint64_t kann das.

Aber nur, wenns nicht aufs Tempo ankommt und der Code 10-fach größer 
sein darf.

uint64_t ist sogar noch deutlich aufwendiger als float beim AVR-GCC. Es 
ist in C geschrieben, völlig ohne jede Optimierung.

Ein Array aus 5 Byte ist daher deutlich besser.


Peter

von Daniel S. (Gast)


Lesenswert?

Hi Leute, ich hab jetzt mal den vorschlag mit dem _BV64 Makro umgesetzt.
Mein Code sieht jetzt so aus
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
#define DS_PORT    PORTC
5
#define DS_PIN     0
6
#define ST_CP_PORT PORTC
7
#define ST_CP_PIN  1
8
#define SH_CP_PORT PORTC
9
#define SH_CP_PIN  2
10
#define _BV64( bit ) ( 1ULL << (bit))
11
12
#define DS_low()  DS_PORT&=~_BV64(DS_PIN)
13
#define DS_high() DS_PORT|=_BV64(DS_PIN)
14
#define ST_CP_low()  ST_CP_PORT&=~_BV64(ST_CP_PIN)
15
#define ST_CP_high() ST_CP_PORT|=_BV64(ST_CP_PIN)
16
#define SH_CP_low()  SH_CP_PORT&=~_BV64(SH_CP_PIN)
17
#define SH_CP_high() SH_CP_PORT|=_BV64(SH_CP_PIN)
18
19
//Define functions
20
//===============================================
21
void ioinit(void);
22
void output_led_state(unsigned int __led_state);
23
//===============================================
24
25
int main (void)
26
{
27
   ioinit(); //Setup IO pins and defaults
28
29
   while(1)
30
   {
31
      // Output a knight rider pattern
32
      
33
      for (int i=35;i>=0;i--)
34
      {
35
         output_led_state(_BV64(i));
36
         _delay_ms(10);
37
      }
38
      for (int i=1;i<35;i++)
39
      {
40
         output_led_state(_BV64(i));
41
         _delay_ms(10);
42
      }
43
   }
44
}
45
46
47
void ioinit (void)
48
{
49
    DDRC  = 0b00000111; //1 = output, 0 = input
50
    PORTC = 0b00000000;
51
}
52
53
void output_led_state(unsigned int __led_state)
54
{
55
   SH_CP_low();
56
   ST_CP_low();
57
   for (int i=0;i<36;i++)
58
   {
59
      if ((_BV(i) & __led_state) == _BV64(i))  //bit_is_set doesn’t work on unsigned int so we do this instead
60
         DS_high();
61
      else   
62
         DS_low();
63
      
64
65
      SH_CP_high();
66
      SH_CP_low();
67
   }
68
   ST_CP_high();
69
}

Mit 16 Leds funktioniert.... ab 16 streikt der Controller bzw. Code.
Hab ich da irgendwo noch was übersehen? Vll auch wieder einen Datentypen 
overflow? Mir fällt jetzt nach mehrmaligen genaueren hinschaun nichts 
auf?

Gruß´Daniel

von Thorsten (Gast)


Lesenswert?

der ganze Thread dreht sich um uint64_t, warum benutzt du es dann nicht?

von Daniel S. (Gast)


Lesenswert?

hab den alten Code kopiert -.-
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
#define DS_PORT    PORTC
5
#define DS_PIN     0
6
#define ST_CP_PORT PORTC
7
#define ST_CP_PIN  1
8
#define SH_CP_PORT PORTC
9
#define SH_CP_PIN  2
10
#define _BV64( bit ) ( 1ULL << (bit))
11
12
#define DS_low()  DS_PORT&=~_BV64(DS_PIN)
13
#define DS_high() DS_PORT|=_BV64(DS_PIN)
14
#define ST_CP_low()  ST_CP_PORT&=~_BV64(ST_CP_PIN)
15
#define ST_CP_high() ST_CP_PORT|=_BV64(ST_CP_PIN)
16
#define SH_CP_low()  SH_CP_PORT&=~_BV64(SH_CP_PIN)
17
#define SH_CP_high() SH_CP_PORT|=_BV64(SH_CP_PIN)
18
19
//Define functions
20
//===============================================
21
void ioinit(void);
22
void output_led_state(unsigned long long int  __led_state);
23
//===============================================
24
25
int main (void)
26
{
27
   ioinit(); //Setup IO pins and defaults
28
29
   while(1)
30
   {
31
      // Output a knight rider pattern
32
      
33
      for (int i=35;i>=0;i--)
34
      {
35
         output_led_state(_BV64(i));
36
         _delay_ms(10);
37
      }
38
      for (int i=1;i<35;i++)
39
      {
40
         output_led_state(_BV64(i));
41
         _delay_ms(10);
42
      }
43
   }
44
}
45
46
47
void ioinit (void)
48
{
49
    DDRC  = 0b00000111; //1 = output, 0 = input
50
    PORTC = 0b00000000;
51
}
52
53
void output_led_state(unsigned long long int  __led_state)
54
{
55
   SH_CP_low();
56
   ST_CP_low();
57
   for (int i=0;i<36;i++)
58
   {
59
      if ((_BV(i) & __led_state) == _BV64(i))  //bit_is_set doesn’t work on unsigned int so we do this instead
60
         DS_high();
61
      else   
62
         DS_low();
63
      
64
65
      SH_CP_high();
66
      SH_CP_low();
67
   }
68
   ST_CP_high();
69
}

von Karl H. (kbuchegg)


Lesenswert?

Daniel S. schrieb:
> hab den alten Code kopiert -.-

Ja.
Aber du hast zu hastig gearbeitet. Mehr Sorgfalt!
Du musst mehr oder weniger bei jeder Anweisung überlegen, ob ein int 
(also 16 Bit) dafür ausreicht.


> void ioinit(void);
> void output_led_state(unsigned long long int  __led_state);

tu dir selbst einen Gefallen und schreibt uint64_t und nicht unsigned 
long long.
Zum einen ist das kürzer zu schreiben zum einen kann dann ein Blinder 
aus 3 Meter Entfernung erkennen, dass du auf einen Dtaentyp mit 64 Bit 
aus bist.

>       for (int i=35;i>=0;i--)

Wenn du nett zu deinem µC sein möchtest, dann passe die Datentypen auf 
den Wertebereich an. Je kleiner desto besser.
Für einen int, der nur Werte von 0 bis 35 annehmen kann, tuns auch 8 
Bit. Das muss dann kein voll ausgewachsener int mit 16 Bit (auf einem 
AVR) sein.

        for (int8_t i = 35; i >= 0; i-- )


> void output_led_state(unsigned long long int  __led_state)
> {
...
>       if ((_BV(i) & __led_state) == _BV64(i))  //bit_is_set doesn’t work
> on unsigned int so we do this instead

Und das erste _BV kann dir keine Überläufe erzeugen, wenn i größer als 
15 ist?

Im Übrigen solltest du dir solche Abfragen gleich wieder abgewöhnen. Die 
Denkweise in C ist: Entweder etwas ist 0, dann ist es logisch FALSE. 
Oder es ist nicht 0, dann ist es logisch TRUE

     if( __led_stat & _BV64(i) )

macht genau das gleiche, ist aber einfacher zu schreiben und weniger 
fehleranfällig, weil du nicht aufpassen musst, was links vom == 
heruaskommt um die rechte Seite korrekt zu formulieren.

Und noch was:
Variablennamen lässt man nicht mit __ beginnen.
Alle Namen, die mit
         _ und einem Grossbuchstaben
  oder   __
sind nämlich für den Compiler und dessen System-Header Files reserviert.

Für dich als Anwendungsprogrammierer bleiben da noch genug andere 
Möglichkeiten übrig, dir Schemata für Variablennamen auszudenken. Es 
muss nicht wirklich ein Beginn mit __ sein.

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.