Forum: Mikrocontroller und Digitale Elektronik Daten in Struct zuordnen und ins EEPROM speichern


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe folgendes Problem:

ich bekomme vom PC Daten über ein Protokoll mit folgendem Aufbau

Art   Befehl-ID Wert
1Byte 2Byte     5 Byte

jetzt bekomme ich beim Wert jeweils Variablen mit Werten aus einem 
Struct.

Ich empfange diese Daten und schreibe die als Struct ins EEPROM wobei 
ich wiederrum zur Laufzeit auch einzelne Werte aus dem EEPROM lese bzw. 
auch wieder schreibe.

Soweit so gut aber jetzt komme ich nicht weiter undzwar: Ist mir nicht 
ganz klar wie ich:
a) empfangene Daten max 5 Byte (Wert) in das struct jeweils richtig den 
entsprechenden Variablen zuordne.

b) wie stelle ich sicher, dass ich aus dem EEPROM auch wirklich die 
Werte aus abgelegten Struct lese und sich das ganze nicht verschiebt.



Wäre schön wenn einer das Prinzip erklären könnte, denn ich kann nicht 
ganz nachvollziehen wie ich die Informationen die in den 5 Bytes 
enthalten sind so im struct ablege, sodass im PC und µC es gleich 
aufgebaut ist.


Danke!

von Frank K. (fchk)


Bewertung
0 lesenswert
nicht lesenswert
1
#pragma pack(push,1)
2
struct{
3
 uint8_t art;
4
 uint16_t befehl;
5
 uint8_t wert[5];
6
} paket_t;
7
#pragma pack(pop)

Das #pragma ist compilerspezifisch (hier für Microsoft C), bei anderen 
Compilern ist das ein __packed, _attribute(irgendwas) oder wie auch 
immer - steht jedenfalls in der Dokumentation.

Damit sagst Du dem Compiler, dass er die Variablen so dicht wie möglich 
packed soll. Er würde sonst int16 auf durch 2 oder durch 4 teilbare 
Adressen legen, denn manche Architekturen können keine misaliged 
Zugriffe (zB Wortzugriffe auf ungerade Adressen).

fchk

