Forum: Compiler & IDEs Bitfeld definition


von Tobias Tetzlaff (Gast)


Lesenswert?

Hallo,

ich versuche grade, eine "Kugel Uhr" mit einem ATmega8 und
4 Schieberegistern HC595 zu realisieren.

Im Moment lasse ich mir die Werte Dezimal auf 7Segmentanzeigen
ausgeben.

Nun kommt mein Problem.
Ich will die Zeit auf die Schieberegister ausgeben.
Nur soll die Zeit ja dort nicht binär erscheinen, sondern je höher die
Zahl, desto mehr Leds an.

Ich dachte, ich nehme für jedes HC595 ein Byte als Struckt definiert,
um die Bits einzeln setzen zu können.
Das sieht flgendermaßen aus:

struct {
    unsigned char led1:1;     // Bit 0
    unsigned char led2:1;     // Bit 1
    unsigned char led3:1;     // ...
    unsigned char led4:1;
    unsigned char led5:1;
    unsigned char led6:1;
    unsigned char led7:1;
    unsigned char led8:1;
} hc595_1;

Setzen der einzelnen Bits manuell (später beim Uhrzeit hochzählen):

  hc595_1.led1 = 1 ;
  hc595_1.led2 = 0 ;
  hc595_1.led3 = 0 ;
  hc595_1.led4 = 1 ;
  hc595_1.led5 = 0 ;
  hc595_1.led6 = 0 ;
  hc595_1.led7 = 0 ;
  hc595_1.led8 = 0 ;

