www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Lauflicht Problem mit 74hc595


Autor: Daniel S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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&....
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

int main (void)
{
   ioinit(); //Setup IO pins and defaults

   while(1)
   {
      // Output a knight rider pattern
      
      for (int i=35;i>=0;i--)
      {
         output_led_state(_BV(i));
         _delay_ms(50);
      }
      for (int i=1;i<35;i++)
      {
         output_led_state(_BV(i));
         _delay_ms(50);
      }
   }
}

void output_led_state(unsigned int __led_state)
{
   SH_CP_low();
   ST_CP_low();
   for (int i=0;i<36;i++)
   {
      if ((_BV(i) & __led_state) == _BV(i))  //bit_is_set doesn’t work on unsigned int so we do this instead
         DS_high();
      else   
         DS_low();
      

      SH_CP_high();
      SH_CP_low();
   }
   ST_CP_high();
}

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: blablub (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Daniel S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
#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
#define _BV64( bit ) ( 1ULL << (bit))
machen und das stattdessen benutzen.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Daniel S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Leute, ich hab jetzt mal den vorschlag mit dem _BV64 Makro umgesetzt.
Mein Code sieht jetzt so aus
#include <avr/io.h>
#include <util/delay.h>

#define DS_PORT    PORTC
#define DS_PIN     0
#define ST_CP_PORT PORTC
#define ST_CP_PIN  1
#define SH_CP_PORT PORTC
#define SH_CP_PIN  2
#define _BV64( bit ) ( 1ULL << (bit))

#define DS_low()  DS_PORT&=~_BV64(DS_PIN)
#define DS_high() DS_PORT|=_BV64(DS_PIN)
#define ST_CP_low()  ST_CP_PORT&=~_BV64(ST_CP_PIN)
#define ST_CP_high() ST_CP_PORT|=_BV64(ST_CP_PIN)
#define SH_CP_low()  SH_CP_PORT&=~_BV64(SH_CP_PIN)
#define SH_CP_high() SH_CP_PORT|=_BV64(SH_CP_PIN)

//Define functions
//===============================================
void ioinit(void);
void output_led_state(unsigned int __led_state);
//===============================================

int main (void)
{
   ioinit(); //Setup IO pins and defaults

   while(1)
   {
      // Output a knight rider pattern
      
      for (int i=35;i>=0;i--)
      {
         output_led_state(_BV64(i));
         _delay_ms(10);
      }
      for (int i=1;i<35;i++)
      {
         output_led_state(_BV64(i));
         _delay_ms(10);
      }
   }
}


void ioinit (void)
{
    DDRC  = 0b00000111; //1 = output, 0 = input
    PORTC = 0b00000000;
}

void output_led_state(unsigned int __led_state)
{
   SH_CP_low();
   ST_CP_low();
   for (int i=0;i<36;i++)
   {
      if ((_BV(i) & __led_state) == _BV64(i))  //bit_is_set doesn’t work on unsigned int so we do this instead
         DS_high();
      else   
         DS_low();
      

      SH_CP_high();
      SH_CP_low();
   }
   ST_CP_high();
}

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

Autor: Thorsten (Gast)
Datum:

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

Autor: Daniel S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hab den alten Code kopiert -.-
#include <avr/io.h>
#include <util/delay.h>

#define DS_PORT    PORTC
#define DS_PIN     0
#define ST_CP_PORT PORTC
#define ST_CP_PIN  1
#define SH_CP_PORT PORTC
#define SH_CP_PIN  2
#define _BV64( bit ) ( 1ULL << (bit))

#define DS_low()  DS_PORT&=~_BV64(DS_PIN)
#define DS_high() DS_PORT|=_BV64(DS_PIN)
#define ST_CP_low()  ST_CP_PORT&=~_BV64(ST_CP_PIN)
#define ST_CP_high() ST_CP_PORT|=_BV64(ST_CP_PIN)
#define SH_CP_low()  SH_CP_PORT&=~_BV64(SH_CP_PIN)
#define SH_CP_high() SH_CP_PORT|=_BV64(SH_CP_PIN)

//Define functions
//===============================================
void ioinit(void);
void output_led_state(unsigned long long int  __led_state);
//===============================================

int main (void)
{
   ioinit(); //Setup IO pins and defaults

   while(1)
   {
      // Output a knight rider pattern
      
      for (int i=35;i>=0;i--)
      {
         output_led_state(_BV64(i));
         _delay_ms(10);
      }
      for (int i=1;i<35;i++)
      {
         output_led_state(_BV64(i));
         _delay_ms(10);
      }
   }
}


void ioinit (void)
{
    DDRC  = 0b00000111; //1 = output, 0 = input
    PORTC = 0b00000000;
}

void output_led_state(unsigned long long int  __led_state)
{
   SH_CP_low();
   ST_CP_low();
   for (int i=0;i<36;i++)
   {
      if ((_BV(i) & __led_state) == _BV64(i))  //bit_is_set doesn’t work on unsigned int so we do this instead
         DS_high();
      else   
         DS_low();
      

      SH_CP_high();
      SH_CP_low();
   }
   ST_CP_high();
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.