PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Daten aus 2 hintereinander liegenden Registern in ein char[8] Array einlesen



arwar52
18.02.2019, 15:44
Hallo Kollegen,

hat jemad ne Lösung zu so einem Fall ???
- Daten aus 2 hintereinander liegenden 32 bit Registern (insgesamt 2 x 4 = 8 Bytes) in ein char[8] Array einlesen

Theoretisch sollte man es mit Pointer erledigen können

- 1. Pointer auf den Anfang des 1. Register setzen.
- 2. Pointer auf den Anfang des char Arrays setzen

- in einer "for" Schleife bis 8
- - Byte vom Register ins char Array einlesen
- - beide Pointer incrementieren
- und so 8x

Kann das so funktionieren ???
. . . komm irgendwie nicht zu Recht.

Über eine Lösung freue ich mich jetzt schon :p

DANKE

HaWe
18.02.2019, 17:29
hallo,
ja, das geht mit memcpy:
http://www.cplusplus.com/reference/cstring/memcpy/

void * memcpy ( void * destination, const void * source, size_t num );


der char array ist ja bereits ein pointer,
für die Variable reg musst du dann ihre Adresse &reg einsetzen.


wenn destination der array ist, und du an pos. 0 des arrays einfügen willst, hieße es
uint32_t reg;
char destination[8];

memcpy ( destination, &reg , sizeof(reg) );

willst du dies 4 Stellen weiter machen, dann

memcpy ( destination+4*sizeof(char), &reg , sizeof(reg) );
da sizeof(char) = 1 ist, vereinfacht
memcpy ( destination+4, &reg , sizeof(reg) );



oder wenn dein array noch größer als 8 wäre, z.B. für 20 Stellen weiter:

char destination[100];
memcpy ( destination+20, &reg , sizeof(reg) );


oder allgemein

memcpy ( destination+charpos, &reg , sizeof(reg) );

arwar52
18.02.2019, 19:38
DANKE HaWe.
Werde es mal versuchen :-)

- - - Aktualisiert - - -

