Forum: Compiler & IDEs 12 bit Wert in Array aus uint8_t speichern


von Julian W. (julian-w) Benutzerseite


Lesenswert?

Hallo,
ich versuche PWM Werte für den TLC5940 in ein Array aus uint8_t zu 
schreiben (damit ich sie später einfach über die SPI ausgeben kann)

Hier mein Code:
1
void SetLED(uint8_t led, uint16_t value)
2
{
3
    if(led | 0b11111110 == 0)
4
    {
5
        // Blöcke 0, 2, 4, 6, ...
6
        pwm_data_raw[led] = (uint8_t)(value >> 4);
7
        pwm_data_raw[led + 1] = ???
8
    }
9
    else
10
    {
11
        // Blöcke 1, 3, 5, 7, ...
12
        pwm_data_raw[led - 1] = (uint8_t)(value << 4);
13
        pwm_data_raw[led] = (uint8_t)(value >> 4);
14
    }
15
}

Nur leider funktioniert... nichts :(
In der ersten IF-Abfrage will ich halt einfach teste, ob es gerade oder 
nicht gerade ist... das dürfte ja stimmen.

Ist der Block ungerade, kommen die 8 oberen Bits (also die von 12-4) in 
das erste Array-Glied und die unteren 4 Bit in die oberen 4 Bit des 
zweiten Array-Gliedes.
Bei geraden halt genau umgekehrt ;)

Evtl. könnt ihr mir ja helfen. Hier eine Grafik des Aufbau's des 
Array's. Die Zahl gibt den LED Kanal an:

00000000 00001111 11111111 22222222 22223333 33333333 44444444 44445555

Wäre nett, wenn mir einer da helfen könnte :D

Liebe Grüße

Julian

von Krapao (Gast)


Lesenswert?

> led | 0b11111110 == 0

Meldet der Compiler bei diesem Ausdruck nix? Ich meine, schau dir mal 
die wahrheitstabelle für egal welchen Wert von led an...

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Jap, folgende Warnung:

warning: suggest parentheses around comparison in operand of ||

Aber tut mir Leid, ich bin eigentlich recht fit in C... nur dieses 
Bitgeschiebe... das is einfach... ich versteh das einfach nicht und 
versuche es auch immer zu vermeinde... nur hier geht es einfach nicht :/

von STK500-Besitzer (Gast)


Lesenswert?

Julian W. schrieb:
> Aber tut mir Leid, ich bin eigentlich recht fit in C... nur dieses
> Bitgeschiebe... das is einfach... ich versteh das einfach nicht und
> versuche es auch immer zu vermeinde... nur hier geht es einfach nicht :

Guck mal nach Bitmanipulation

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Hab ich schon... aber wie mach ich z.B. folgendes:

00001111 11112222

Diese 8 "Einsen" auslesen und in ein uint8_t kopieren?
Und die 2er dann in die oberen Bits eines anderen uint8_t kopieren?

also das aus

00001111 11112222
=>
11111111 2222XXXX (X = alte Bits)

und dann noch einmal "verdreht"

00001111 22222222
=>
XXXX1111 22222222 (Y = alte Bits)


Die if-Abfrage könnte ich evtl. noch durch % ersetzen, aber die Routiner 
wird halt seeeeehr oft aufgerufen, daher dachte ich, dass das so evtl. 
schneller geht.

von Falk B. (falk)


Lesenswert?

@  Julian W. (julian-w) Benutzerseite

>wird halt seeeeehr oft aufgerufen, daher dachte ich, dass das so evtl.
>schneller geht.

Nuu gloor. Geene Fettbemm fressen, Glotzn off und arweidn!

http://www.mikrocontroller.net/articles/Bitmanipulation#Siehe_auch

MFG
Falk

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Aber soweit ich das sehe werden dort doch nur 8 bit genutzt, oder?
Ich würde aber gerne schon die vollen 12 bit nutzen ;)

Beitrag "Re: AtMega 48 Timmer"