von Basti (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wenn die selbe Architektur das struct speichert und lädt ist gar kein 
packed nötig! Wenn man nicht unbedingt jedes Byte sparen will!

Vorschlag:

int eeprom_store(uint32_t addr, void *data, size_t len);
int eeprom_load(uint32_t addr, void *data, size_t len);

aufrufen z.B. mit:

eeprom_store(0, &my_struct, sizeof(my_struct));
eeprom_load(0, &my_struct, sizeof(my_struct));

VG

Basti

P.S. sizeof beachtet das padding des Kompilates!

von Paddy (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Vergess nicht die endianess unterschieden zwischen beide systemen !
https://en.wikipedia.org/wiki/Endianness

von Basti (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Jap,

selbst mit packed und gleichem Endian würde ich bei der Kommunikation 
nicht folgendes tun:

memcpy(&my_struct, recv_buffer, sizeof(my_struct));

Dann sollte jeder lieber Element einzeln kopiert/extrahiert werden, auch 
wenn es mehr Schreibarbeit bedeutet.

Beim EEPROM laden und speichern ist es dann wieder egal...

von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

die Struktur sieht in etwa so aus (siehe unten) die ich bekomme und da 
ist mir schon nicht ganz klar wie sie in 5Bytes übertragen wird, ich 
denke das jede einzelne Variable die max 5Bytes vom Wert belegt aus dem 
Struct übertragen wird, richtig?


Basti schrieb:
> Vorschlag:
>
> int eeprom_store(uint32_t addr, void *data, size_t len);
> int eeprom_load(uint32_t addr, void *data, size_t len);

ich möchte dafür die funktionen eeprom_update_block und 
eeprom_read_block

nutzen aus <avr/eeprom.h>. Wie füge ich jetzt die Informationen die ich 
in den 5 Bytes bekommen habe in das Struct ein ?




1
#if X86
2
#define AVRPACK
3
#pragma pack push
4
#else
5
#define AVRPACK __attribute__((__packed__))
6
#endif
7
8
typedef struct
9
{
10
  
11
  uint16_t exposeN;
12
  uint16_t exposeL;
13
  uint16_t exposeD;  
14
  
15
  uint16_t gammaR;
16
  int16_t gammaG;
17
  int16_t gammaB;
18
  int16_t gammaM;
19
  
20
  int16_t mot_Pos1;
21
  int16_t mot_Pos2;
22
  
23
  uint16_t RESERVED;
24
} AVRPACK Att_t; 
25
26
typedef struct
27
{
28
  
29
  uint8_t allowed;
30
  
31
  uint8_t zoomL;
32
  
33
  uint16_t m;
34
  uint16_t m;  
35
  
36
  
37
  uint16_t x;
38
  uint16_t y;
39
  
40
  uint16_t RESERVED;  
41
  
42
  Settings_t at;
43
  Settings_t at;
44
  Settings_t at;
45
  Settings_t at;
46
  
47
  
48
} AVRPACK Z_t;

von Basti (Gast)


Bewertung
0 lesenswert
nicht lesenswert
@Hans woher sollen wir wissen warum das 5 Byte sind und wie die 
angeordnet sind? Das musst du herausfinden und das wäre auch die Lösung 
wie du die eingehende Variable in deine Struktur speicherst.

von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Basti schrieb:
> @Hans woher sollen wir wissen warum das 5 Byte sind und wie die
> angeordnet sind? Das musst du herausfinden und das wäre auch die Lösung
> wie du die eingehende Variable in deine Struktur speicherst.

Naja nach dem Protokoll

 Art   Befehl-ID    Wert
1Byte    2Byte     5 Byte

werden die Variablen jeweils aus dem Struct von der Gegenseite (PC) 
nacheinander in Wert übertragen. Jetzt hab ich z.B. dort den Wert von 
der Variablen uint8_t zoomL; drinne. Aber wie schreibe ich das jetzt in 
mein Struct auf dem µC welches ich dann ins EEPROM verschiebe oder wenn 
das geht sofort ins EEPROM schreibe.

Denn von meinem Verständnis passt ja das ganze Struct nicht in 5 Bytes.

Daher ist das Schreiben hintereinander notwenig und woher weiß ich 
welche Variable sich gerade in den 5 Bytes befindet?

Ich hoffe man kann das Problem in etwa verstehen ._.

von Basti (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Das Protokoll wird hoffentlich aus einem längeren Dokument bestehen und 
das musst du verstehen!

Wir können maximal vermuten:
Wahrscheinlich sagt dir die "Befehl-ID" welche Variable gerade kommt und 
dann liegt evtl. die Variable little endian gleich vorn in den 5 Byte...

von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Basti schrieb:
> Wir können maximal vermuten:
> Wahrscheinlich sagt dir die "Befehl-ID" welche Variable gerade kommt und
> dann liegt evtl. die Variable little endian gleich vorn in den 5 Byte...

Es geht um das Prinzip das Protokoll besagt folgendes:

Art:Write / Read   Befehl-ID: Adresse beginnt bei NULL    Wert: Variable 
aus dem Struct vom PC

Das vom PC gesendete könnte so ausehen:

Write (max. 1Byte) NULL (max. 2 Byte)  zoomL = 240 (max 5.Byte);
Write (max. 1Byte) 1 (max. 2 Byte)  gammaR = 2400 (max 5.Byte);
Write (max. 1Byte) 2 (max. 2 Byte)  gammaG = 50000 (max 5.Byte);

etc..


Die Frage die ich eigentlich habe ist jetzt: wie extrahiere ich jetzt 
aus dem Befehlsatz die Befehl-ID also die Adresse von wo das schreiben 
ins EEProm beginnt dann den dazugehörigen Wert und wie schreibe ich das 
nun ins EEPROM hab an sowas gedacht:
1
eeprom_update_block(&RAMZoomSettings, &EEPROMZoomSettings, sizeof(ZoomSettings_t));   
2
RAMZoomSettings.zoomL = ui64Val;


Es wird jetzt zwar ins EEPROM geschrieben und der Platz des Struct wird 
im EEPROM angelegt aber ich möchte ja die Variablen die ich aus dem 
Protokoll bekommen habe an die richtige adresse im EEPROM schreiben.

Um später z.B. beim start des µC die werte aus dem EEPROM zu laden oder 
im laufenden betrieb darauf zu greifen uns sie als Offset verwenden.

von Basti (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Also ich weiß nicht genau worauf du hinaus willst... ich habe zwei 
Vermutungen:

1. Du weißt nicht wie du mit einer Statemachine dieses Protokoll in 
deinen µC sauber in einen Buffer einlesen kannst. Du kennst auch nicht 
die Grundlagen des Framings. Dann könntest du dich z.B. hier erst einmal 
grob über die Konzepte belesen:
https://sebastianfoerster86.wordpress.com/2017/02/01/protokolldesign-kommunikation/

2. Du hast noch keine switch case verwendet. Dann schlage ich mal vor
1
switch(Befehl_ID)
2
{
3
    case 0: //schöner mit enum typen!
4
    {
5
    //Daten der EEPROM struct zuordnen und zuweisen und abspeichern
6
    }
7
    break;
8
}

VG

Basti

von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Basti schrieb:
> Also ich weiß nicht genau worauf du hinaus willst... ich habe zwei
> Vermutungen:
>
> 1. Du weißt nicht wie du mit einer Statemachine dieses Protokoll in
> deinen µC sauber in einen Buffer einlesen kannst. Du kennst auch nicht
> die Grundlagen des Framings. Dann könntest du dich z.B. hier erst einmal
> grob über die Konzepte belesen:
> 
https://sebastianfoerster86.wordpress.com/2017/02/01/protokolldesign-kommunikation/
>
> 2. Du hast noch keine switch case verwendet. Dann schlage ich mal vor
> switch(Befehl_ID)
> {
>     case 0: //schöner mit enum typen!
>     {
>     //Daten der EEPROM struct zuordnen und zuweisen und abspeichern
>     }
>     break;
> }

Ein großes Danke schön dir schon mal !!!

Aber die Statemachine für das Protokol habe ich schon die auch soweit 
funktioniert mir Fehlt das wissen in der Zeile von dir wo der Kommentar: 
"//Daten der EEPROM struct zuordnen und zuweisen und abspeichern" 
steht.

mein Buffer ist [8] groß wenn ich jetzt z.b die Befehls-ID extrahieren 
möchte dann mache ich das so
1
 
2
uint16_t get_adr (void)
3
{
4
  uint16_t ui16Temp;
5
  
6
  ui16Temp  = ucRxBuffer [1];
7
  ui16Temp <<= 8;
8
  ui16Temp += ucRxBuffer [2];    
9
  
10
  return ui16Temp;
11
}   
12
13
ui16Adr = get_adr();

soweit so gut aber wie gehe ich jetzt weiter vor wenn ich die Adresse in 
der Variable ui16Adr habe wie weise ich das jetzt dem Struct zu und 
schreibe das ins EEPROM?

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Hans89 schrieb:
> wie weise ich das jetzt dem Struct zu
In dem du die Daten in einen dafür reservierten Speicherbereich 
schreibst!

Denn man kann einer Struktur keine Daten zuweisen.

Das wäre ein bisschen so, als würdest du das Wort "Eimer" auf Papier 
schreiben und dann versuchen da Wasser einzufüllen.

: Bearbeitet durch User
von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Arduino F. schrieb:
> In dem du die Daten in einen dafür reservierten Speicherbereich
> schreibst!

Ich fürchte ich kann mein Problem schlecht in Worte fassen.

ich versuche es nochmal etwas anders zu beschreiben:
Bsp.:

1)Vom PC gesendet

Write (max. 1Byte) NULL (max. 2 Byte)  zoomL = 240 (max 5.Byte);
Write (max. 1Byte) 1    (max. 2 Byte)  gammaR = 2400 (max 5.Byte);
Write (max. 1Byte) 2    (max. 2 Byte)  gammaG = 50000 (max 5.Byte);


2)extrahieren der Adresse und des Wertes aus dem RxBuffer
1
uint16_t get_adr (void)
2
{
3
  uint16_t ui16Temp;
4
  
5
  ui16Temp  = ucRxBuffer [1];
6
  ui16Temp <<= 8;
7
  ui16Temp += ucRxBuffer [2];    
8
    
9
  return ui16Temp;
10
}  
11
  
12
uint64_t get_val(void)
13
{
14
  uint64_t ui64Temp;
15
  
16
  ui64Temp =  ucRxBuffer [3];
17
  ui64Temp <<=8; 
18
  ui64Temp += ucRxBuffer [4];
19
  ui64Temp <<=8; 
20
  ui64Temp += ucRxBuffer [5];
21
  ui64Temp <<=8; 
22
  ui64Temp += ucRxBuffer [6];
23
  ui64Temp <<=8; 
24
  ui64Temp += ucRxBuffer [7];    
25
  
26
  return ui64Temp;
27
}
28
29
ui16Adr = get_adr();
30
ui64Val = get_val();
3)
jetzt habe ich die Adresse als Wert in ui16Adr Variable und analog dazu 
Wert in der ui64Val Variablen.

4) wie schreibe ich das ganze ins EEPROM an die Adresse 0 und den Wert 
der in ui64Val steht und das ganze immer weiter je nachdem was im 
Kommando vom PC steht[andere Adresse, anderer Wert].


folgendes funktioniert aber dabei schreibe ich nur den Wert
1
ZoomSettings_t EEMEM EEPROMZoomSettings;
2
ZoomSettings_t RAMZoomSettings; 
3
4
eeprom_update_block(&RAMZoomSettings, &EEPROMZoomSettings, sizeof(ZoomSettings_t));
5
6
RAMZoomSettings.zoomL = ui64Val;


Kann jemand bitte einen Hinweis dazu geben?

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Hans89 schrieb:
> Ich fürchte ich kann mein Problem schlecht in Worte fassen.
Das ist so nicht das Problem!

Folgendes läuft hier schief:
Du hast dir was ausgedacht, ohne die Bedingungen zu beachten.
Und jetzt hängst du auf dem falschen Ast, und siehst kein Weiterkommen.


Wie ich es machen würde:

Ich würde eine Struktur definieren, welche alle meine Daten, welche ins 
EEProm kommen sollen erfasst.

Dann erzeuge ich eine Variable dieses Types, und teile dem Kompiler mit, 
dass er diese Variable in der EEPROM Section anlegen soll.

Der Vorteil dieser Konstruktion:
1:
Der Kompiler/linker erzeugt mir ein *.eep File, welches ich per ISP auf 
den Controler schreiben kann. Das ist schön, wenn man den Bereich mit 
default Daten versehen möchte/muss.
2:
Ich komme nie mit der Adressberechnung durcheinander! Das tut alles der 
Compiler für mich.

: Bearbeitet durch User
von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Arduino F. schrieb:
> Ich würde eine Struktur definieren, welche alle meine Daten, welche ins
> EEProm kommen sollen erfasst.

die Struktur gibt es siehe oben

Arduino F. schrieb:
> Dann erzeuge ich eine Variable dieses Types, und teile dem Kompiler mit,
> dass er diese Variable in der EEPROM Section anlegen soll.

hab ich auch soweit gemacht

Die Frage ist eine andere: Wie kann ich wenn ich die Funktion 
eeprom_update_block nutzen möchte die Empfangen Daten ins EEPROM 
schreiben, sodass ich darauf zu greifen kann

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Hans89 schrieb:
> Die Frage ist eine andere: Wie kann ich wenn ich die Funktion
> eeprom_update_block nutzen möchte die Empfangen Daten ins EEPROM
> schreiben, sodass ich darauf zu greifen kann

Die Funktion mit Quelle, Ziel, Anzahl aufrufen!
Wie sonst?

Beispiel:
1
#include <avr/eeprom.h>
2
3
struct DatenSatz
4
{
5
  int version;
6
  char name[64];
7
  unsigned long resetCounter;
8
};
9
10
11
DatenSatz EEMEM eep_datensatz  = {1,"Frosch",0}; // Gcc erzeugt *.eep Datei
12
13
14
int main(void)
15
{
16
  unsigned long counter;
17
  eeprom_read_block(&eep_datensatz.resetCounter,&counter,sizeof(counter));// lesen
18
  counter++; 
19
  eeprom_write_block(&eep_datensatz.resetCounter,&counter,sizeof(counter));// schreiben
20
  
21
  
22
  for(;;);
23
}
*getestet mit der Arduino IDE, und einem UNO*

: Bearbeitet durch User
von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Arduino F. schrieb:

> int main(void)
> {
>   unsigned long counter;
>   eeprom_read_block(&eep_datensatz.resetCounter,&counter,sizeof(counter)); //
> lesen
>   counter++;
>   eeprom_write_block(&eep_datensatz.resetCounter,&counter,sizeof(counter)) ;//
> schreiben
>
>
>   for(;;);
> }

bei mir ist Information (Wert) in der Variablen ui64Val(Max. 5 Bytes) 
enthalten welche sich entsprechend (je nachdem was der PC sendet) ändert 
enthalten wie schreibe ich diese ins EEPROM?

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Sorry:
eeprom_write_block(&eep_datensatz.resetCounter,&counter,sizeof(counter)) 
;//  schreiben

Muss so:
eeprom_write_block(&counter,&eep_datensatz.resetCounter,sizeof(counter)) 
;//  schreiben

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Hans89 schrieb:
> bei mir ist Information (Wert) in der Variablen ui64Val(Max. 5 Bytes)
> enthalten welche sich entsprechend (je nachdem was der PC sendet) ändert
> enthalten wie schreibe ich diese ins EEPROM?
Ich glaube, ich kann dir nicht helfen....
aufgeb

von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

so geht es jetzt aber ich möchte eigentlich das die Variable ui64Val die 
gesamte Struktur mit dem Wert von ui64Val füll unzwar jenachdem welches 
element aus der Struktur (die Strukturen sind im µC und PC gleich 
aufgebaut) vom PC gesendet wird:

in etwa so aber das funktioniert nicht weil die syntax nicht passt kann 
mir vllt einer einen Tip geben wie man sowas macht?
1
for(i=0; i<sizeof(ZoomSettings_t); i++)
2
{
3
  RAMZoomSettings[i] = ui64Val;
4
}


Das klapp:
1
ZoomSettings_t EEMEM EEPROMZoomSettings;
2
ZoomSettings_t RAMZoomSettings;
3
4
RAMZoomSettings.x = ui64Val;
5
eeprom_update_block( &RAMZoomSettings, &EEPROMZoomSettings, sizeof(ZoomSettings_t) );

von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Kann keiner was dazu sagen?

Komme nicht weiter...


thx

von Basti (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ich gebe auch auf...

Da hilft nur selbst nachdenken Hans! Alternativ ist dir das Projekt 
evtl. zur Zeit zu schwieirg und zu viel für deine Fähigkeiten.

von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Das ist sehr motivierend .-(

Ich bin noch nicht so erfahren in C und weiß daher nicht wie man das 
korrekt mit der syntax ausprogrammieren muss...


Vllt kann mir doch einer ein Beispiel machen

von Marco H. (damarco)


Bewertung
0 lesenswert
nicht lesenswert
hmm

Du musst dich erst mal damit befassen wie die Daten im EErom abgelegt 
werden. Außerdem ob es wirklich sinnvoll ist diese Daten zur Laufzeit 
dauert aus dem EErom zu lesen ?  Denn dieser ist langsam und veranlasst 
zum warten .

Wenn du dass versteht wirst du auch Festellen das du nicht so einfach 
auf einzelne Werte im Struct zugreifen kannst. Denn es wird Blockweise 
gelesen und geschrieben.  Du müssten wissen in welchen Block die Daten 
liegen ;)

Überlichtweise ließt man das ganze Struct aus und schreibt es zurück 
wenn sich etwas ändert.

Parameter etc. ließt man aus und arbeitet aus dem Speicher heraus mit 
ihnen.

Nun auch solltest du dich damit befassen wie die Daten im Speicher 
abgelegt werden. Es ist nicht gesagt das sie mit aufsteigenden Adressen 
dort liegen. Auch weist du nicht wie die verschieden Datentype dort 
angeordnet werden. Naja wenn man sich damit befasst schon ;)


Solche Konstrukte sind immer gefährlich wenn man die Architektur nicht 
ausreichend kennt.

Ich verstehe auch nicht warum deine 64bit Daten Type nicht als Array 
belässt. Das hin und herschieben bringt kaum was. Denn ein AVR wird sie 
weiterhin byte weise speichern müssen.

Es gäbe noch eine Möglichkeit in dem man den Datentyp drüber castet.

 ZoomSettings_t *packet=(ZoomSettings_t*)rxbuffer;

Du legst also einen pointer an von type ZoomSettings_t und weißt diesen 
die Adresse von deinen buffer zu. Damit sich der Compiler nicht 
beschwert wird dieser zum zoomSettings_t ebenfals gecastet.

dann kannst du mit packet->x=10; auf die daten zugreifen. Allerdings 
musst du sicherstellen das dieser zusammenhängt angelegt (packed) . 
Sonst greift du auf Adressen zu wo andere Daten liegen. Die MSB-LSB 
Problematik muss man berücksichtigen bei Datentypen größer wie 1 byte.

: Bearbeitet durch User
von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Marco H. schrieb:
> hmm
>
> Du musst dich erst mal damit befassen wie die Daten im EErom abgelegt
> werden. Außerdem ob es wirklich sinnvoll ist diese Daten zur Laufzeit
> dauert aus dem EErom zu lesen ?  Denn dieser ist langsam und veranlasst
> zum warten .

dieses wird nicht ständig gelesen nur beim start vom µc diese 
offsetwerte werden vom PC bei der Konfiguration einmalig geschickt.

Marco H. schrieb:
> Ich verstehe auch nicht warum deine 64bit Daten Type nicht als Array
> belässt. Das hin und herschieben bringt kaum was. Denn ein AVR wird sie
> weiterhin byte weise speichern müssen.

das hängt mit dem protokoll zusammen mit dem die Daten gesendet werden

welches 8Byte groß ist und aufgeteil in Art 1Byte , CMD-ID 2Byte und 
Wert 5Byte ist ich extrahiere nur die 5Bytes da nur diese werte 
interessant sind welche ich nacheinander in das Struct schreibe also 
z.B. bekomme ich so etwas vom PC:

       TYPE                 COMMAND-ID                         VALUE

W (max. 1Byte)   200 (max. 2 Byte)    zoomL = 240 (max 5.Byte);
W (max. 1Byte)   200 (max. 2 Byte)    gammaR = 2400 (max 5.Byte);
W (max. 1Byte)   200 (max. 2 Byte)    gammaG = 50000 (max 5.Byte);

ich möchte jetzt nur jeweils VALUE in das Struct schreiben erst ins RAM 
und dann mit eeprom_update_block() ins EEPROM.


und da weiß ich halt nicht wie ich den wert der bei mir in der Variable 
ui64Val steht der Struct zuweise

Marco H. schrieb:
> Es gäbe noch eine Möglichkeit in dem man den Datentyp drüber castet.
>
>  ZoomSettings_t *packet=(ZoomSettings_t*)rxbuffer;
>
> Du legst also einen pointer an von type ZoomSettings_t und weißt diesen
> die Adresse von deinen buffer zu. Damit sich der Compiler nicht
> beschwert wird dieser zum zoomSettings_t ebenfals gecastet.
>
> dann kannst du mit packet->x=10; auf die daten zugreifen. Allerdings
> musst du sicherstellen das dieser zusammenhängt angelegt (packed) .
> Sonst greift du auf Adressen zu wo andere Daten liegen. Die MSB-LSB
> Problematik muss man berücksichtigen bei Datentypen größer wie 1 byte.

die Daten sind packed und padding macht avr8 bit ja normal nicht


kannst du dan vllt ein Bsp. bringen etwas ausführlicher werde aus 
ZoomSettings_t *packet=(ZoomSettings_t*)rxbuffer; nicht ganz schlau...

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Moin...

Nächster Versuch dich zu verstehen, bzw. zu kommunizieren!


In deinen Texten kommen oft (max 5.Byte) vor.
Das finde ich sehr komisch.
Vielleicht hast du dich da ein bisschen festgebissen....
Und lenkst dich und uns damit ab.

Besonders absurd mit den  (max 5.Byte) wird ist es hier:
Hans89 schrieb:
> bei mir ist Information (Wert) in der Variablen ui64Val(Max. 5 Bytes)
> enthalten
Das ist einfach unlogisch!
Eine uint64_t Variable wird niemals kleiner oder größer sein, als 8 
Byte.
NIEMALS

So wie du sagst, kannst du grundsätzlich das EEPROM lesen und auch 
beschreiben.
Du sagst aber nicht, warum du es mit diesen Daten nicht kannst.
Dabei ist den EEPROM Funktionen doch egal was du schreibst oder ließt.
Das sind treue und folgsame Sklaven.


Mein Tipp, fürs erste:
Vergiss das mit den 5 Byte!
Das verwirrt mich und auch offensichtlich dich selber.
Verwende stattdessen die Datentypen, welche dir dein C/C++ anbietet, 
oder schaffe selber welche.

Aber höre bitte auf über die "max 5 Byte" zu reden.

: Bearbeitet durch User
von Marco H. (damarco)


Bewertung
0 lesenswert
nicht lesenswert
Sag mal deine 5 byte sind nicht etwa eine Gleitkomma oder Festkomma Zahl 
? Du versucht das in ein 64bit Format und quetschen und beim auslesen 
kommt nur Käse raus ?

welchen Wertebereich haben denn einen ominösen 5 byte ?

Auf welche Art Hardware werden die Daten übertragen ? Ist das Protokoll 
bekannt ? Ja welches ?  Was soll man den Wert gemacht werden ?

MSB-LSB beachtet, besonders bei Seriellen Sachen die über 
Schieberegister funktionieren, kommen die Daten auch so an wie du sie 
erwartest ? oder ewt. spiegelverkehrt ?

Egal was du auf deinen AVR(8bit) anstellst alles bleibt bei 8bit auch 
deine 64bit sind nur ein Array aus 1 byte Elemente auf die man über 
Zeiger zugreifen kann.

Ach so was heißt maximal ?  Ist der Frame dann etwa kleiner ? wer macht 
denn so etwas ? Die Telegrammlänge sollte man schon Allgemein gültig 
aushandeln unabhängig vom Wert. Dann füllt man sie eben mit Nullen auf 
oder fügt im Frame die Länge der angehängten Daten mit ein. Der Header 
bleibt immer immer gleich.

: Bearbeitet durch User
von Marco H. (damarco)


Bewertung
0 lesenswert
nicht lesenswert
TYPE->COMMAND-ID->DATA-LENGTH->VALUES

so in etwa...

von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Arduino F. schrieb:
> Das ist einfach unlogisch!
> Eine uint64_t Variable wird niemals kleiner oder größer sein, als 8
> Byte.
> NIEMALS

das ist so gemeint, dass in der uint64_t ui64Val Variable die 5 Bytes 
schon in der richtigen Reihenfolge aus dem buffer abgelegt sind

Arduino F. schrieb:
> So wie du sagst, kannst du grundsätzlich das EEPROM lesen und auch
> beschreiben.
> Du sagst aber nicht, warum du es mit diesen Daten nicht kannst.
> Dabei ist den EEPROM Funktionen doch egal was du schreibst oder ließt.
> Das sind treue und folgsame Sklaven.



ich kann es auch mit diesen Daten z.B so
RAMZoomSettings.zoomL = ui64Val;
eeprom_update_block( &RAMZoomSettings, &EEPROMZoomSettings, 
sizeof(ZoomSettings_t) );

die Frage ist ich weiß nicht wie ich die Daten die nach und nach vom PC 
gesendet werden in das struct entsprechend ablegen kann...

von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Marco H. schrieb:
> Sag mal deine 5 byte sind nicht etwa eine Gleitkomma oder Festkomma Zahl
> ? Du versucht das in ein 64bit Format und quetschen und beim auslesen
> kommt nur Käse raus ?

nein es sind die Datentypen aus dem Struct welches gleich im µC und PC 
aufgebaut ist

Marco H. schrieb:
> Auf welche Art Hardware werden die Daten übertragen ? Ist das Protokoll
> bekannt ? Ja welches ?  Was soll man den Wert gemacht werden ?

über HID-USB aber mit einem eigenem Datagram:

   TYPE      COMMAND-ID            VALUE

W (1Byte)   200 (2 Byte)    zoomL = 240 (5.Byte);

Marco H. schrieb:
> MSB-LSB beachtet, besonders bei Seriellen Sachen die über
> Schieberegister funktionieren, kommen die Daten auch so an wie du sie
> erwartest ? oder ewt. spiegelverkehrt ?

senden empfangen funktioniert soweit

Marco H. schrieb:
> Ach so was heißt maximal ?  Ist der Frame dann etwa kleiner ? wer macht
> denn so etwas ? Die Telegrammlänge sollte man schon Allgemein gültig
> aushandeln unabhängig vom Wert. Dann füllt man sie eben mit Nullen auf
> oder fügt im Frame die Länge der angehängten Daten mit ein. Der Header
> bleibt immer immer gleich.

wird auch so gemacht wenn die Information nur 1Byte breit ist wird 
trozdem 5 Byte gesendet also z.B so W (1Byte) 100 (2Byte) zoomL = 240 
(5Byte)

Telegram ist immer 8Byte breit

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Hans89 schrieb:
> das ist so gemeint, dass in der uint64_t ui64Val Variable die 5 Bytes
> schon in der richtigen Reihenfolge aus dem buffer abgelegt sind

Da findet eine Transformation statt:
Es tröpfeln 5 Byte über die Serielle rein.
Dann stopfst du sie in ein uint64_t.
Jetzt ist es ein 8 Byte uint65_t.
Fertig und Ende mit 5 Byte!
Die sind weg.
Transformiert!
Aus der Pferdescheiße sind Tomaten geworden.
(nur nicht in deinem Kopf, da gibts die 5 Byte immer noch)

Habe ich das gut erklärt?
;-)

