Forum: Mikrocontroller und Digitale Elektronik MikroC 32bit Zahl in 4x8 Blöcke zerlegen und wieder zusammensetzen


von mikroC Zahl Bitweise addieren (Gast)


Lesenswert?

Guten Abend,

Ich habe ein 32 Bit Integer Zahl und will diese ins EEPROM bringen. Das 
EEPROM ist aber als 8 Bit Register aufgebaut, was bedeutet das ich die 
32 Bit Zahl in 4 x 8 Bit Blöcke zerlegen muss. Das zerlegen ist weniger 
Problematisch mit den Befehlen (Highest, Higher, High, Lo). Nun meine 
Frage beim zusammensetzen der Zahl kann ich ja nich die Dezimalenwerte 
addieren sondern muss die Binären nehmen. Wie könnete ich das machen ?
Der Mikrocontroller ist ein PIC16F628A

mein Vorschlag


32bitz= 8.1reg+8.2reg+8.3reg+8.4reg

aber ich denke dort addiere ich eben nur die dezimalwerte ?


Vielen Dank für die Antworten

Andreas

von Peter D. (peda)


Lesenswert?

Nimm ne Union aus dem zu speichernden Typ und nem Bytearray.


Peter

von David M. (md2k7)


Lesenswert?

naja, wenn du C benutzt, sehr einfach, zum Beispiel mit ner Union:
1
typedef union {
2
        uint32_t i32;
3
        struct {
4
                uint8_t b0;
5
                uint8_t b1;
6
                uint8_t b2;
7
                uint8_t b3;
8
        };
9
} convert32to8;
(frei nach dem AVR-GCC Tutorial hier auf der Seite und ohne Gewähr)

Wenn du den PIC in Assembler programmierst, wäre mir unklar, wo das 
Problem liegt, denn dann müsstest du eigentlich schon wissen, wie du mit 
den 4 Bytes rechnest. Soweit ich weiß haben die PIC16F ja auch nur 8 bit 
Datenbreite.

von Andreas (Gast)


Lesenswert?

Wie schon gesagt ich programmiere mit mikroC, bei einer multiplikation 
von 32 bit Zahlen übernimmt für mich der Compiler die notwendige 
Zerlegung in berechenbare Blöcke.

Vielen Dank für die Antworten

von Peter D. (peda)


Lesenswert?

Andreas wrote:
> Wie schon gesagt ich programmiere mit mikroC, bei einer multiplikation
> von 32 bit Zahlen übernimmt für mich der Compiler die notwendige
> Zerlegung in berechenbare Blöcke.

Da wird überhaupt nichts zerlegt oder berechnet.

Eine Union ist einfach nur eine unterschiedliche Typdefinition des 
selben Speicherplatzes.


Peter

von Andreas (Gast)


Lesenswert?

So jetzt hab ich das Gnaze mal mit einer 16 bit Zahl probiert:

unsigned int input;

typedef struct { unsigned short bit8_low;
                 unsigned short bit8_high; } bit16;
bit16 value;
value.bit8_low=125;
value.bit8_high=52;
input=value;


In Value. schreib ich nur testweiße die Werte, das funktioniert alles 
bis auf die letzt Programmzeile.

Irgendwie schreibt er den Wert nicht in die neue Variable.

Der Compiler bringt nur die Meldung "Kann value nicht Input zuweisen"

Aber warum ?

Integer ist eine 16bit zahl und short sind jeweils 8 bit, also müsste 
das doch funktionieren ?

von Andreas (Gast)


Lesenswert?

Hab das Problem gefunden !
1
unsigned int input;
2
3
typedef struct { unsigned short bit8_low;
4
                 unsigned short bit8_high; } bit16;
5
bit16 value;
6
value.bit8_low=125;
7
value.bit8_high=52;
8
9
input = *(unsigned*) &value;

In der Dokumentation war ein fehlerhaftes Beispiel

http://www.mikroe.com/forum/viewtopic.php?p=55658&sid=18724aa0b02a34fa1c5f818c602a496e

von Gast (Gast)


Lesenswert?

Das ist aber nicht die feine englische. Siehe oben bei den Beiträgen mit 
der union.

