12 bit Wert in Array aus uint8_t speichern

OP Persönliche Seite #2431542
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
OP Persönliche Seite #2431596
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.
OP Persönliche Seite #2431681
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.
Gast #2431780
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
...
OP Persönliche Seite #2432279
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
#2432325
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.
#2432355
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.
OP Persönliche Seite #2432364
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);
#2432372
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
OP Persönliche Seite #2432433
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
}
OP Persönliche Seite #2432852
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
}
OP Persönliche Seite #2432875
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
}

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