von Hans89 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Bisher extrahiere ich mir die jeweils notwendige Information aus dem 
Datagramm so:
1
uint8_t get_art (void)
2
{
3
  return ucRxBuffer[0];
4
}  
5
6
uint16_t get_adr (void)
7
{
8
  uint16_t ui16Temp;
9
  
10
  ui16Temp  = ucRxBuffer [1];
11
  ui16Temp <<= 8;
12
  ui16Temp += ucRxBuffer [2];    
13
  
14
  return ui16Temp;
15
}  
16
  
17
uint64_t get_val(void)
18
{
19
  uint64_t ui64Temp;
20
  
21
  ui64Temp =  ucRxBuffer [3];
22
  ui64Temp <<=8; 
23
  ui64Temp += ucRxBuffer [4];
24
  ui64Temp <<=8; 
25
  ui64Temp += ucRxBuffer [5];
26
  ui64Temp <<=8; 
27
  ui64Temp += ucRxBuffer [6];
28
  ui64Temp <<=8; 
29
  ui64Temp += ucRxBuffer [7];    
30
    
31
  return ui64Temp;
32
}
33
34
uint8_t ucArt;
35
uint16_t ui16Adr;
36
uint64_t ui64Val;
37
38
ucArt = get_art();
39
ui16Adr = get_adr();
40
ui64Val = get_val();