von Johnny Maxwell (Gast)


Lesenswert?

1
unsigned int input;
2
3
typedef struct { unsigned short bit8_low;
4
                 unsigned short bit8_high; } bit16;
5
bit16 value;
6
value.bit8_low=125;
7
value.bit8_high=52;
8
9
input = *(unsigned*) &value;

Der Code ist ziemlich sinnlos, das sind nur zwei Zuweisungen. Der Witz 
ist, das du um auf die Bytewerte zu kommen nichts rechnen musst, da 
der int ja von vornherein schon als Byte Reihenfolge im Speicher liegt. 
Du brauchst also nur die richtige Syntax, keinen weiteren Variabeln, 
etc.

Wenn du deinen int in Bytes splitten willst nimm entweder Bit Shift 
Operatoren (der Compiler wandelt das automatisch in reine Zugriffe um) 
oder ein union.

Ein union sieht auf den ersten Blick natürlich sehr elegant aus, hat 
aber den Nachteil das die (Byte-) Endianness dann vom Prozessor abhängt. 
Mit Bit Shifts kannst du die selber einstellen. Das ist aber nur 
wichtig, falls du die Daten mit einem anderen Prozessor wieder auslesen 
willst

von Andreas (Gast)


Lesenswert?

Die 2 Zuweisungen war nur um zu zeigen was ich meine Eigentlich ging es 
darum auf ein EEProm zuzugreifen da dieses nur 8Bit breit ist muss man 
doch eine 16 bit zahl zerlegen in 2 teile.
1
value.bit8_low=EEPROM_READ(1);
2
value.bit8_high=EEPROM_READ(2);

Das ist das eigentliche was ich wollte.

Wie schon gesagt ein etwas dämlich gewähltes Beispiel

von Johnny Maxwell (Gast)


Lesenswert?

Warum nicht einfach so?
1
  value = EEPROM_READ(1) + 256 * EEPROM_READ(1);

Und nein: Da muss keine lange dauernde Multiplikation durchgeführt 
werden :)
Du kannst dir ja mal den Assembler Output davon anschauen.

Oder so:
1
  value = EEPROM_READ(1) + (EEPROM_READ(1) << 8);

Du konstruierst dir da ein Problem wo gar keines ist.

von Johnny Maxwell (Gast)


Lesenswert?

Sorry, beides mal die 1. Muss natürlich heißen:
1
value = EEPROM_READ(1) + 256 * EEPROM_READ(2);
2
/* oder */
3
value = EEPROM_READ(1) + (EEPROM_READ(2) << 8);

von R. W. (quakeman)


Lesenswert?

Johnny Maxwell wrote:
> Ein union sieht auf den ersten Blick natürlich sehr elegant aus, hat
> aber den Nachteil das die (Byte-) Endianness dann vom Prozessor abhängt.

Das dürfte so nicht ganz korrekt sein.
Da es sich um einen 8Bit Prozessor handelt gibt die Hardware-Architektur 
nur innerhalb eines Bytes die Reihenfolge der Bits vor (normalerweise 
LSB rechts). Bei größeren Zahlen mit 16Bit oder 32Bit wird die 
Reihenfolge der Bytes nur durch den Compiler bestimmt, welcher diese 
dann bei Operationen mit solchen Zahlen berücksichtigen muß.
Erst bei 16Bit oder 32Bit Prozessoren ist schon in der Hardware die 
Reihenfolge der Bytes vorgegeben.

Ciao,
     Rainer

von Johnny Maxwell (Gast)


Lesenswert?

Das stimmt natürlich :)

von Andreas B. (bitverdreher)


Lesenswert?

Hallo,
ich habe das so gelöst
1
char eeprom_write_word(uint16_t eeaddr, uint16_t word) {
2
   if ((eeprom_write_byte (eeaddr, (uint8_t) (word >> 8))) == 0) return 0;
3
   return eeprom_write_byte (eeaddr+1, word);
4
}

 mit char eeprom_write_byte(uint16_t eeaddr, uint8_t byte)
(Rückgabewert ist hier 1 bei erfolgreichen Schreiben)

analog halt mit 32bit.

Gruß
Andy

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.