Aber ich glaube ich habe mein if-Problem lösen können mit:
1
if(led & 0b00000001)

immerhin ein Anfang^^

von STK500-Besitzer (Gast)


Lesenswert?

1
// Blöcke 1, 3, 5, 7, ...

Du hast für jedes Bit eine If-Abfrage?
Schon mal was von Schleifen gehört?

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Nein, ich muss ja die 12bit-Werte in 8bit-Blöcke (also ein Byte) 
einsortieren. Und da unterscheide ich quasi zwei Fälle^^


bei geraden "Block-Nummern", also 0, 2, 4, 6, ...

00001111 11112222 (12 bit PWM-Wert in uint16_t)
=>
11111111 2222XXXX (X = alte Bits)
BLOCK    BLOCK+1


bei ungeraden "Block-Nummern", also 1, 3, 5, 7, ...

00001111 22222222 (12 bit PWM-Wert in uint16_t)
=>
XXXX1111 22222222 (X = alte Bits)
BLOCK    BLOCK+1


Das ganze ist halt für ein TLC5940, der eine 12bit PWM zur Verfügung 
stellt und dem ich die Daten über SPI, also jeweils 8bit weise, zur 
Verfügung stelle.

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Mist, ich merke gerade dass das ja auch Blödsinn ist... mmhhhh... ich 
muss morgen mir nochmal neu den Kopf darüber zerbrechen...

was ich brauche:
16x 12bit Werte, die jeweils in einem uint16_t gespeichert sind, direkt 
aneinander in einem Array aus 24 Elementen des Typs uint8_t.

von Rolf Magnus (Gast)


Lesenswert?

Julian W. schrieb:
> Nein, ich muss ja die 12bit-Werte in 8bit-Blöcke (also ein Byte)
> einsortieren. Und da unterscheide ich quasi zwei Fälle^^

Das paßt auch. Du kannst immer zwei 12-Bit-Werte in 3 Bytes stecken, 
danach wiederholt sich das Schema.

> bei geraden "Block-Nummern", also 0, 2, 4, 6, ...
>
> 00001111 11112222 (12 bit PWM-Wert in uint16_t)
> =>
> 11111111 2222XXXX (X = alte Bits)
> BLOCK    BLOCK+1
>
>
> bei ungeraden "Block-Nummern", also 1, 3, 5, 7, ...
>
> 00001111 22222222 (12 bit PWM-Wert in uint16_t)
> =>
> XXXX1111 22222222 (X = alte Bits)
> BLOCK    BLOCK+1

Sieht erstmal nicht so schlecht aus. Du darfst halt nur deine Xe nicht 
überschreiben, sondern, wie du schon erwähnst, die alten Bits 
beibehalten. Und du must BLOCK richtig ausrechnen, denn zwei Werte 
brauchen ja nicht zwei, sondern drei Blöcke. Du mußt also deine 
LED-Nummer * 3 / 2 nehmen, um die richtige Blocknummer zu bekommen:
1
LED0 -> Block 0 und 1
2
LED1 -> Block 1 und 2
3
LED2 -> Block 3 und 4
4
LED3 -> Block 4 und 5
5
...

von Falk B. (falk)


Lesenswert?

@  Julian W. (julian-w) Benutzerseite

>Aber soweit ich das sehe werden dort doch nur 8 bit genutzt, oder?
>Ich würde aber gerne schon die vollen 12 bit nutzen ;)

Dann bist du kurzsichtig.

Drei Beiträge im Thread tiefer . . .

Beitrag "Re: AtMega 48 Timmer"

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Mein Ziel ist es halt, die Werte immer in uint8_t zu haben, da ich die 
Werte sehr viel öfters senden wie bearbeiten muss. Daher denke ich ist 
es effizenter, einfach immer nur das fertige Array zu senden anstatt die 
zu sendenen Daten jedesmal neu zu "berechnen".

Hier mal was in C#, was funktionieren sollte:
1
int pwm1 = 175;
2
int pwm2 = 10;
3
                        
4
byte[] dat = new byte[3];
5
            