Ausgabe an die HC's dann so
(es soll nun in die Hc's B10010000 eingeschoben werden):

SPDR = hc595_1;

Nur leider meckert der compiler:

error: incompatible types in assignment

Also ist das struckt nicht 8 Bit lang ?!
Ich dachte, das das Struckt, so wie oben, 8 Bit lang ist.

Wer kann mir weiterhelfen ?

Gibt es eine andere Möglichkeit die dezimalwerte an die HC' zu senden
?
Die Uhr läuft so:

0  0  0  0  // Leds Minuten 0-4, wenn 5 dann 5er Minuten +1
1  2  3  4  // Dezimalwert

0  0  0  0  0  0  0  0  0  0  0 // Leds 5er minuten, = 12 Stunden +1
5 10 15 20 25 30 35 40 45 50 55

0  0  0  0  0  0  0  0  0  0  0  0 // Leds Stunden, =13 dann 1
1  2  3  4  5  6  7  8  9  10 11 12

Ach, ich zähle jede Ziffer einzeln hoch, um die Werte einfacher an die
7Segment Anzeigen auszugeben :

Dort steht zb. für 03:27 Uhr
  03 : 05 : 02 > 3 Stunden und 25 Minuten und 3 Minuten

if(Zl_sekunde == 10)
{
  Zl_sekunde = 0;
  Zh_sekunde ++;
  if(Zh_sekunde == 6)
  {
  Zh_sekunde = 0;
  Zl_minute ++;
  }
        if(Zl_minute == 5)
  {
  Zl_minute = 0;
  Zl_minute5 ++;
  }
  if(Zl_minute5 == 10)
  {
  Zl_minute5 = 0;
  Zh_minute5 ++;
  }
  if(Zh_minute5 == 1 && Zl_minute5 == 2)
  {
  Zh_minute5 = 0;
  Zl_minute5 = 0;
  Zl_stunde ++;
  }
  if(Zl_stunde == 10)
  {
  Zl_stunde = 0;
  Zh_stunde ++;
  }
  if(Zh_stunde == 1 && Zl_stunde == 3)
  {
  Zh_stunde = 0
        Zl_stunde = 1;
  }
}

Über ein wenig Hilfe würd ich mich sehr freuen !!!

Gruß Toby

von Sebastian (Gast)


Lesenswert?

SPDR=
((hc595_1.led1)+(hc595_1.led2*2)+(hc595_1.led3*4)+(hc595_1.led4*8)+(hc59 
5_1.led5*16)+(hc595_1.led6*32)+(hc595_1.led7*64)+(hc595_1.led8*128));
   SPDR=
((hc595_1.led1<<0)|(hc595_1.led2<<1)|(hc595_1.led3<<2)|(hc595_1.led4<<3) 
|(hc595_1.led5<<4)|(hc595_1.led6<<5)|(hc595_1.led7<<6)|(hc595_1.led8<<7) 
);

von Sebastian (Gast)


Lesenswert?

eins on beiden... keine ahnung ob es einfacher geht

von Rufus T. Firefly (Gast)


Lesenswert?

So ginge es einfacher:

union {
  unsigned char Byte;
  struct {
    unsigned char led1:1;     // Bit 0
    unsigned char led2:1;     // Bit 1
    unsigned char led3:1;     // ...
    unsigned char led4:1;
    unsigned char led5:1;
    unsigned char led6:1;
    unsigned char led7:1;
    unsigned char led8:1;
  } Bitfeld;
} hc595_1;

Bit setzen:

hc595_1.Bitfeld.led1 = 1;

Byte beschreiben:

hc595_1.Byte = 0;


Man könnte sich natürlich auch mit den Bitoperationen von C
auseinandersetzen, dann wäre der ganze Aufriss nicht erforderlich.

von peter dannegger (Gast)


Lesenswert?

Also mit Bitfeldern gibt das einen ziemlichen Codewust.

Deshalb arbeiten C-Programmierer lieber mit Masken und seltener mit
Bitfeldern.

Du hast 4 + 11 + 12 = 27 LEDs, das kann man bequem in ein long (32 Bit)
packen und die 4 Bytes schiebt man dann raus.

// min = 0..59, hour = 1..12

unsigned long led_bits( unsigned char min, unsigned char hour )
{
  unsigned long ledbits = 0;
  unsigned long bitmask;
  unsigned char i;

  i = min % 5;
  for( bitmask = 1<<0; i--; bitmask += bitmask ) // bit 0..3
    ledbits += bitmask;

  min /= 5;
  for( bitmask = 1<<4; min--; bitmask += bitmask ) // bit 4..14
    ledbits += bitmask;

  for( bitmask = 1<<15; hour--; bitmask += bitmask ) // bit 15..26
    ledbits += bitmask;

  return ledbits;
}


Peter

von Tobias Tetzlaff (Gast)


Lesenswert?

Hallo Peter,

zuerst mal vielen Dank.
> gibt es etwas, was Du nicht weißt ? <

Peter :

Wie muß ich diese Funktion ( ist doch eine, nicht?) einfügen?
Ich hab schon einiges versucht, aber irgendwie geht das nicht.

Ich muß die Funktion doch auch irgendwie aufrufen, nicht?
beim aufruf meckertr der Compiler,
irgendetwas mit "too far Arguments"

Könntest Du mir evtl. mal beschreiben, wie ich am besten eine Uhr
höchzähle, ich denke so :

und diese dann
1. an die 6 /Segmentanzeigen sende
2. wie das mit deinem Tip gehen soll


uint_8 Sekunden;
uint_8 Minuten;
uint_8 Stunden;
uint_8 Temp_ziffer;

prog_char
Segmentfolge[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,} 
;

void
main(void)
{
 if(Sekunden > 59)
 {
 Sekunden = 0;
 Minuten ++;
 }
  if(Minuten > 59)
  {
  Minuten = 0;
  Stunden ++;
  }
   if(Stunden > 12)
   {
   Stunden = 0;
   }
}

//Timer0 Overflow für Multiplexen der 7Segmentanzeigen

SIGNAL(SIG_OVERFLOW0)
{
if(Temp_ziffer == 6)
  {
  Temp_ziffer = 0;
  }
  Temp_ziffer++;      // Zifferauswahl erhöhen

switch (Temp_ziffer)
  {             //welche Ziffer soll angesteuert werden
   case 1 :
  PORTC= 0x01;           //1. Ziffer
  PORTD = ~ PRG_RDB(Segmentfolge + Zl_minute);
  break;
   case 2 :
  PORTC= 0x02;           //2. Ziffer
  PORTD = ~ PRG_RDB(Segmentfolge + Zh_minute);
         break;
   case 3 :
  PORTC= 0x04;           //3. Ziffer
  PORTD = ~ PRG_RDB(Segmentfolge + Zl_minute5);
        break;
   case 4 :
  PORTC= 0x08;           //4. Ziffer
  PORTD = ~ PRG_RDB(Segmentfolge + Zh_minute5);
        break;
   case 5 :
  PORTC= 0x10;           //5. Ziffer
  PORTD = ~ PRG_RDB(Segmentfolge + Zl_stunde)
  break;
   case 6 :
  PORTC= 0x20;           //6. Ziffer
  PORTD = ~ PRG_RDB(Segmentfolge + Zh_stunde);

  // Nullstelle Stunde Zehner unterdrücken
  if (Zh_stunde == 0)
    {
    PORTD = ~ PRG_RDB(Segmentfolge + 11);
    }
  break;
  }
}

In der Interruptroutine steht allerdings noch einiges falsches,
da ich im Moment ja noch die Stellen einzeln hochzähle.
Das muß ja auch noch geändert werden, da ich ja die Minuten und Stunden
von 0 bis 59 zählen soll.

Wie ???

Gruß Toby

von Tobias Tetzlaff (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Nochmal,

ich habe es nun etwas hin bekommen.

Der Versuch macht schlau !!!

Anliegend meine bisherigen Programmier Künste.

Peter :

Mit den Minuten und 5er Minuten klappt einwandfrei! DANKE.

Nur sind bei Stunden == 0 alle LEDs aus, das ist ok.
Bei Stunde == 1 sind Bit 15 bis 31 an ?!
Bei Stunde == 2 geht Bit 16 aus.
Bei Stunde == 3 gehen Bit 16 und 17 aus.
...
Bei Stunde == 12 gehen Bit 16 bis 26 aus.
Bei Stunde == 13 ist Stunde == 0 und es sind wieder Bits 15 bis 31 an.

Da ich deine rechnung noch nicht so ganz verstehe, könntest du mir da
weiterhelfen?

Anliegend mein Code für WinAvr.

Gruß Toby

von Tobias Tetzlaff (Gast)


Lesenswert?

Hallo Nochmal.

Einen kleinen nachtrag :

Wenn ich Minuten statt 4 mal 5 mal schiebe, erhalte ich zwischen den
4Minuten Leds und den 11 5Minuten Leds eine Lücke von einer Led.

for( bitmask = 1<<4; minute--; bitmask += bitmask ) // bit 4..14
    ledbits += bitmask;

for( bitmask = 1<<5; minute--; bitmask += bitmask ) // bit 4..14
    ledbits += bitmask;

daher machte ich dies mal mit den Stunden:

Ich schiebe also 16 mal:
Die LEDs bleiben dunkel.

wenn ich nun aber nur 14 mal schiebe, zeigen die stunden korrekt an!
Allerdings überschneiden sich die Stunden dann mit der 11. 5er Minute.

for( bitmask = 1<<14; stunde--; bitmask += bitmask ) // bit 15..26
    ledbits += bitmask;

Muß man evtl. im Bezug auf die Stunden die Minuten mit bedenken?

Gruß Toby

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.