was auch gut klappt vllt kann man hier besser erkennen das mein Wert der 
vom PC gesendet wir sich in der Variablen ui64Val befindet und bei jedem 
Sendevorgang befindet sich der Wert der jeweilen Variablen aus dem 
Struct


Bsp:
1
typedef struct
2
{
3
  
4
  uint16_t exposeN;
5
  uint16_t exposeL;
6
  uint16_t exposeD;  
7
  
8
  uint16_t gammaR;
9
  int16_t gammaG;
10
  int16_t gammaB;
11
  int16_t gammaM;
12
  
13
  int16_t mot_Pos1;
14
  int16_t mot_Pos2;
15
  
16
  uint16_t RESERVED;
17
}Att_t; 
18
19
ui64Val = Att_t.exposeN;
20
ui64Val = Att_t.exposeL;
21
ui64Val = Att_t.exposeD;
22
usw...
23
24
bis die gesamte Struktur verschickt wurde

von Eric B. (beric)


Bewertung
0 lesenswert
nicht lesenswert
Was sind in den Telegrammen dann diese "Type-ID" und "Command"?
Wenn ein Telegramm empfangen wird, woher weisst du ob ExposeN, 
ExposeL oder ExposeD verschickt wurde?

> Bsp:
>
> typedef struct
> {
>
>   uint16_t exposeN;
>   uint16_t exposeL;
>   uint16_t exposeD;
...
> }Att_t;
>
> ui64Val = Att_t.exposeN;
> ui64Val = Att_t.exposeL;
> ui64Val = Att_t.exposeD;
> usw...