6
dat[0] = (byte)(pwm1 >> 4);
7
dat[1] |= (byte)(pwm1 << 4);
8
9
dat[1] |= (byte)(pwm2 >> 8);
10
dat[2] = (byte)(pwm2);
11
12
label1.Text = Convert.ToString(dat[0], 2).PadLeft(8, '0') + " - " + Convert.ToString(dat[1], 2).PadLeft(8, '0') + " - " + Convert.ToString(dat[2], 2).PadLeft(8, '0');

Wenn ich zu Hause bin werde ich dies mal testen, sollte aber wohl 
funktionieren ;)

Aber schonmal Danke für eure Hilfe :D

von Karl H. (kbuchegg)


Lesenswert?

Julian W. schrieb:
> Mein Ziel ist es halt, die Werte immer in uint8_t zu haben, da ich die
> Werte sehr viel öfters senden wie bearbeiten muss. Daher denke ich ist
> es effizenter, einfach immer nur das fertige Array zu senden anstatt die
> zu sendenen Daten jedesmal neu zu "berechnen".

Das ist ja auch ok

> Hier mal was in C#, was funktionieren sollte:

Nope.
Es gibt einen ganz einfachen Grund warum das nicht funktionieren KANN.

Mit einem Oder (|) kannst du immer nur Bits von 0 auf 1 ziehen. Um ein 
1-Bit wieder auf 0 zu ziehen, brauchst du ein Und (&). Ich seh aber 
keines in deinem Code, daher kann der schon mal im allgemeinen Fall dort 
nicht stimmen, wo sich 2 Werte 1 Byte teilen müssen und du daher nicht 
mit einer Zuweisung arbeiten kannst.

Aber abgesehen davon siehts nicht schlecht aus. Jetzt noch daraus eine 
Funnktion machen, die aus der LED Nummer den ersten der beiden Array 
Indizes bestimmt und welches der beiden Verfahren zur Bitmanipulation 
anzuwenden ist und du hast es.

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Stimmt... ich bin bei dieser einfachen "Simulation" einfach davon 
ausgegangen, das vorher alles 0 ist.... Nur irgendwie klappt es mit & 
gar nicht...

Könntest du mir nicht schnell weiterhelfen ;)

von Karl H. (kbuchegg)


Lesenswert?

Was klappt denn nicht?

Du brauchst doch nur die 4 Bits, die du beschreiben willst vorher alle 
miteinander gezielt auf 0 setzen, ehe du dann mit dem Oder einzelne 
davon wieder auf 1 ziehst.

Bitmanipulationen

Sorry. Aber da musst du durch. Mit Und und Oder zu arbeiten um Bits in 
einem Byte zu manipulieren, ist das kleine EinmalEins der 
µC-Programmierung.

In beiden Fällen bearbeitet man ein Byte mit einer 'Maske'.

Bei einem Oder hat man im Ergebnis genau dort auf jeden Fall ein 1 Bit, 
wo
in der Maske ebenfalls ein 1 Bit war.
Bei einem Und hat man im Ergebnis genau dort auf jeden Fall ein 0 Bit, 
wo in der Maske ebenfalls ein 0 Bit war.

Oft ist die Maske konstant und fix, bei dir ist das ein Bitmuster, das 
dir jemand vorgegeben hat.

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Achso, quasi als zusätzlicher Schritt... Ich wollte irgendwie das ODER 
durch ein UND ersetzten... und das ging schief^^

Hier mein Code... in C# funktioniert er :D
1
int pwm1 = 175;
2
int pwm2 = 10;
3
                        
4
byte[] dat = new byte[3];
5
            
6
dat[0] = (byte)(pwm1 >> 4);
7
dat[1] &= (byte)15; // 00001111
8
dat[1] |= (byte)(pwm1 << 4);
9
10
dat[1] &= (byte)240; // 11110000
11
dat[1] |= (byte)(pwm2 >> 8);
12
dat[2] = (byte)(pwm2);

von Karl H. (kbuchegg)


Lesenswert?

