Now how to feed your data from solver (assuming Windows PC) into MCU?
The easiest way is use RS232 but for that you need voltage converter like MAX232 (your MCU board probably has it or it use some USB chip as USB2RS232 converter in TTL voltages like FTDI or another small MCU).
So what you should do is to write a parser that take in your file (or stream or what ever) on PC side (can be the same executable where you solve) convert the commands to single char U,D,L,R,F,B
style and send that to RS232.
The same can be done with USB but that is magnitude more complicated due to need for drivers and much much more on both PC and MCU side which is not a good idea to start with for a rookie.
In windows you simply open file like COM1
set its properties and read/write your stuff from/to it (the same way like it would be a file). Here is a small Win32 C++/VCL lib port.h
I wrote ages ago for stuff like this:
//---------------------------------------------------------------------------
//--- port class ver: 2.0 ------------------------------------------------
//---------------------------------------------------------------------------
#ifndef _port_h
#define _port_h
//---------------------------------------------------------------------------
class port
{
public: HANDLE hnd;
DWORD error;
DWORD rlen,wlen;
DCB rs232_state;
COMMPROP properties;
COMMTIMEOUTS timeouts;
COMSTAT stat;
port();
~port();
int open(AnsiString name);
void close();
int get_stat(); // err,stat
int get_timeouts(); // timeouts
int set_timeouts();
int get_properties(); // properties
int get_rs232_state(); // rs232_state
int set_rs232_state();
void rst_rs232_state();
void out(BYTE data) { WriteFile(hnd,&data,1,&wlen,NULL); }
void in (BYTE *data) { ReadFile (hnd, data,1,&rlen,NULL); }
void in (char *data) { ReadFile (hnd, data,1,&rlen,NULL); }
void out(BYTE *data,DWORD len) { WriteFile(hnd,data,len,&wlen,NULL); }
void in (BYTE *data,DWORD len) { ReadFile (hnd,data,len,&rlen,NULL); }
};
//---------------------------------------------------------------------------
port::port()
{
rlen=0;
wlen=0;
error=0;
hnd=(void*)0xFFFFFFFF;
rst_rs232_state();
}
//---------------------------------------------------------------------------
port::~port()
{
close();
}
//---------------------------------------------------------------------------
int port::open(AnsiString name)
{
close();
error=0;
rlen=0;
wlen=0;
hnd=CreateFile( name.c_str(),GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_ALWAYS,0,NULL);
error=GetLastError();
if ((DWORD)hnd==0xFFFFFFFF) return 0;
get_timeouts();
get_properties();
get_rs232_state();
timeouts.ReadIntervalTimeout;
timeouts.ReadTotalTimeoutMultiplier;
timeouts.ReadTotalTimeoutConstant;
timeouts.WriteTotalTimeoutMultiplier;
timeouts.WriteTotalTimeoutConstant;
properties.wPacketLength;
properties.wPacketVersion;
properties.dwServiceMask;
properties.dwReserved1;
properties.dwMaxTxQueue;
properties.dwMaxRxQueue;
properties.dwMaxBaud;
properties.dwProvSubType;
properties.dwProvCapabilities;
properties.dwSettableParams;
properties.dwSettableBaud;
properties.wSettableData;
properties.wSettableStopParity;
properties.dwCurrentTxQueue;
properties.dwCurrentRxQueue;
properties.dwProvSpec1;
properties.dwProvSpec2;
properties.wcProvChar[1];
return 1;
}
//---------------------------------------------------------------------------
void port::close()
{
if ((DWORD)hnd==0xFFFFFFFF) return;
CloseHandle(hnd);
error=GetLastError();
hnd=(void*)0xFFFFFFFF;
}
//---------------------------------------------------------------------------
int port::get_stat()
{
if ((DWORD)hnd==0xFFFFFFFF) return 0;
DWORD err;
if (ClearCommError(hnd,&err,&stat)) return 1;
error=GetLastError();
return 0;
}
//---------------------------------------------------------------------------
int port::get_timeouts()
{
if ((DWORD)hnd==0xFFFFFFFF) return 0;
if (GetCommTimeouts(hnd,&timeouts)) return 1;
error=GetLastError();
get_stat();
return 0;
}
//---------------------------------------------------------------------------
int port::set_timeouts()
{
if ((DWORD)hnd==0xFFFFFFFF) return 0;
if (SetCommTimeouts(hnd,&timeouts)) return 1;
error=GetLastError();
get_stat();
return 0;
}
//---------------------------------------------------------------------------
int port::get_properties()
{
if ((DWORD)hnd==0xFFFFFFFF) return 0;
if (GetCommProperties(hnd,&properties)) return 1;
error=GetLastError();
get_stat();
return 0;
}
//---------------------------------------------------------------------------
int port::get_rs232_state()
{
if ((DWORD)hnd==0xFFFFFFFF) return 0;
if (GetCommState(hnd,&rs232_state)) return 1;
error=GetLastError();
get_stat();
return 0;
}
//---------------------------------------------------------------------------
int port::set_rs232_state()
{
if ((DWORD)hnd==0xFFFFFFFF) return 0;
if (SetCommState(hnd,&rs232_state)) return 1;
error=GetLastError();
get_stat();
return 0;
}
//---------------------------------------------------------------------------
void port::rst_rs232_state()
{
rs232_state.BaudRate = CBR_9600;
rs232_state.ByteSize = 8;
rs232_state.Parity = NOPARITY;
rs232_state.StopBits = ONESTOPBIT;
rs232_state.fOutxCtsFlow= FALSE;
rs232_state.fOutxDsrFlow= FALSE;
rs232_state.fOutX = FALSE;
rs232_state.fInX = FALSE;
rs232_state.fBinary = FALSE;
rs232_state.fRtsControl = RTS_CONTROL_DISABLE;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
The only stuff it uses from VCL is AnsiString
which is string datatype with character access indexed from 1
instead of 0
. The AnsiString s; s.c_str();
just returns char*
pointer so you can directly port all this to char*
or string type you got at your disposal.
When dealing with RS232 you should take in mind you need some sort of synchronization because the other side never knows if it receives data from the beginning or some data was send already prior to initialization. So you should add some start/end commands to your solver stream.
You can also simultaneously read and write the RS232 but you need to use threads to implement this correctly. This is how I usually do it:
#include <windows.h>
//typedef uint32_t DWORD; // uncomment this if no DWORD type is present
//typedef uint16_t WORD; // uncomment this if no WORD type is present
//typedef uint8_t BYTE; // uncomment this if no BYTE type is present
#include "port.h"
port com;
const int _timeout=1;
const BYTE _id_timeout=0;
unsigned char q;
// init or reconnect
com.open("COM1"); // use number of your COM port to use can be different than 1 especially for USB converters see device manager)
com.timeouts.ReadIntervalTimeout =_timeout;
com.timeouts.ReadTotalTimeoutMultiplier =_timeout;
com.timeouts.ReadTotalTimeoutConstant =_timeout;
com.timeouts.WriteTotalTimeoutMultiplier=_timeout;
com.timeouts.WriteTotalTimeoutConstant =_timeout;
com.set_timeouts();
com.rs232_state.BaudRate=CBR_9600;
com.set_rs232_state();
// write
q='L';
com.out(q);
// read (this can freeze if no data in RS232 and timeout set too big)
q=_id_timeout;
com.in (&q);
if (q==_id_timeout) /* do something if timeout*/ ;
else /* handle valid data*/ ;
// exit
com.close();
In case your environment does not know BYTE, WORD, DWORD
then change them with uint8_t, uint16_t, uint32_t
or use typedef
. The WinAPI functions need to include windows.h
.
As I mentioned before beware that reading COM port without actual data sending from other side might freeze your code so it is better to separate reads and writes to threads or have short timeouts and account for the loss of data due to freeze ups.
Before moving to MCU you should check if your PC side code is working (as you can much easily debug the PC side than the MCU side). So code emulator of your MCU which will read the RS232 feed from your solver and print it somewhere like console or whatever so you can see if data is correct. Then connect RS232 by loop-link (short circuit RxD and Txd pins by a wire) ...