Forum: Compiler & IDEs Wie bekommt man eine double Variable in ein char Array?
Hallo,
Ich schon wieder. Wie oben schon beschrieben bekomme ich es nicht hin in
ein char Array eine double/float Variable hineinzubringen.
Hier mal der Versuch: 1 | static char spi_buf[32];
| 2 |
| 3 | void sendDouble(double n )
| 4 | {
| 5 | spi_buf[0] = n>>24;
| 6 | spi_buf[1] = n>>16;
| 7 | spi_buf[2] = n>>8;
| 8 | spi_buf[3] = n;
| 9 | }
|
Was mach ich da falsch? Hat das was mit casten zu tun?
Steffen
Steffen H. schrieb:
1 | static char spi_buf[32];
| 2 |
| 3 | void sendDouble(double n )
| 4 | {
| 5 | memcpy(spi_buf, &n, sizeof(double));
| 6 | }
|
So sollte es gehen...
Ansonsten dein n mal auf
char * ptr = (char*) &n;
casten, dann müsste auch
spi_buf[0] = ptr[3];
funktionieren, aber memcpy ist einfacher...
mfg Andreas
Lass doch die libc die Arbeit machen:
1 | #include <string.h>
| 2 |
| 3 | ...
| 4 |
| 5 | memcpy(spi_buf, &n, sizeof(double));
|
Steffen H. schrieb:
> static char spi_buf[32];
Wozu 32 chars?
Danke für die Anworten.
Mit memcpy funktioniert das auch, aber ich habe vorher noch eine
Berechnung und will dann die berechneten double/Floats hintereinander in
das spi_buf Array schreiben. Deswegen der gescheiterte Klimmzug über
die Funktion sendDouble. Also ich versuchs konkreter zu erklären durch
mehr code.
Variablen: 1 | static char spi_buf[32];
| 2 | typedef struct {
| 3 | int32_t position[3]; // Real-time machine position vector in steps.
| 4 | uint8_t coord_select; // Active work coordinate system number.
| 5 | double coord_offset[3]; // G92 coordinate offset (work coordinates)
| 6 | } system_t;
| 7 | extern system_t sys;
|
Hier sollen die 3 Positionsdaten in den spi_buf nacheinander gespeichert
werden, damit sie dann per SPI (interrupted) verschickt werden können. 1 | void send_status_report()
| 2 | {
| 3 | double stepper_position[3];
| 4 | memcpy(stepper_position,sys.position,sizeof(sys.position));
| 5 |
| 6 | sendDouble(stepper_position[X_AXIS])/(settings.steps_per_mm[X_AXIS]));
| 7 | sendDouble(stepper_position[Y_AXIS])/(settings.steps_per_mm[Y_AXIS]));
| 8 | sendDouble(stepper_position[Z_AXIS])/(settings.steps_per_mm[Z_AXIS]));
| 9 | }
|
Hier muss dann natürlich noch der Zähler für die Position im Array mit
der Funktion mitgeliefert und von der aufrufenden übergeben werden. 1 | void sendDouble(double n )
| 2 | {
| 3 | spi_buf[0] = n>>24;
| 4 | spi_buf[1] = n>>16;
| 5 | spi_buf[2] = n>>8;
| 6 | spi_buf[3] = n;
| 7 | }
|
allerdings klappt es so nicht.
Tom M. schrieb:
> Wozu 32 chars?
Ist der maximal zu erwartende spi transfer.
Steffen
Steffen H. schrieb:
> Ist der maximal zu erwartende spi transfer.
>
>
> Steffen
memcpy(spi_buf+pos*sizeof(double), &n, sizeof(double));
Wobei pos 0 ... sizeof(spi_buf) / sizeof(double).
Vergiss das Shiften, ist so einfacher, natürlich musst du pos
entsprechend hochzählen bei jedem Senden.
mfg Andreas
Andreas B. schrieb:
> Wobei pos 0 ... sizeof(spi_buf) / sizeof(double).
>
> Vergiss das Shiften, ist so einfacher, natürlich musst du pos
> entsprechend hochzählen bei jedem Senden.
Heißt das ich nach jedem Aufruf 1 | sendDouble(stepper_position[X_AXIS])/(settings.steps_per_mm[X_AXIS]));
|
irgendwie Pos hochzählen muss? So etwa?
1 | uint8_t pos=0;
| 2 |
| 3 | sendDouble(stepper_position[X_AXIS])/(settings.steps_per_mm[X_AXIS]),pos);
| 4 | pos += sizeof(double);
| 5 | sendDouble(stepper_position[Y_AXIS])/(settings.steps_per_mm[X_AXIS]),pos);
| 6 | ..
|
Und in der Funktion sendDouble dann: 1 | void sendDouble(double n, uint8_t pos)
| 2 | {
| 3 | memcpy(spi_buf+pos*sizeof(double), &n, sizeof(double));
| 4 | }
|
Sollte es so gehen?
Gruß Steffen
Steffen H. schrieb:
sendDouble(stepper_position[Y_AXIS])/(settings.steps_per_mm[X_AXIS]),pos
);
> ..
> [/c]
>
> Und in der Funktion sendDouble dann:
> 1 | > void sendDouble(double n, uint8_t pos)
| 2 | > {
| 3 | > memcpy(spi_buf+pos*sizeof(double), &n, sizeof(double));
| 4 | > }
| 5 | >
|
> Sollte es so gehen?
Wenn du hier mit sizeof(double) multiplizierst, dann brauchst du pos
aussen nicht mit sizeof(double) erhöhen. Du hast doch die Abstände schon
in der Multiplikation berücksichtigt.
Wenn du jeweils 5 SChachteln in Folge (in einer Sequenz) aufstellst, wo
steht dann die erste Schachtel der 6-ten Sequenz?
Die steht in der 6*5 = 30-ten Position,
sizeof liefert dir einfach nur die Größe des angegebenen in Bytes.
Karl Heinz Buchegger schrieb:
> Wenn du hier mit sizeof(double) multiplizierst, dann brauchst du pos
> aussen nicht mit sizeof(double) erhöhen. Du hast doch die Abstände schon
> in der Multiplikation berücksichtigt.
Stimmt, so gehts natürlich auch. Hab ich ja voll übersehen. Aber pos
muss ich außen ja trotzdem erhöhen. Dann allerdings nur um 1. (pos++;)
Würde mich jetzt mal interessieren, welche der beiden Varianten hier
mehr Resourcen verbraucht.
Ich sehe gerade, ich hab es jetzt eh etwas anders gelöst. Aber es
funktioniert. 1 | void send_status_report()
| 2 | {
| 3 | uint8_t pos=0;
| 4 | double stepper_position[3];
| 5 | memcpy(stepper_position,sys.position,sizeof(sys.position));
| 6 |
| 7 | sendDouble((stepper_position[X_AXIS]/(settings.steps_per_mm[X_AXIS])), pos);
| 8 | pos += sizeof(double);
| 9 | sendDouble((stepper_position[Y_AXIS]/(settings.steps_per_mm[Y_AXIS])), pos);
| 10 | pos += sizeof(double);
| 11 | sendDouble((stepper_position[Z_AXIS]/(settings.steps_per_mm[Z_AXIS])), pos);
| 12 | spi_write_data(spi_buf,11,CS_EXT);
| 13 |
| 14 | }
| 15 |
| 16 |
| 17 | void sendDouble(double n, uint8_t i )
| 18 | {
| 19 | char * ptr = (char*) &n;
| 20 |
| 21 | spi_buf[i++] = ptr[3];
| 22 | spi_buf[i++] = ptr[2];
| 23 | spi_buf[i++] = ptr[1];
| 24 | spi_buf[i++] = ptr[0];
| 25 | }
| 26 |
| 27 |
| 28 | // write one or multiple bytes to the Serial SPI memory
| 29 | void spi_write_data(char* source, char wr_bytes, char cs_adr)
| 30 | {
| 31 | spi_busy = true;
| 32 | nb_byte = wr_bytes;
| 33 | byte_cnt = 0;
| 34 | data_ptr = source;
| 35 | set_spi_cs(cs_adr); // Pull down the chip select line of the SPI device
| 36 | SPDR = *data_ptr; // send the first byte
| 37 | }
| 38 |
| 39 |
| 40 | // Interrupt Routine Master Mode (interrupt controlled)
| 41 | ISR(SPI_STC_vect)
| 42 | {
| 43 | data_ptr++; // point to the next byte (even if it was the last)
| 44 |
| 45 | if (byte_cnt == nb_byte ) // is the last byte sent?
| 46 | {
| 47 | PORTB &= ~(CS_MASK);
| 48 | PORTB |= CS_HI; // Pull high the chip select line of the SPI device
| 49 | spi_busy = false; // return to the idle state
| 50 | }
| 51 | else
| 52 | {
| 53 | byte_cnt ++;
| 54 | SPDR = *data_ptr;
| 55 | }
| 56 | }
|
Dank an all den freundlichen Helfern.
Gruß Steffen
Widersteh der Versuchung zu 'künsteln'. Die einfachste Variante ist die
beste.
1 | void send_status_report()
| 2 | {
| 3 | double stepper_position[3];
| 4 |
| 5 | stepper_position[X_AXIS] = sys.position[X_AXIS] / settings.steps_per_mm[X_AXIS];
| 6 | stepper_position[Y_AXIS] = sys.position[Y_AXIS] / settings.steps_per_mm[Y_AXIS];
| 7 | stepper_position[Z_AXIS] = sys.position[Z_AXIS] / settings.steps_per_mm[Z_AXIS];
| 8 |
| 9 | memcpy( spi_buf, stepper_position, sizeof(stepper_position) );
| 10 |
| 11 | spi_write_data(spi_buf, 11, CS_EXT);
| 12 | }
|
Bist du sicher, dass die 11 zum Schluss korrekt sind?
Wenn das eigentlich 12 sein sollten (wegen 3*sizeof(double) == 12), dann
noch besser so
1 | void send_status_report()
| 2 | {
| 3 | double stepper_position[3];
| 4 |
| 5 | stepper_position[X_AXIS] = sys.position[X_AXIS] / settings.steps_per_mm[X_AXIS];
| 6 | stepper_position[Y_AXIS] = sys.position[Y_AXIS] / settings.steps_per_mm[Y_AXIS];
| 7 | stepper_position[Z_AXIS] = sys.position[Z_AXIS] / settings.steps_per_mm[Z_AXIS];
| 8 |
| 9 | spi_write_data( (unsigned char*)stepper_position, sizeof(stepper_position), CS_EXT);
| 10 | }
|
Karl Heinz Buchegger schrieb:
> Bist du sicher, dass die 11 zum Schluss korrekt sind?
> Wenn das eigentlich 12 sein sollten (wegen 3*sizeof(double) == 12
Ja, das ist schon richtig so. Denn in der spi_write_data wird ja schon
1Byte an SPDR übergeben. Und somit fehlt eins zum countern in der ISR.
Danke für die Hilfe.
Steffen
Steffen H. schrieb:
> Karl Heinz Buchegger schrieb:
>> Bist du sicher, dass die 11 zum Schluss korrekt sind?
>> Wenn das eigentlich 12 sein sollten (wegen 3*sizeof(double) == 12
> Ja, das ist schon richtig so. Denn in der spi_write_data wird ja schon
> 1Byte an SPDR übergeben. Und somit fehlt eins zum countern in der ISR.
ui.
Solche Sachen sollte die spi_write_data selber regeln.
Du übergibst 12 Bytes an die Funktion. Die Funktion stellt eines in SPDR
und 11 in einen Buffer.
Das ist das, was man erwarten würde: Ich habe 12 Bytes und das sage ich
auch genau so der Funktion. Wie die Funktion das dann intern regelt, das
ist Sache der Funktion - das geht mich als Aufrufer nichts an. Ich weiß
nur, dass ich 12 Bytes auf die Reise bringen will, und das teile ich
auch der Funktion so mit.
Sowas sind typische Stolpersteine über die du in ein paar Wochen mehr
als einmal stolpern wirst. Gestalte Funktionalitäten nach Möglichkeit
immer so, dass sie FÜR DEN AUFRUFER(!) logisch sind. Denn der muss damit
klar kommen und je weniger Spezial- und Sonderfälle man beim Aufruf
einer Funktion wissen bzw. unterscheiden muss, desto weniger läuft man
Gefahr dabei einen Fehler zu machen. Und Fehler macht man als
Programmierer - du genauso wie ich.
Steffen H. schrieb:
> Was mach ich da falsch? Hat das was mit casten zu tun?
Um das auch noch mal aufzunehmen: Beantworte dir die Frage doch selber,
zur Not auch mit Hilfe (d)eines C-Buches. Der Lerneffekt daraus wird
dein Verständnis zu Datentypen in C erheblich erweitern.
Oliver
Karl Heinz Buchegger schrieb:
> Solche Sachen sollte die spi_write_data selber regeln.
> Du übergibst 12 Bytes an die Funktion. Die Funktion stellt eines in SPDR
> und 11 in einen Buffer.
So hab ich es jetzt gemacht. War nur eine kleine Änderung in der
spi_write_data .
Steffen
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|