Att_t ist eine Typedef, keine Variable. Die Zuweisung wird so nicht 
funktionieren. Vielleicht suchst du einfach so was:
1
uint64_t read_value()
2
{
3
  uint64_t retval = 0;
4
5
  read_telegram_from_UART();
6
7
  for(int i = 3; i < 8; i++)
8
    retval = (retval << 8) | rxBuffer[i];
9
  
10
  return retval;
11
}
12
13
void read_att(Att_t *pAtt)
14
{
15
  pAtt->exposeN = read_value();
16
  pAtt->exposeL = read_value();
17
  pAtt->exposeD = read_value();
18
  // ...usw...
19
}
20
21
int main()
22
{
23
  Att_t theAtt;
24
25
  read_att(&theAtt);
26
  // usw...
27
}

von Walter S. (avatar)


Bewertung
0 lesenswert
nicht lesenswert
Bahnhof? Ich habe nicht den leisesten Hauch einer Ahnung wo dein Problem 
ist (und ich glaube das liegt nicht an mir)
Wie sieht ein Beispieltelegramm aus, was genau soll damit gemacht 
werden, warum geht das bei dir nicht?

von Sheeva P. (sheevaplug)


Bewertung
0 lesenswert
nicht lesenswert
Hans89 schrieb:
> Bisher extrahiere ich mir die jeweils notwendige Information aus dem
> Datagramm so:

