I have a C program (win32 api) which communicates to my Arduino Mega via serial (USB).
I can communicate to the Arduino fine via the IDE's serial monitor.
If I plug in my Arduino and run the C program, the port does not seem to be opened properly and there is no communication.
In this case, if I open the serial monitor from Arduino's IDE (or another serial program) and then close it again, the C program then works perfectly.
Here is my port code from the C program (in this example it is passed 5 as this is the port the Arduino is using):
CSerialPort.h:
#pragma once
#include <Windows.h>
#define CP_BAUD_RATE_1200 CBR_1200
#define CP_BAUD_RATE_9600 CBR_9600
#define CP_BAUD_RATE_1155 CBR_1155
#define CP_BAUD_RATE_4800 CBR_4800
#define CP_BAUD_RATE_19200 CBR_19200
#define CP_DATA_BITS_5 5
#define CP_DATA_BITS_6 6
#define CP_DATA_BITS_7 7
#define CP_DATA_BITS_8 8
#define CP_STOP_BITS_ONE ONESTOPBIT
#define CP_STOP_BITS_TWO TWOSTOPBITS
#define CP_STOP_BITS_ONE_AND_HALF ONE5STOPBITS
#define CP_PARITY_NOPARITY NOPARITY
#define CP_PARITY_ODD ODDPARITY
#define CP_PARITY_EVEN EVENPARITY
#define CP_PARITY_MARK MARKPARITY
#define CP_PARITY_SPACE SPACEPARITY
typedef HANDLE PORT;
PORT OpenPort(int idx);
void ClosePort(PORT com_port);
int SetPortBaudRate(PORT com_port, int rate);
int SetPortDataBits(PORT com_port, int databits);
int SetPortStopBits(PORT com_port, int stopbits);
int SetPortParity(PORT com_port, int parity);
int GetPortBaudRate(PORT com_port);
int GetPortDataBits(PORT com_port);
int GetPortStopBits(PORT com_port);
int GetPortParity(PORT com_port);
int SendData(PORT com_port,const char * data);
int ReciveData(PORT com_port, char * databuffer,int bufferlen);
CSerialPort.c
#include "CSerialPort.h"
#include <time.h>
PORT OpenPort(int idx)
{
HANDLE hComm;
TCHAR comname[100];
wsprintf(comname, TEXT("\\\\.\\COM%d"), idx);
hComm = CreateFile(comname, //port name
GENERIC_READ | GENERIC_WRITE, //Read/Write
0, // No Sharing
NULL, // No Security
OPEN_EXISTING,// Open existing port only
0, // Non Overlapped I/O
NULL); // Null for Comm Devices
if (hComm == INVALID_HANDLE_VALUE)
return NULL;
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (SetCommTimeouts(hComm, &timeouts) == FALSE)
return NULL;
if (SetCommMask(hComm, EV_RXCHAR) == FALSE)
return NULL;
return hComm;
}
void ClosePort(PORT com_port)
{
CloseHandle(com_port);
}
int SetPortBaudRate(PORT com_port, int rate)
{
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
printf("FALSE BAUD STATE");
return FALSE;
dcbSerialParams.BaudRate = rate;
Status = SetCommState(com_port, &dcbSerialParams);
return Status;
}
int SetPortDataBits(PORT com_port, int bits)
{
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
printf("FALSE DATABITS STATE");
return FALSE;
dcbSerialParams.ByteSize = bits;
Status = SetCommState(com_port, &dcbSerialParams);
return Status;
}
int SetPortStopBits(PORT com_port, int bits)
{
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
printf("FALSE STOP STATE");
return FALSE;
dcbSerialParams.StopBits = bits;
Status = SetCommState(com_port, &dcbSerialParams);
return Status;
}
int SetPortParity(PORT com_port, int parity)
{
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
printf("FALSE PARITY STATE");
return FALSE;
dcbSerialParams.Parity = parity;
Status = SetCommState(com_port, &dcbSerialParams);
return Status;
}
int GetPortBaudRate(PORT com_port)
{
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
return -1;
return dcbSerialParams.BaudRate;
}
int GetPortDataBits(PORT com_port) {
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
return -1;
return dcbSerialParams.ByteSize;
}
int GetPortStopBits(PORT com_port) {
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
return -1;
return dcbSerialParams.StopBits;
}
int GetPortParity(PORT com_port) {
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
return -1;
return dcbSerialParams.Parity;
}
int SendData(PORT com_port, const char * data)
{
DWORD dNoOFBytestoWrite = strlen(data);
DWORD dNoOfBytesWritten;
BOOL Status = WriteFile(com_port,
data,
dNoOFBytestoWrite,
&dNoOfBytesWritten,
NULL);
if (Status == FALSE)
return -1;
return dNoOfBytesWritten;
}
int ReciveData(PORT com_port, char * data, int len)
{
DWORD dwEventMask;
DWORD NoBytesRead;
BOOL Status = WaitCommEvent(com_port, &dwEventMask, NULL);
if (Status == FALSE) {
return FALSE;
}
Status = ReadFile(com_port, data, len, &NoBytesRead, NULL);
data[NoBytesRead] = 0;
if (Status == FALSE) {
return FALSE;
}
return TRUE;
}
Test Code:
#include "CSerialPort.h"
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
bool sendComms(char * msgSndPtr, int portNum)
{
auto p1 = OpenPort(portNum);
SetPortBaudRate(p1, CP_BAUD_RATE_9600);
SetPortDataBits(p1, CP_DATA_BITS_8);
SetPortStopBits(p1, CP_STOP_BITS_ONE);
SetPortParity(p1, CP_PARITY_NOPARITY);
SendData(p1, msgSndPtr);
ClosePort(p1);
printf("%s sent.\n", msgSndPtr); //debug
//strcpy(msgSndPtr,"");
return 1;
}
bool receiveComms(char * msgRecPtr, int portNum)
{
bool status = 0;
strcpy(msgRecPtr,"");
SetPortBaudRate(portNum, CP_BAUD_RATE_9600);
SetPortDataBits(portNum, CP_DATA_BITS_8);
SetPortStopBits(portNum, CP_STOP_BITS_ONE);
SetPortParity(portNum, CP_PARITY_NOPARITY);
auto p1 = OpenPort(portNum);
status = ReciveData(p1, msgRecPtr, 50);
ClosePort(p1);
if (!status) //if nothing is received, cancel out and show error
{
return 0;
}
else
{
printf("%s received.\n", msgRecPtr); //debug
return 1;
}
}
void main()
{
char msgRec[50];
char * msgRecPtr = msgRec;
char msgSnd[50];
char * msgSndPtr = msgSnd;
while (!(strcmp("end",msgRecPtr)))
{
sendComms(msgSndPtr, 5);
receiveComms(msgRecPtr, 5);
printf("sent: %s\n, msgSndPtr);
printf("received: %s\n, msgRecPtr);
}
}
The arduino code:
int i = 0;
void setup()
{
// Initiate Serial
Serial.begin(9600);
while (!Serial) ; // wait for serial port to connect. Needed for native USB
Serial.println("serial ready");
}
void loop()
{
Serial.println("testing comms");
i++
delay (150);
if (i == 10) {
Serial.println("end");
}
}
If anyone has had this problem using win32 or knows how the Serial Monitor opens it's port, that would be very helpful.
Edit: just to clarify, once the port has been opened once successfully (by any program apart from my C program), my C program then works fine and can open/close the port successfully until the next power cycle.
Thanks