OK

In C schreibst du das
1
dat[1] &= (byte)15; // 00001111
dann aber als Hex-Zahl
1
  dat[1] &= 0x0F;

von Karl H. (kbuchegg)


Lesenswert?

Julian W. schrieb:
> Achso, quasi als zusätzlicher Schritt... Ich wollte irgendwie das ODER
> durch ein UND ersetzten... und das ging schief^^
>
> Hier mein Code... in C# funktioniert er :D

OK.

Jetzt willst du noch ein

 byte[] dat = new byte[20];

und eine Funktion, die die n-te LED auf einen Wert setzt.
Wie muss die Funktion aussehen?
Zum Test: die 4. Led setzen lassen, die 5. Led setzen lassen

von Julian W. (julian-w) Benutzerseite


Lesenswert?

So, in C# geht es... dürfte ja die Portierung auf C kein Problem mehr 
sein :D
1
private byte[] pwm_raw_data = new byte[24];
2
private void SetLED(byte led, int pwm)
3
{
4
    int adr;
5
6
    if(led == 0)
7
    {
8
        adr = 0
9
    }
10
    else
11
    {
12
       adr = (led * 3) / 2;
13
    }
14
15
    if ((led & (byte)0x01) == 1)
16
    {
17
        // Blöcke 0, 2, 4, ...
18
        pwm_raw_data[adr] = (byte)(pwm >> 4);
19
        pwm_raw_data[adr + 1] &= (byte)15; // 00001111
20
        pwm_raw_data[adr + 1] |= (byte)(pwm << 4);
21
    }
22
    else
23
    {
24
        // Blöcke 1, 3, 5, ...
25
        pwm_raw_data[adr] &= (byte)240; // 00001111
26
        pwm_raw_data[adr] |= (byte)(pwm >> 2);               
27
        pwm_raw_data[adr + 1] = (byte)(pwm);
28
    }
29
}

von Julian W. (julian-w) Benutzerseite


Lesenswert?

OK, ich kriege es immer noch nicht auf dem Atmega zum laufen :/

Kann mir einer weiterhelfen?
1
void SetLED(uint8_t led, uint16_t value)
2
{
3
    uint8_t adr;
4
5
    if (led%2 == 0 ||led == 0)
6
    {
7
        // Blöcke 0, 2, 4, ...
8
        adr = (led * 3) / 2;
9
        pwm_data_raw[adr] = (uint8_t)(value >> 4);
10
        pwm_data_raw[adr + 1] &= (uint8_t)15; // 00001111
11
        pwm_data_raw[adr + 1] |= (uint8_t)(value << 4);
12
    }
13
    else
14
    {
15
        // Blöcke 1, 3, 5, ...
16
        led++;
17
        adr = (led * 3) / 2;
18
        pwm_data_raw[adr] &= (uint8_t)240; // 11110000
19
        pwm_data_raw[adr] |= (uint8_t)(value >> 8);
20
        pwm_data_raw[adr + 1] = (uint8_t)(value);
21
    }
22
}

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Yeah :D

Ich glaub ich hab des Rätsel's-Lösung:
1
void SetLED(uint8_t led, uint16_t value)
2
{
3
    uint8_t adr;
4
5
    if (led%2 == 0 ||led == 0)
6
    {
7
        // Blöcke 0, 2, 4, ...
8
        adr = (led * 3) / 2 + 1;
9
        pwm_data_raw[adr - 1] = (uint8_t)(value >> 4);
10
        pwm_data_raw[adr] &= 0b00001111;
11
        pwm_data_raw[adr] |= (uint8_t)(value << 4);
12
    }
13
    else
14
    {
15
        // Blöcke 1, 3, 5, ...
16
        led++;
17
        adr = (led * 3) / 2 - 2;
18
        pwm_data_raw[adr] &= 0b11110000;
19
        pwm_data_raw[adr] |= (uint8_t)(value >> 8);
20
        pwm_data_raw[adr + 1] = (uint8_t)(value);
21
    }
22
}

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.