Das, was Du da vorhast, geht vermutlich wesentlich einfacher mit einer 
Union. Das ist eine spezielle Datenstruktur, mit der derselbe Speicher 
mithilfe verschiedener Datentypen angesprochen werden kann.

Im folgenden Beispiel ist command_t::eeprom ein ganz einfacher Puffer, 
in den die Daten aus der seriellen Schnittstellen geschrieben werden 
können. command_t::data ist eine Datenstruktur vom Typ data_t, mit der 
die Daten strukturiert aus dem Puffer gelesen oder hineingeschrieben 
werden können.

Beachte bitte auch, daß ein struct oder ein typedef struct nur 
beschreiben, wie eine Datenstruktur aussehen soll. Um die Datenstruktur 
zu benutzen, muß sie angelegt werden; im folgenden Beispiel tut das die 
Zeile "command_t c".
1
#include <stdio.h>
2
#include <string.h>
3
#include <inttypes.h>
4
5
typedef struct {
6
    char art;
7
    char befehl[2];
8
    char wert[5];
9
} data_t;
10
11
typedef union {
12
    data_t data;
13
    char eeprom[8];
14
} command_t;
15
16
17
int main(void) {
18
19
    char cmd[] = "12345678";
20
21
    command_t c;
22
    memcpy(&c.eeprom, cmd, sizeof(c.eeprom));
23
24
    for(int i = 0; i < 8; ++i) {
25
  printf("%c", c.eeprom[i]);
26
    }
27
    printf("\n");
28
29
    printf("%c | %c %c | %c %c %c %c %c\n",
30
     c.data.art,
31
     c.data.befehl[0], c.data.befehl[1],
32
     c.data.wert[0], c.data.wert[1], 
33
           c.data.wert[2], c.data.wert[3],
34
           c.data.wert[4]);
35
36
    return 0;
37
}

