Daten mit dem COM-Port verschicken
-
elsucht schrieb:
Wenn ich nun z.b. die Zahl -150.8 übertragen will, müsste ich also 6mal den ComWrite befehl aufrufen, eben mit dem ASCII-Code des Zeichens, richtig?
nö, vier mal. -150.8 passt in einen float. ein float ist 4 byte lang.
bei floats verschickst du auch keine ascii zeichen in dem sinne, sondern byteweise die binäre interpretation eines float datentypen.
wenn du nach IEEE 754 googelst, erfährst du mehr über das fließkomma-datenformat.elsucht schrieb:
messwerte[z][s] = Get_SpectrumPtr(s, 1); //ComWrite(comport,messwerte[z][s]); so einfach gehts ja nicht :P
stimmt.
elsucht schrieb:
Also in dem array Messwerte wird nun z.B. in [1][1] die Zahl -150.8 gespeichert. Hat jmd ne Idee, wie man die am besten verschicken könnte?
wenn du unterschiedliche datentypen verschicken willst, kannst du die daten in strukturen einpacken und auf der empfängerseite wieder in strukturen einlesen.
das ist denke ich mal, die einfachste möglichkeit, verschiedene datentypen zu verschicken.unten findest du ein beispiel fürs verschicken eines float-wertes. mit strukturen kannst du im prinzip genauso umgehen, dann nimmst du einen zeiger auf einen strukturpuffer anstelle eines float-puffers.
der 'sender' ist hier das main-programm, der 'empfänger' die unten stehende funktion.
void receiveFloat( char* p ) // Byteweise Empfangen { static int i = 0; static float fnum = 0.0; char* pf = (char*)&fnum; *(pf+i++) = *p; if ( i == sizeof(float) ) { printf("Received: %.3f\n", fnum ); } } int main(int argc, char *argv[]) { int i; float fnum = -150.8; char* p = (char*)&fnum; for ( i=0; i<sizeof(float); i++ ) // Byteweise Senden { receiveFloat(p+i); } return 0; }
have fun.
-
Hallo,
Das ist genau die Frage, die ich schon ganze Zeit suche. Aber ich kann ComTools kann ich leider nicht in meinem Visual Studio 2005 Version 2.0.50727 finden. Wo liegt dieses Tool? Danke
-
Hier kannst du dir das Zeugs ziehen.
-
Vielen Dank!
-
@agga ugga
besser spät als nie ein Danke für deine Hilfe.
Habe die ganze Übertragung mittlerweile erfolgreich implementiert, jedoch mit dem "einfach" Versenden als String-Zeichnkette.Also ungefähr so:for(int z=0, iLen=0; strcmp(rBuffer, "RECEND") != 0;iLen=ComRead(comport,rBuffer,6),z++) { for (int s=0; s<MaxS; s++) { _gcvt_s(xbuffer,_countof(xbuffer),Get_SpectrumPtr(s,1),6); //hole Spektrum(double) und convertiere nach char und schreibe in xbuffer ComWrite(comport,xbuffer,strlen(xbuffer)); //Zeichenkette xbuffer senden ComWrite(comport, 32); // Leer-Zeichen für Ende des double senden } ComWrite(comport, 13); // Return-Zeichen für Ende der 512 Übertragungen letzte=z; }
Jedoch habe ich nun das große Problem, dass die Übertragung viel zu langsam ist (hatte ich befürchtet). Will 512 double-Werte wie z.B. -150.5 verschicken(die Schleife wird 512mal durchlaufen), und das ca 50mal in der Sekunde. Mit meiner derzeitigen Methode sind das 6 Zeichen pro Zahl, mach mit Leer- und dem Returnzeichen ca. 3000 Bytes, eher weniger, da manchmal auch nur die bspw. "148" gesendet wird.
Ich suche nun eine optimierte Übertragung, womit ich einiges an Datenrate einsparen kann bzw sie für was anderes nutzen kann( die 512 Werte sollen möglichst oft in der Sekunde verschickt werden).
P.S. für sonstige Anmerkungen bzgl Verbesserung der Struktur wäre ich auch sehr dankbar. Für einen C++ Neuling bin ich eigentlich schon recht "zufrieden" mit meinem Programm.
-
Nun, die einfachste Variante ist natürlich die Baudrate zu erhöhen
Anderer Lösungsansatz:
Du schreibst zwar, Du verwendest float bzw. double, aber andererseits schreibst Du, Du überträgst max. 6 Zeichen für eine Zahl.Ich interpretiere der Einfachheit halber mal so: Dir genügt offensichtlich nur eine Nachkommastelle?
Dann verwende für die serielle Übertragung nur 16-Bit vorzeichenbehaftete Integer-Zahlen als Fixpunktzahlen. D.h. für jede Zahl benötigst Du nur noch 2 Bytes, und zwar so:16-Bit float- Integer Wert 9999 = 999.9 1000 = 100.0 4623 = 462.3 10 = 1.0 2 = 0.2 1 = 0.1 0 = 0.0 -1 = -0.1 -2 = -0.2 -1000 = -100.0 -9999 = -999.9
Damit sparst Du 4 Zeichen pro Zahl!
Die Limits für 16-Bit Integer Werte wären -32768 und +32767 (entsprechend float-Werte -3276.8 bis 3276.7).Martin
-
Mmacher schrieb:
Nun, die einfachste Variante ist natürlich die Baudrate zu erhöhen
Anderer Lösungsansatz:
Du schreibst zwar, Du verwendest float bzw. double, aber andererseits schreibst Du, Du überträgst max. 6 Zeichen für eine Zahl.Ich interpretiere der Einfachheit halber mal so: Dir genügt offensichtlich nur eine Nachkommastelle?
Dann verwende für die serielle Übertragung nur 16-Bit vorzeichenbehaftete Integer-Zahlen als Fixpunktzahlen. D.h. für jede Zahl benötigst Du nur noch 2 Bytes, und zwar so:16-Bit float- Integer Wert 9999 = 999.9 1000 = 100.0 4623 = 462.3 10 = 1.0 2 = 0.2 1 = 0.1 0 = 0.0 -1 = -0.1 -2 = -0.2 -1000 = -100.0 -9999 = -999.9
Damit sparst Du 4 Zeichen pro Zahl!
Die Limits für 16-Bit Integer Werte wären -32768 und +32767 (entsprechend float-Werte -3276.8 bis 3276.7).Martin
Danke für deinen Tipp. Mit der Realisierung würde ich dann wirklich sehr viel einsparen. Jetzt ist nur die Frage, wie ich das programmiertechnisch löse. Also der Comwrite() befehl verschickt ja die in einem string gespeicherten Zeichen hintereinander weg. Ich hatte das bisher so, dass ich die doubles (genau!,mit einer Nachkommastelle) in einen string konvertiert hab. Diese wurden anschließend verschickt.
Jetzt müsste ich, sofern ich es richtig verstanden habe, meine double werte zu einem Integer machen, davon den Binärcode bestimmen und den Übertragen.Gibt es eine Winapi-Funktion o.ä. mit der ich auf die serielle Schnittstelle zugreifen kann? dieses ComTools scheint mir für meine Bedürfnisse nicht geeignet zu sein.
P.S. die Baudrate steht auf maximum :p
-
Mmacher schrieb:
Ich interpretiere der Einfachheit halber mal so: Dir genügt offensichtlich nur eine Nachkommastelle?
Dann verwende für die serielle Übertragung nur 16-Bit vorzeichenbehaftete Integer-Zahlen als Fixpunktzahlen. D.h. für jede Zahl benötigst Du nur noch 2 Bytes, und zwar so:hab da grad nen spontanen Einfall zur Konvertierung. bitte nicht auf die Syntax achten, muss C++ und Matlab gleichzeitig programmieren
float zahl=3.1; int zahl2=zahl*10;
-
elsucht schrieb:
float zahl=3.1; int zahl2=zahl*10;
Das Prinzip ist schon korrekt, ABER:
Verwende unbedingt einen Integer-Typen, der tatsächlich 16 Bit breit ist, ansonsten hast Du Konvertierungsfehler bei negativen Zahlen!
Wir wollen ja schließlich von der Zahl das Low- und High-Byte zum Übertragen an die serielle Schnittstelle verwenden.Welcher int-Typ tatsächlich 16 Bit breit ist, kann von Compiler zu Compiler unterschiedlich sein, deshalb immer in der zugehörigen Doku nachlesen.
Am Beispiel von Visual C++ ist sind die folgenden Typen dafür geeignet:
__int16 short short int signed short int
Alle diese Typen haben einen Wertebereich von -32768 bis +32767.
Martin
-
ok, also die Kovertierung sollte kein Problem mehr sein. Stellt sich nur die Frage, wie realisiere ich die Versendung über die RS232-Schnittstelle. Für Tipps wäre ich sehr dankbar...
-
...sagen wir zahl2 ist jetzt ne 16bit integer zahl.
Kann ich mit
char zahl3[]=zahl2
direkt den string erstellen, den ich mit Comwrite versenden kann?
Also aus z.B. dem double 1234.5 wird erst ein int16 12345 .
int16 sind ja 16bit. Baut mir die Zeile oben jetzt einen char[]="12345" oder baut es mir den "nutzbaren" char[2]="%$", oder welche beiden Zeichen auch immer entstehen würden.
Kurz gefragt, wie bekomme ich aus der 16bit-Integerzahl 2 ASCII Zeichen?
-
Probiers mal mit der io.dll. Google nanach...
Import (in Delphi .. Sorry bin C Neuling):
//-- IO.DLL import -----------------------------------------------------------// // PortOut // Outputs a byte to the specified port. procedure PortOut(Port : Word; Data : Byte); stdcall; external 'io.dll'; // PortWordOut // Outputs a word (16-bits) to the specified port. procedure PortWordOut(Port : Word; Data : Word); stdcall; external 'io.dll'; // PortDWordOut // Outputs a double word (32-bits) to the specified port. procedure PortDWordOut(Port : Word; Data : DWord); stdcall; external 'io.dll'; // PortIn // Reads a byte from the specified port. function PortIn(Port : Word) : Byte; stdcall; external 'io.dll'; // PortWordIn // Reads a word (16-bits) from the specified port. function PortWordIn(Port : Word) : Word; stdcall; external 'io.dll'; // PortDWordIn // Reads a double word (32-bits) from the specified port. function PortDWordIn(Port : Word) : DWord; stdcall; external 'io.dll'; // SetPortBit // Sets the bit of the specified port. procedure SetPortBit(Port : Word; Bit : Byte); stdcall; external 'io.dll'; // ClrPortBit // Clears the bit of the specified port. procedure ClrPortBit(Port : Word; Bit : Byte); stdcall; external 'io.dll'; // NotPortBit // Nots (inverts) the bit of the specified port. procedure NotPortBit(Port : Word; Bit : Byte); stdcall; external 'io.dll'; // GetPortBit // Returns the state of the specified bit. function GetPortBit(Port : Word; Bit : Byte) : WordBool; stdcall; external 'io.dll'; // RightPortShift // Shifts the specified port to the right. The LSB is returned, and the value passed becomes the MSB. function RightPortShift(Port : Word; Val : WordBool) : WordBool; stdcall; external 'io.dll'; // LeftPortShift // Shifts the specified port to the left. The MSB is returned, and the value passed becomes the LSB. function LeftPortShift(Port : Word; Val : WordBool) : WordBool; stdcall; external 'io.dll'; // IsDriverInstalled // Returns non-zero if io.dll is installed and functioning. The primary purpose of this function is to ensure that the kernel mode driver for NT/2000/XP has been installed and is accessible. function IsDriverInstalled : Boolean; stdcall; external 'io.dll';
-
habe da noch eine Frage zum Konvertieren...ich habe jetzt die int16 Zahl und würde diese gerne aufspalten in das obere und untere Byte, um danach die 2 zugehörigen chars zu bekommen.
Mit dem befehl (chars)(65) kann man sich ja dann z.B. sich das entstprechende ASCII codierte Zeichen holen. (ComWrite() läuft mit auch mit "Conwrite(65)")
Wie komme ich nun am einfachsten von meiner 2-Byte Integer auf 2-mal 1-Byte Char?
-
High-Byte : (int16 && 0xFF00)>>8 /( Shift Right 8 )/
Low-Byte : (int16 && 0x00FF)