Hallo Forumgemeinde,
ich habe ein Problem mit meine „struct’s“ und „union’s“ Ich erkläre kurz
worum es geht. Ich habe einen µC der serielle Daten (UART) an einen 2.
µC senden soll. Am 2. µC hängt ein G-LCD. Die Befehle des G-LCD’s haben
unterschiedliche Übergabe-Parameter. Ich habe im 1. µC eine
include-Datei mit dem Namen „Applikation“ In dieser Datei gibt es mehrer
struct’s die die unterschiedlichen Übergabe-Parameter abbilden. In einer
Union sind dann die erwähnten Funktionen für den 2. µC.
/****** Typ deklarationen *****************************************/
typedef struct
{
U8 dummy;
}no_data_t;
typedef struct
{
U8 single;
}one_byte_t;
typedef struct
{
U8 first;
U8 second;
}two_byte_t;
typedef struct
{
U16 single;
}one_int_t;
typedef struct
{
U16 first_16;
U16 second_16;
U16 third_16;
U8 first_8;
}three_int_one_byte_t;
typedef struct
{
U16 first_16;
U16 second_16;
U16 third_16;
U16 fourth_16;
U8 first_8;
}four_int_one_byte_t;
typedef union
{
two_byte_t set_cursor;
two_byte_t set_offset;
two_byte_t set_address_xy;
one_int_t set_address;
one_int_t set_text;
one_byte_t text_area;
one_byte_t set_graphic;
one_byte_t graphic_area;
one_byte_t set_mode;
one_byte_t display_mode;
one_byte_t cursor_line;
no_data_t init;
no_data_t clear_text;
no_data_t clear_graph;
no_data_t put_char;
four_int_one_byte_t set_pixel;
four_int_one_byte_t line;
three_int_one_byte_t circle;
three_int_one_byte_t half_circle;
four_int_one_byte_t box;
}control_u;
typedef struct
{
U16 sof;
U8 laenge;
U8 command;
control_u u;
}puffer_t;
puffer_t buf; // Erzeugung des Buffers
/***********************************************/
Mein Problem ist jetzt, ich schaffe es nicht eine Funktion zu erstellen,
die byteweise den Buffer über UART versendet. Mir ist schon klar das man
dies mit Zeiger machen muss, aber wie??
Es müsste so irgendwie aussehen: (ich weiß das die Funktion so nicht
funktioniert)
//Sendefunktion//
void send_buffer(puffer_t *p,U8 laenge)
{
U8 *pc = p;
while(!(laenge == 0))
{
Uart_putchar(*pc);
pc++;
laenge--;
}
}
//Funktionsaufruf//
send_buffer(buf,buf.laenge);
Ich suche eine Möglichkeit die Anfangsadresse des Buffers zu bekommen
und dann mit einem Zeiger, byteweise die Daten über UART senden. Ich
weiß nicht mehr weiter. Kann mir jemand weiter helfen??
Mit den besten Grüßen,
Marcel
Hallo Yagan,
danke für deine Antwort.
Ich habe jetzt die Funktion so umgeschrieben:
//////////////////////
void send_buffer(U8 *pbyte,U8 laenge)
{
while(!(laenge == 0))
{
send_data(*pbyte++);
laenge-=1;
}
}
///////////////////////
Das funktioniert jetzt auch ohne Fehler!
Allerdings der Funktionsaufruf gibt mir einen Fehler! Ich übergebe für
den 2. Parameter zum testen auch erst mal nur ne 1 damit dieser Fehler
ausgeschlossen wird. Der Fehler liegt also beim 1. Übergabeparameter.
//////////////////////
send_buffer((U8 *)buf,1);
/////////////////////
Woran liegt das??
Viele Grüße, Marcel
AAAACHTUNG: Enum deklarieren ist gut und schön, aber die Enum dann bitte
nich als als Datentyp verwenden, weil die Standardmäßig (meine ich
grübel) vier Bytes belegen.
> Allerdings der Funktionsaufruf gibt mir einen Fehler! Ich übergebe für> den 2. Parameter zum testen auch erst mal nur ne 1 damit dieser Fehler> ausgeschlossen wird. Der Fehler liegt also beim 1. Übergabeparameter.> //////////////////////> send_buffer((U8 *)buf,1);> /////////////////////> Woran liegt das??
Hm, wie sieht die Fehlermeldung aus?
Sven Pauli wrote:
> AAAACHTUNG: Enum deklarieren ist gut und schön, aber die Enum dann bitte> nich als als Datentyp verwenden, weil die Standardmäßig (meine ich> grübel) vier Bytes belegen.
Nicht beim AVR, so viel ich weiß. Zumindest gibts dafür ne
Compiler-Option: -fshort-enums. Wichtig ist auch -fpack-struct.
Danke für eure Antworten!!!
@Manuel
im Funktionsaufruf:
call_rpc(RPC_set_cursor, &p, sizeof(PARAM_set_cursor));
stimmt doch der 3. Übergabewert nicht, oder??
Die Funktion erwartet doch ein U8??
@Yagan
ich bekomme bei der Funktion "send_buffer((U8 *)buf,1);" die
Fehlermeldung: (Benutze IAR)
Error[Pe171]: invalid type conversion
Wieso übergibst du in deinem Funktionsaufruf als 2. Parameter:
sizeof(puffer_t) wenn du in der Funktion allerdings ein U8 erwartest?
Hmm, ich denke da habe ich bei euch beiden etwas nicht so richtig
verstanden!! (C- Verständnisproblem)
Yagan z. Dongobar wrote:
> Ach ja, da fehlt noch eine Klammer:>> send_buffer( (U8 *)buf, sizeof(puffer_t) );>> So müsste es gehen.
Nein! buf ist noch kein Zeiger.
send_buffer( (U8*)&buf, sizeof(puffer_t) );
Marcel,
ich möchte Dich bitten, von dieser Vorgehensweise gänzlich abzugehen.
Datenstrukturen in C sind in ihrem inneren Aufbau IMMER vom verwendeten
Compiler abhängig. Ein Compiler kann solche lustigen Dinge machen wie:
- Datenstrukturen in ihrer Größe auf ganze Maschinenworte aufweiten.
- Elemente der Datenstrukturen umsortieren, damit sie sich besser packen
lassen.
- Mehrbyte-Werte können Big Endian oder Little Endian sein.
Das macht C-Datenstrukturen grundsätzlich ungeeignet, um als Basis für
die Kommunikation zu anderen Rechnern zu dienen. Ganz besonders lustig
wird es, wenn Du z.B. Deinen Compiler updatest und der neue sortiert die
Datenstrukturen anders.
Wen ich in meinem Bereich dabei erwische, wie er so programmiert,
bekommt was auf die Finger!
Ich würde Dir raten, die Kommunikation in Einheiten von Bytes zu
definieren, auch wenn es erstmal mehr Aufwand ist.
Gruß
Wolfgang
Sven Pauli wrote:
> AAAACHTUNG: Enum deklarieren ist gut und schön, aber die Enum dann bitte> nich als als Datentyp verwenden, weil die Standardmäßig (meine ich> grübel) vier Bytes belegen.
Enums verwenden standardmäßig den Datentypen int als Speicher. Der ist
bei AVR-GCC 2 Byte groß. Die Sache mit fshort-enums wurde ja schon
genannt.
Wolfgang Mües wrote:
> Ich würde Dir raten, die Kommunikation in Einheiten von Bytes zu> definieren, auch wenn es erstmal mehr Aufwand ist.
Da hat der gute Wolfgang nicht ganz unrecht. Es gibt ne Menge Dinge zu
beachten bei sowas.
Marcel,
mit sizeof(puffer_t) berechnet der Compiler die Länge des Typs
'puffer_t' in Bytes. Das Ergebnis ist eine konstante Zahl, die eventuell
in ein 'U8' passt.
> send_buffer((U8 *)buf,1)
Wo hier eine 'invalid type conversion' sehe ich momentan nicht.
Wolfgang Mües wrote:
>> Ich würde Dir raten, die Kommunikation in Einheiten von Bytes zu> definieren, auch wenn es erstmal mehr Aufwand ist.
Schreib doch mal ein Codebeispiel.
Mit dem GCC und dem C166 hatte ich noch nie Probleme...
Yagan z. Dongobar wrote:
> Marcel,>> mit sizeof(puffer_t) berechnet der Compiler die Länge des Typs> 'puffer_t' in Bytes. Das Ergebnis ist eine konstante Zahl, die eventuell> in ein 'U8' passt.>>> send_buffer((U8 *)buf,1)> Wo hier eine 'invalid type conversion' sehe ich momentan nicht.
Hab ich doch schon geschrieben, buf ist kein Zeiger!
Noch mal Danke für eure fleißigen Antworten!!!!
@Manuel
Also jetzt funktioniert alles! Ich bekomme über UART genau das gesendet
was ich wollte! Danke ertsmal für deine Hilfe.
Jetzt komme ich zu Wolfgang. :o)
Also wenn ich dich richtig verstanden habe, meinst du dass ich alle
Werte in ein Array von U8 anlegen soll. Auch die Int Werte sollten als
high und low byte abgespeichert werden.
So richtig verstanden?
Viele Grüße, Marcel
Hallo zusammen,
ich habe noch eine Frage wie ich den meinen „Buffer“ füllen kann. Ich
weiß ich könnte z.B. schreiben:
buf.u.set_cursor.first = 4;
Das funktioniert auch. Ich würde allerdings gerne mit einem Zeiger auf
den Buffer zugreifen. Es soll eine Funktion geben die byteweise in den
Buffer schreibt und dann immer um eins erhöht wird. Ich habe es schon so
probiert:
U8 *zeiger;
*zeiger = &buf;
Allerdings funktioniert das so nicht. Was mach ich den falsch?
Viele Grüße,
Marcel
Marcel,
wie Wolfgang schon dargelegt hat, ist die Methode eine Struktur in
binärer Form byteweise über die serielle Schnittstelle zu übertragen,
schlechter Programmierstil und kann problematisch werden.
Besser ist es ein 'Protokoll' zu definieren, das jedem übertragenen Byte
eine bestimmte Funktion zuordnet, z.B. die Funktion
'SetCursor(Zeile,Spalte)'
erzeugt drei Bytes:
1. Byte = Code für Kommando SetCursor,
2. Byte = Wert für Zeile,
3. Byte = Wert für Spalte.
etwa so:
1
#include<string.h>
2
#define SETCURSOR 0x01 // Kommandocode für SetCursor.
3
4
U8buffer[20];// String der Länge maximal 20 Bytes.
5
6
voidSetCursor(U8zeile,U8spalte)
7
{
8
buffer[0]=SETCURSOR;
9
buffer[1]=zeile;
10
buffer[2]=spalte;
11
buffer[3]=0;// Endemarke für String setzen.
12
send_buffer(buffer,strlen(buffer));
13
}
14
15
// Beispiel: Setze Cursor in Zeile 1 und Spalte 2:
16
17
SetCursor(1,2);
Das ist jetzt ein ganz einfaches Beispiel um die Vorgehensweise
anzudeuten.
Möglicherweise passt es nicht ganz zu dem bisherigen Konzept, lässt sich
aber leicht anpassen.
Ciao, Yagan
Hallo Yagan,
ja ich habe am Anfang das ganze auch so gehabt. Es gibt aber Funktionen
die nicht nur zwei Byte benötigen (Cursor x,y) sondern auch Funktionen
die integer benötigen. Z.B. „set_address(int address)“ Ich habe auch
Funktionen die z.B. zwei Byte und zwei Integer erwarten. Deshalb wollte
ich das ganze mit Strukturen machen da ich beim Empfangen des Buffers
nur noch die Struktur als Maske über den Buffer legen muss und kann dann
direkt die Werte über die Struktur heraus lesen. So wie du das erklärt
hast, habe ich es am Anfang auch gehabt, aber gerade bei integer-Werten
muss man dann mir zwischenvariablen arbeiten (int = empfang>>8) und dann
(int = %256 empfang) (so irgendwie habe ich das gemacht, bin jetzt nicht
zu Haus aber es hat funktioniert)
Auf jeden Fall dachte ich mir das es über Strukturen viel sauberer zu
lesen ist.
Mein erstes Problem war ja, dass ich einen gefüllten Buffer byteweise
senden wollte. Jetzt möchte ich empfangene Bytes in den Buffer
schreiben. Allerdings mit einem Zeiger der auf die Anfangsadresse des
Buffers zeigt.
Ich bin über die Antwort von Wolfgang dankbar. Und ich kann mir ganz gut
vorstellen das es beim importieren in andere Compiler Probleme geben
kann. Ich finde aber auch dass das byteweise senden wirklich nicht sehr
gut für die Lesbarkeit zu erkennen ist.
Würdet Ihr wirklich das ganze byteweise versenden?? Gibt es denn keine
andere, gut lesbare Möglichkeit?
Bin über jeden Vorschlag dankbar!
Schönen Tag noch und viele Grüße,
Marcel
Alles klar, ich hab's jetzt hinbekommen. Für diejenigen die es
interessiert:
unsigned char *zeiger = (unsigned char*) &buf;
Danke für eure Mühe!!!
Marcel
Marcel,
gegen die Datenstrukturen ist nichts einzuwenden, problematisch ist nur
die Art des 'streaming' über die serielle Schnittstelle.
Deine Methode funktioniert nur wenn auf Sender- und Empfängerseite
absolut gleiche Bedingungen herrschen, also gleicher Compiler, gleiche
Version, gleicher Prozessor.
Das macht die Angelegenheit unflexibel.
Wenn du z.B. zum Test auf der Empfängerseite zunächst einen PC benutzen
willst, ist das Verfahren schon ungeeignet, wogegen die Datenübertragung
nach einem festgelegten Protokoll immer (platformunabhängig)
funktioniert.
Das Beispiel für set_address könnte dann so aussehen:
'set_address(Adresse)'
erzeugt drei Bytes:
1. Byte = Code für Kommando SetAdress,
2. Byte = unteres (Low) Byte von Adresse,
3. Byte = oberes (High) Byte von Adresse.
in C etwa so:
1
#define SETADDRESS 0x02 // Kommandocode für SetAddress.
2
#define SETADDRESS_FRAME 3 // Länge des SetAdresss-Frames.
3
4
U8buffer[20];// Sendepuffer der Länge maximal 20 Bytes.
Eine eigene Frage?
Dieser Thread ist über 18 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.