Ansonsten möchte ich Dir die Lektüre des Standardwerks "The C 
Programming Language" von Brian Kerninghan und Dennis Ritchie ans Herz 
legen. Da sind Sprachfeatures wie Zeiger, Datenstrukturen, Unions und 
deren Verwendung hervorragend und mit Beispielen beschrieben. Das wird 
Dir einerseits dabei helfen, ein besserer C-Programmierer zu werden, 
andererseits aber auch, eventuell auftretende Probleme wie dieses besser 
zu beschreiben, wenn Du noch einmal Hilfe benötigen solltest.

HTH und viel Erfolg!

PS: Die Verwendung strukturierender Satzzeichen, zum Beispiel von 
Kommata, würde es wesentlich einfacher machen, Deine Texte zu verstehen.

von Hans89 (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Eric B. schrieb:
> Was sind in den Telegrammen dann diese "Type-ID" und "Command"?
> Wenn ein Telegramm empfangen wird, woher weisst du ob ExposeN,
> ExposeL oder ExposeD verschickt wurde?

die Variablen werden vom PC nach und nach gesendet bis die gesamte 
Struktur versendet wurde.
1
[Type]      [CMD-ID]        [VALUE]
2
3
  57          00 c8      00 00 00 00 91 (all Bytes in HEX)
4
5
1Byte         2Byte          5Byte
6
7
 
8
9
    #define UDI_HID_REPORT_OUT_SIZE 8
10
11
    uint8_t ucRxBuffer [UDI_HID_REPORT_OUT_SIZE];
12
13
    uint8_t ucTxBuffer1 [UDI_HID_REPORT_IN_SIZE];
14
15
    uint8_t ucArt;
16
17
    uint16_t ui16Adr;
18
19
    uint64_t ui64Val;
20
21
    typedef struct
22
    {
23
        uint8_t allowed;
24
        uint8_t zoomLevel;
25
26
       
27
28
        uint16_t motorChip;
29
        uint16_t motorOptic;
30
31
       
32
33
        uint8_t ledww;
34
        uint8_t ledkw;
35
        uint8_t ledred;
36
        uint8_t ledblue;
37
        
38
        uint16_t x;
39
        uint16_t y;
40
        
41
        uint16_t RESERVED;
42
        
43
           
44
        AttachmentSettings_t att_default;
45
        AttachmentSettings_t att_small;
46
        AttachmentSettings_t att_pol;
47
        AttachmentSettings_t att_pdd;
48
        
49
        //112 Bytes Total
50
        
51
    } ZoomSettings_t;
52
53
    ZoomSettings_t EEMEM EEPROMZoomSettings;
54
    ZoomSettings_t RAMZoomSettings;
55
56
    void HID_RX_TX(uint8_t *report)
57
    {
58
59
         //fill buffer with received data
60
        for (uint8_t i = 0; i < UDI_HID_REPORT_OUT_SIZE; i++)
61
        {
62
            ucRxBuffer [i] = report[i];       
63
        }   
64
65
       
66
67
        uint8_t get_art (void)
68
        {
69
            return ucRxBuffer[0];
70
        }    
71
        
72
        uint16_t get_adr (void)
73
        {
74
            uint16_t ui16Temp;
75
            
76
            ui16Temp  = ucRxBuffer [1];
77
            ui16Temp <<= 8;
78
            ui16Temp += ucRxBuffer [2];        
79
            
80
            return ui16Temp;
81
        }   
82
83
           
84
85
        uint64_t get_val(void)
86
        {
87
            uint64_t ui64Temp;
88
            
89
            ui64Temp =  ucRxBuffer [3];
90
            ui64Temp <<=8;
91
            ui64Temp |= ucRxBuffer [4];
92
            ui64Temp <<=8;
93
            ui64Temp |= ucRxBuffer [5];
94
            ui64Temp <<=8;
95
            ui64Temp |= ucRxBuffer [6];
96
            ui64Temp <<=8;
97
            ui64Temp |= ucRxBuffer [7];
98
            
99
            return ui64Temp;
100
        }
101
102
       
103
104
        ucArt = get_art();
105
        ui16Adr = get_adr();
106
        ui64Val = get_val();
107
108
      
109
110
        if (ucArt == 'W' /*0x57*/)
111
        { 
112
113
            switch (ui16Adr)
114
            {
115
116
                  case 200:                                                            
117
                                for (uint8_t i = 0; i < sizeof (ZoomSettings_t); i++)
118
                                {
119
                                     ucRxBuffer1[i] = ui64Val;
120
                                }
121
122
                                eeprom_update_block( (ZoomSettings_t*)ucRxBuffer1, &EEPROMZoomSettings, sizeof(ZoomSettings_t) ); 
123
124
            }
125
126
        }  
127
128
    }


Das Problem ist der Buffer denke ich weil jetzt steht im EEPROM der 
gesamte reservierte Bereich auf 0x91 (siehe Anhang) obwohl vom PC nur 
einmal der Wert gesendet wurde nach dem folgenden Datagram:

[Type]      [CMD-ID]       [VALUE]

  57          00 c8      00 00 00 00 91 (all Bytes in HEX)

1Byte        2Byte          5Byte

Wie kann ich den Buffer so aufbauen, dass alle Werte die Datagram für 
Datagram vom PC gesendet werden sich darin befindet.

Sodass ich danach das ganze ins EEPROM schreiben kann...

z.B.

Vom PC gesendet:

 [Type]      [CMD-ID]       [VALUE]

  57          00 c8      00 00 00 00 22 (all Bytes in HEX)
  57          00 c8      00 00 00 40 22 (all Bytes in HEX)
  57          00 c8      00 00 34 00 22 (all Bytes in HEX)
  57          00 c8      00 34 00 00 22 (all Bytes in HEX)
usw.......


jeweils nur Value extrahiert und im Buffer abgelegt dann den gesamten 
buffer ins EEPROM

EEPROM sollte dann enthalten: 00 00 00 00 22 00 00 00 40 22 00 00 34 00 
22 00 00 34 00 22


P.S. struct ist packed und aligned.

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Musst du wirklich Funktionen in Funktionen definieren?
Und wenn ja, warum?

von Eric B. (beric)


Bewertung
0 lesenswert
nicht lesenswert
Hans89 schrieb:
> z.B.
>
> Vom PC gesendet:
>
>  [Type]      [CMD-ID]       [VALUE]
>
>   57          00 c8      00 00 00 00 22 (all Bytes in HEX)
>   57          00 c8      00 00 00 40 22 (all Bytes in HEX)
>   57          00 c8      00 00 34 00 22 (all Bytes in HEX)
>   57          00 c8      00 34 00 00 22 (all Bytes in HEX)
> usw.......
>
> jeweils nur Value extrahiert und im Buffer abgelegt dann den gesamten
> buffer ins EEPROM
>
> EEPROM sollte dann enthalten: 00 00 00 00 22 00 00 00 40 22 00 00 34 00
> 22 00 00 34 00 22

Das ist einfach, und dafür brauchst du weder structs noch uint64_t oder 
sogar verschachtelte Funktionen.
1
uint32_t eepromAddress = 0;
2
3
void HID_RX_TX(uint8_t *report)
4
{
5
  if(report[0] == 'W' && report[1] == 0x00 && report[2] == 0xC8)
6
  {
7
    eeprom_write(eepromAddress, report + 3, 5);
8
    eepromAddress += 5;
9
  }
10
}

Ich bin mir aber ziemlich sicher dass das nicht ist was du willst ;-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.