... leider arbeite ich in einer ganz bestimmten Umgebung die KEINEN memcpy hat :-(

Konnte es erstmal so lösen:
+++++++++++++++
for (i=0; i < 8; i++){
Data[i] = *pRegister;
pRegister++;
}

++++++++++++++++

Leider frunktioniert es NICHT in die andere Richtung - vom Array ins Register.
Egal in welchen Byte des Registers man den char schreibt - alle 4 Bytes des Registers werden mit dem selben char beschrieben :( ???
Das andere Register bleibt unberührt.
Sobald i > 3, passiert das gleiche mit dem 2. Register.

Also man sieht
- beide Zeiger bewegen sich Byte für Byte entlang der beiden Registers und Array.
- es werden die richtigen char's geschrieben

NUR diese char's befüllen nicht ein Byte des Registers sondern ALLE Bytes - und das ist nicht gewünscht . . .

Wo könnte da der Fehler liegen?
+++++++++++++++++++++++++++++++
for( i = 0; i < 8; i++ ){
*pTxRegister = Data[i];
pTxRegister++;
}
+++++++++++++++++++++++++++++++

Siro
18.02.2019, 20:27
Ich vermute hier gibt es eine Vermischung zwischen 2 verschiedenen Pointern
Da es sich anscheinend um eine 32 Bit ARM Prozessor handelt, hat ein Register 4 Bytes.
Bei deinem Dein Array hat jeder index nur ein Byte.
Das Problem tritt nun auf, wenn Du den Register Pointer mit ++ erhöhst.
Da der Pointer auf einen 4 Byte Wert zeigt, wird die Adresse auch gleich um 4 Bytes erhöht.

Du benötigst einen char* also einen Character Pointer auf dein Register

char *pRegister; // ein Byte Zeiger auf irgendwas

pRegister = (char*)&DeinRegister; // Der Zeiger setzt Du auf die Adresse des Registers

Data[i]=*pRegister++; // nun werden die Bytes kopiert uind der Zeiger wird Byteweise erhöht.

Siro

arwar52
18.02.2019, 20:54
Hallo Siro.

- eigentlich habe ich den pointer als char *pTxRegister deklariert.
Und im Debag modus siet man auch - nach ++ erhoht sich der Pointer um 1 Byte , nicht um 4.

Siro
18.02.2019, 21:03
Ich hab das grade so ausprobiert mit 4 Bytes,



char Data[8];
volatile unsigned int value;
volatile char* pRegister; // muss ein byte Zeiger sein

int main(void)
{ int i;

value = 0xAABBCCDD; // Testweise einen Wert ins register bzw. Speicher schreiben
pRegister = (char*)&value; // hier setze ich die Adresse

for (i=0; i<4; i++)
{
Data[i]=*pRegister++; // alle Bytes kopieren

}
}

ich hab jetzt nur mal 4 Bytes kopiert. Wenn deine anderen 4 bytes genau dahinter stehen, kannst Du natürlich alle 8 kopieren

arwar52
18.02.2019, 21:17
Hi Siro,
danke für Deine Mühen :-)

Was Du gerade zugeschikt hast - vom Register ins Array - funktioniert bei mir auch - siehe oben um 20:38

Ich stecke fest bei Übertragung der Daten vom Array ins Register . . . :( siehe oben um 20:38

Siro
18.02.2019, 21:22
struct // hier habe ich eine 8 Byte Struktur
{
unsigned int a; // 4 Bytes
unsigned int b; // nochmal 4 Bytes
} value;

char* pRegister;

unsigned char Data[8];

int main(void)
{int i;

// 8 Bytes initialisieren
value.a = 0x11223344;
value.b = 0x55667788;

pRegister = (char*)&value; // Zeiger setzen

for (i=0; i<8; i++) // alle 8 Bytes kopieren
{
Data[i]=*pRegister++;
}

// !!!!! den Pointer wieder richtig setzen !!!! hatte ich eben auch vergessen.....
pRegister = (char*)&value; // Zeiger wieder auf Start setzen

for (i=0; i<8; i++) // alle 8 Bytes zurück kopieren
{
*pRegister++=Data[i];
}

arwar52
18.02.2019, 21:58
. . glaube es siet bei mir ziemlich änlich aus ausser das ich CAN Register mit bestimmten Adresse anspreche.

Aber das ist ja auch NUR Speicher . . .

++++++++++++++++++++
char Data[8] = "11223344";

volatile char *pTxRegister = (char *)(CAN1_BASE + CAN_TDL0R_OFFSET);

for (unsigned char i = 0; i < 8; i++){
*pTxRegister = Data[i ];
pTxRegister++;
}

Müsste doch gehen, ABER
jedes Zeichen wird nicht nur in das adressierte Byte sondern in jedes der 4 Bytes des Registers übertragen.

- - - Aktualisiert - - -

. . ok hab es erst mal so gelöst:
pTxReg1 = Data[i+3] << 24 | Data[i+2] << 16 | Data[i+1] << 8 | Data[i+0];
pTxReg2 = Data[i+7] << 24 | Data[i+6] << 16 | Data[i+5] << 8 | Data[i+4];

i - ist die Verschiebung durch das Data Array.

Ist nicht so elegant wie ne Schleife aber erfüllt den Zweck.

Trotzdem würde mich interessieren wieso es mit der Schleife nicht tut ???
Wo ist da der Fehler ??

HaWe
19.02.2019, 05:45
... leider arbeite ich in einer ganz bestimmten Umgebung die KEINEN memcpy hat

memcpy ist Teil der Bibliothek <cstring> bzw. <string.h> , wieso kannst du die nicht #includen? Das ist schließlich eine C99 Standardbibliothek, die jeder C Compiler einbinden kann.

Klebwax
19.02.2019, 06:06
Die ganze Sache ist nicht so einfach. Das fängt schon mal mit der Größe der Variablen an. Ein int ist in C mindestens 16 Bit, kann aber auch 64 Bit sein. Dazu kommt noch die Anordnung und die Orientierung der Bytes im Speicher, also ob Big oder Little Endian. Sauberer C-Code sollte von all dem nicht abhängig sein. Spätestens bei der Übertragung der Daten zwischen verschiedenen Systemen fällt einem das sonst auf die Füsse.

Um die Größe sicherzustellen, kann man int32_t bzw. uint32_t verwenden. Und um Probleme mit der Endianes zu vermeiden ist

pTxReg1 = Data[i+3] << 24 | Data[i+2] << 16 | Data[i+1] << 8 | Data[i+0];

ein Weg. Rückwärts geht es dann über Schieben nach rechts und ausmaskieren. Das sollte auf allen Architekturen das gleiche Ergebnis liefern.

MfG Klebwax

Ceos
19.02.2019, 06:57
kein memcpy?
hast du denn
#include <string.h>
schon probiert?
Der compiler weis meistens am besten wie man mit registern umgeht, also sollte man es dem compiler auch überlassen.

Ich unterstütze hier Klebwax mit seiner Aussage, wenn man schon Bare-Bone programmiert sollte man sich ein klein wenig mit der Architektur mit der man arbeitet auseinandersetzen.

Die Register sind je nach Controller und zugehöriger Bibliothek ander zu benutzen und sollten (wenn man nicht gerade irgendwelche Magie mit DMAs versucht) auch so benutzt werden. Ein Register manuell per Pointer anzusprechen führt nur zu den seltsamsten Effekten. Da gibt es z.B. den XMega (okay nicht gerade ein ARM, aber ein gutes Beispiel) bei dem man immer erst das high und dann das low byte beschreiben muss, weil er sonst nur das low byte kopiert und das high byte dann irgendwo anders landet wenn man ein anderes Register beschreibt.

HaWe
19.02.2019, 09:08
das mit dem #include <cstring> bzw. <string.h> hatte ich oben ja auch bereits angemerkt.
Welche Endianess vom Compiler bzw. MCU benutzt werden, ist aber eigentlich egal, wenn man es anschließend wieder als (int) bzw. (uint32_t) ausliest oder aber zurückkopiert - das mache ich auch immer so, und es klappt sowohl auf AVRs als auch ARM Cortex M0, M3, M4 als auch auf dem Raspi (ARM57).

Ceos
19.02.2019, 09:29
das mit dem #include <cstring> bzw. <string.h> hatte ich oben ja auch bereits angemerkt.
Sorry muss ich überlesen haben


Welche Endianess vom Compiler bzw. MCU benutzt werden, ist aber eigentlich egal, wenn man es anschließend wieder als (int) bzw. (uint32_t) ausliest oder aber zurückkopiert

sicher, aber wenn du es vorher in Bytes zerlegst und willkürlich speicherst kommt am Ende nur Murks raus wenn man nicht auf die Byteorder achtet :)

Worauf ich hinaus wollte war eher dass man die Register nach Möglichkeit ausschließlich (DMA als Ausnahme genannt) über ihr Registernamen und nicht über Pointer ansprechen sollte! Bzw die Zuweisung zu Registern und ggf. auch das auslesen immer (quasi-)atomar machen sollte und nicht stückeln.
Bei AtMegas und XMegas wie erwähnt, kann man auch manche Register word- oder byteweise schreiben aber da der Bus nur 8 bzw. 16 bit breit ist muss man da auf die Reihenfolge achten, da quasi der halbe Schreibbefehl in einem Puffer landet und der Latch erst mit dem schreiben des low Byte ausgeführt wird und wenn man falsch herum schreibt kommt auch nur Murks dabei raus.

Byteweise + Register (>8bit bzw. >Busbreite) sollte man generell vermeiden, das ist der Kern meiner Aussage

HaWe
19.02.2019, 10:43
wieso willkürlich?
In meinem Beispiel oben mit memcpy kopiere ich doch immer die int32-Bytes in 4er-Gruppen in das Array, anschießend könnte man es genau so weiter- oder wieder zurückkopieren, die Ordnung würde dabei nicht geändert.

(edit): vorrausgesetzt ntl, es handelt sich tatsächlich um 32-bit-Register.... 8)

Ceos
19.02.2019, 11:03
ich bezog mich auch nicht auf dein Beispiel sondern mein Satz sagte
aber wenn du es vorher in Bytes zerlegst und willkürlich speicherst kommt am Ende nur Murks raus wenn man nicht auf die Byteorder achtet ... du hattest verallgemeinert geantwortet oder dich implizit auf deine Aussage bezogen und das wollte ich relativieren, denn allgemein gilt das nicht!

Casten alleine reicht nicht wenn man zwischendurch stückelt. Immer Vorsicht mit der Byteorder bei sowas. Das will ich damit sagen...

HaWe
19.02.2019, 11:13
ich habe im meinem Beispiel oben die 32-bit-Variable (ob Register oder nicht) doch gar nicht in einzelne Bytes zerlegt, sondern per memcpy als 4er-Block komplett in den Array rüberkopiert!

https://www.roboternetz.de/community/threads/73094-Daten-aus-2-hintereinander-liegenden-Registern-in-ein-char-8-Array-einlesen?p=650420&viewfull=1#post650420

- - - Aktualisiert - - -

PS,
jetzt verstehe ich - wir haben aneinander vorbei geredet.
Ich halte das Zerlegen in einzelne Bytes mit anschließendem Shiften oder was auch immer auch für potentiell fehleranfällig, daher ja mein Vorschlag mit memcpy für den ganzen 32bit-Block.

arwar52
19.02.2019, 22:22
Hallo Kollegen,

vielen DANK für die die Erklärung der Sache.

Wie genau die Register beschrieben werden ??? - da bin ich noch zu jung im Fach :-)

Also gelernt - Register langsam und sicher zu beschreiben.
Gewünschten Triks gehen nicht immer durch :-(

Vielen DANK noch mal.