Update: I uploaded a Version of my mapper to GitHub
I searched for this topic and found no real leads so i looked it up.
Opening the serial port
First point is to open a connection. Before opening any connection several informations must be acquired.
- The name of the serial port.(Usually COM1-COM6 )
- The direction of communication.
- (It is possible to set the communication to an asynchronic mode but it is far mor complex and unintuitive than the synchronic mode used here)
#include <windows.h>
LPCSTR portname = "COM6";
DWORD accessdirection =GENERIC_READ | GENERIC_WRITE;
HANDLE hSerial = CreateFile(portname,
accessdirection,
0,
0,
OPEN_EXISTING,
0,
0);
if (hSerial == INVALID_HANDLE_VALUE) {
//call GetLastError(); to gain more information
}
After opening the port further settings like Baudrate, Byte size, the number of stopbits and the Parity need to be set.
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
if (!GetCommState(hSerial, &dcbSerialParams)) {
//could not get the state of the comport
}
dcbSerialParams.BaudRate=460800;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
if(!SetCommState(hSerial, &dcbSerialParams)){
//analyse error
}
Finally timeouts need to be set so that the program does not hang up when receiving nothing.
COMMTIMEOUTS timeouts={0};
timeouts.ReadIntervalTimeout=50;
timeouts.ReadTotalTimeoutConstant=50;
timeouts.ReadTotalTimeoutMultiplier=10;
timeouts.WriteTotalTimeoutConstant=50;
timeouts.WriteTotalTimeoutMultiplier=10;
if(!SetCommTimeouts(hSerial, &timeouts)){
//handle error
}
return hSerial;
Reading and writing
Reading and writing is analogous to each other.
Reading:
To tell windows that data is going to be send over the serial port, the handle, the data and the amount of data are needed.
The following transmission is a simple fileIO operation.
DWORD readFromSerialPort(HANDLE hSerial, uint8_t * buffer, int buffersize)
{
DWORD dwBytesRead = 0;
if(!ReadFile(hSerial, buffer, buffersize, &dwBytesRead, NULL)){
//handle error
}
return dwBytesRead;
}
Writing
The same information is needed when writing to the port.
DWORD writeToSerialPort(HANDLE hSerial, uint8_t * data, int length)
{
DWORD dwBytesRead = 0;
if(!WriteFile(hSerial, data, length, &dwBytesRead, NULL)){
printLastError();
}
return dwBytesRead;
}
Closing:
when the serial port is not longer needed, it can be freed by closing the associated handle.
void closeSerialPort(HANDLE hSerial)
{
CloseHandle(hSerial);
}
[…] C (usually i do my programming under linux), i found a cute little wrapper for the serial port here. i don’t like .NET that’s why i’ve wanted a pure C implementation. here’s […]
Hi,
Thanks for the excellent blog article. I have a question. Could you please let me know how to call the writeToSerialPort() and readFromSerialPort() functions? I am new to C and I don’t know how to store my serial port command text (in my case „R05“) into the buffer variable. I guess I need to allocate it first and then store the value in it, right? Can you please show how? Thanks a lot!
Hello pkout, the simplest way would be to use the Stingvariable as buffer.
The array can then also be used as the buffer value to transmit the string over the serial port.
HANDLE h = openSerialPort("COM3");
uint8_t arr[] = "R08";
writeToSerialPort(h,arr, 3);
Great! Thanks for the quick response! I assume reading out into the buffer would be done by defining a variable:
uint8_t response;
and then passing a pointer to it like so:
readFromSerialPort(handle, &response, 5);
I think I must be missing something. My response variable always contains null after calling the readFromSerialPort() function even though I should be getting a response. I also tried to put a 10ms sleep call in between write and read, but that didn’t help. Can you please check if I am defining the response variable correctly? Thank you so much!
the responsevariable should be an empty array like arr with a allocated length!
uint8_t response[5];int bytes_read = readFromSerialPort(handle, &response, 5);
Please test this on your own or wait until I get home and have a serial port to do further tests.
if bytes_read is continiously 0 it might be possible that the port is not initialized right.
I tested it and I am still getting 0 bytes in response. One thing that’s interesting is that I had to call the readFromSerialPort(handle, response, 5) instead of readFromSerialPort(handle, &response, 5). Notice the & character. It didn’t compile. As if uint8_t was defined as a pointer. I will check my connection settings and let you know if I get it to work. Thanks for your help!
The & was a copy and paste error on my side ;-).
Hi. I just wanted to let you know that I got it working now. I had a bug in the code as I adjusted it a bit to fit my software architecture. Works like a charm! Thanks for posting! I will tweet this.
Hi.
I hope you are still around here.
i realyze that tou have a return hSerial;
should it not belong to a function?
hserial is a handle(type HANDLE) for the file represents one Serial port in windows.
it is implemented as an integer index to the file table that is maintained for every program by the Operating system.
The tutorial uses this handle to identify the serial port it will write to.
It is easy to implement the communication with more than one serial port when the the file handle is returned as an identifier.
I was making this function:
HANDLE openSerialPort(const char* port){
LPCSTR portname = port;
DWORD accessdirection =GENERIC_READ | GENERIC_WRITE;
HANDLE hSerial = CreateFile(portname,
……………..
……………..
if(!SetCommTimeouts(hSerial, &timeouts))
cout << "handle error";
return hSerial;
}
and then inside int main () i was calling it like this.
HANDLE h = openSerialPort("COM3");
is this correct?
there was no compiling error though.
I did upload my project to Github.
Look for the example.c in the README file
wow. Thank you. I really appreciate.
used github files. minor modification was necessary to open the port. „COM11″ didn’t worked, but following:
LPCSTR serialport=“\\\\.\\COM11“;
HANDLE h = openSerialPort(serialport, B115200, one, off);
Hi i really appreciate this, My query is is this limited for com1 to com6. Actually am working on it mine port is com12. The code is compiled but i couldn’t possible to send and receive any data.Please help me out
Hello Arvind,
please try the comment of jaui that I unlocked just now 😉