C Program not opening Serial on Arduino Mega

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

@Black-Solis, your topic has been moved to a more suitable location on the forum.

It will be useful to put some printf statements in your PC code so you can see what fails, e.g.

if (hComm == INVALID_HANDLE_VALUE)
{
    printf("invalid handle\r\n");
    return NULL;
}

How do you handle the return value?

I might have missed it, but where do you set the baudrate in your PC code?

Hi @sterretje
Thanks.

I set the baud rate before the port is open.

This function is called before OpenPort (and is passed 5, CBR_9600 (I have also tried just 9600)).

int SetPortBaudRate(PORT com_port, int rate)
{
	DCB dcbSerialParams = { 0 };
	BOOL Status;
	dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
	Status = GetCommState(com_port, &dcbSerialParams);
	if (Status == FALSE)
		return FALSE;
	dcbSerialParams.BaudRate = rate;
	Status = SetCommState(com_port, &dcbSerialParams);
	return Status;
}

I also set the port to 8 data bits, 1 stop bit and no parity, are these settings correct?

post the complete program?

this works under Windows 10 using the GNU gcc compiler

// terminal.c - simple terminal program for Dev-C++/Code:Blocks

//
// only works for one port at moment
//
#include <conio.h>
#include <stdio.h>
#include <windows.h>


HANDLE hCom;           //handle for serial port I/O

/*----------------------------------------------------------------------------*
 * Serial port: initialise io_port, set baud rate, set data bits, one stop bit*/

HANDLE rs_initialise (int io_port, const long int BaudRate, const char parity, const char data)
{
    BOOL bPortReady;
    DCB dcb;
	    COMMTIMEOUTS CommTimeouts;

    char ComPortName[]="COM1";           // set up COM port number in COM?
    ComPortName[3]='0'+io_port;
    hCom = CreateFile(ComPortName, GENERIC_READ | GENERIC_WRITE,
                                  0,            // exclusive access
                                  NULL,         // no security
                                  OPEN_EXISTING,
                                  0,            // no overlapped I/O
                                  NULL);        // null template


    if ((int)hCom <= 0) { printf("serial port COM%d connect fail %s error %ld\n\r", io_port, ComPortName, GetLastError()); return 0;   }
    //else                printf(" serial port COM%d connect OK \n\r", io_port);

    bPortReady = SetupComm(hCom, 2, 128); // set buffer sizes
    if (!bPortReady ) { printf("serial port COM%d SetupComm fail  %ld\n\r", io_port,  GetLastError()); return 0;   }
    //else                printf(" serial port COM%d connect OK \n\r", io_port);

    bPortReady = GetCommState(hCom, &dcb);
    if (!bPortReady ) { printf("serial port COM%d  GetCommState fail  %ld\n\r", io_port,  GetLastError()); return 0;   }
  //  else                printf(" serial port COM%d connect OK \n\r", io_port);
    dcb.BaudRate = BaudRate;
    if( data == '7') dcb.ByteSize = 7;
    else             dcb.ByteSize = 8;
    if( parity == 'E') dcb.Parity = EVENPARITY;
    if( parity == 'O') dcb.Parity = ODDPARITY;
    else               dcb.Parity = NOPARITY;
    dcb.StopBits = ONESTOPBIT;
    dcb.fAbortOnError = TRUE;

    // set XON/XOFF
    dcb.fOutX = FALSE;                       // XON/XOFF off for transmit
    dcb.fInX = FALSE;                        // XON/XOFF off for receive
    // set RTSCTS
    dcb.fOutxCtsFlow = FALSE;               // turn off CTS flow control
    dcb.fRtsControl = FALSE;                // RTS_CONTROL_HANDSHAKE; //
    // set DSRDTR
    dcb.fOutxDsrFlow = FALSE;               // turn off DSR flow control
    //dcb.fDtrControl = DTR_CONTROL_ENABLE; // DTR handshake
    dcb.fDtrControl = DTR_CONTROL_DISABLE;  //
    // dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; //

    bPortReady = SetCommState(hCom, &dcb);
    if (!bPortReady ) { printf("serial port COM%d  SetCommState fail  %ld\n\r", io_port,  GetLastError()); return 0;   }

    // Communication timeouts
    //COMMTIMEOUTS CommTimeouts;
    bPortReady = GetCommTimeouts (hCom, &CommTimeouts);
    CommTimeouts.ReadIntervalTimeout = 5 ;
    CommTimeouts.ReadTotalTimeoutConstant = 5 ;
    CommTimeouts.ReadTotalTimeoutMultiplier = 1 ;
    CommTimeouts.WriteTotalTimeoutConstant = 5 ;
    CommTimeouts.WriteTotalTimeoutMultiplier = 1 ;
    bPortReady = SetCommTimeouts (hCom, &CommTimeouts);
    if (!bPortReady ) { printf("serial port COM%d SetCommTimeouts fail  %ld\n\r", io_port,  GetLastError()); return 0;   }
    else                printf(" serial port COM%d connect @ %ld baud OK \n\r", io_port, BaudRate);
    return hCom;
}

/*----------------------------------------------------------------------------*
 * Serial port:  initialise using command line parameters passed from main()  *
 *  return serial port value in range 0 to 3 of all OK                        */
int rs_parameters(int argc, char *argv[], const int print_data)
{
    int io_port = 1, parity = 'n', data = '8';
    long int baud_rate = 9600l;
    char *chr_ptr;
    int index;

    /* search command line for port number, baud rate, etc. */
    for (index = 0; index < argc ; index++)
       {
       if ((chr_ptr = strstr(argv[index],"port=com")) != 0)
          {
          chr_ptr = chr_ptr + 8;           /* found port=com, point to number */
          io_port = (int) strtol(chr_ptr, NULL, 10);        /* convert number */
          }
       if ((chr_ptr = strstr(argv[index],"baud=")) != 0)
          {
      chr_ptr = chr_ptr + 5;              /* found baud=, point to number */
          baud_rate = strtol(chr_ptr, NULL, 10);            /* convert number */
          }
       if ((chr_ptr = strstr(argv[index],"parity=")) != 0)
          parity = *(chr_ptr + 7);                 /* found parity=, get char */
       if ((chr_ptr = strstr(argv[index],"data=")) != 0)
          data = *(chr_ptr + 5);              /* found data lenngth, get char */
    }

    if (print_data)
      {
      printf("\nRS232 serial line initialisation \n"
           "  command line options: port=com1/2/3/4\n"
       "                        baud=2400/4800/9600/19200"
                                    "/38400/57600/115200\n"
           "                        parity=n/e/o\n"
           "                        data=7/8\n\n"
           "  initialising port = com%d,", io_port);
      printf(" baud rate = %ld, parity = %c, data = %c\n\n",
                         baud_rate, parity, data);
      }
    io_port = io_port - 1;
   // rs_initialise(io_port, baud_rate, parity, data);          /* initialise io_port */
    rs_initialise(39, baud_rate, parity, data);          /* initialise io_port */
    return io_port;
}

/*----------------------------------------------------------------------------*
 * Serial port: terminate io_port, sets DTR and RTS to low                     */
void rs_terminate(const int io_port)
{
  // Close(hCom);
}



/*----------------------------------------------------------------------------*
 * Serial port: read character from io_port (ignored in this version)         */
char rs_getch(const int io_port)
{
    char rxchar;
   BOOL bReadRC;
    static DWORD iBytesRead;
    bReadRC = ReadFile(hCom, &rxchar, 1, &iBytesRead, NULL);
    if (iBytesRead) return rxchar; else return 0;         // return 0 if no character read
}

/*----------------------------------------------------------------------------*
 * Serial port: transmit character to io_port                                 */
void rs_putch(const int io_port, const int txchar)
{
    BOOL bWriteRC;
    static DWORD iBytesWritten;
    bWriteRC = WriteFile(hCom, &txchar, 1, &iBytesWritten,NULL);
    return;
}

/*----------------------------------------------------------------------------*
 * Serial port: transmit a string of characters to io_port                    */
void rs_putstring(const int io_port, const char *string)
{
    while (*string != '\0')
        rs_putch(io_port, *string++);
}

#include <stdio.h>
#include <stdlib.h>


int main()
{
    char letter;
    int port = 8;//1;
    if(!rs_initialise(port ,115200, '8', 'N')) { getch(); exit(1); };
    while(1)
     {
      if (kbhit())  rs_putch(port, getche());             // if keyboard hit read character and transmit it
      if((letter=rs_getch(port))>0)
         { putchar(letter); if(letter=='\r')   putchar('\n'); }     // if character received display it
     }
    getch();
    return 0;
}

conected to an Arduino Due using a HC-05 to communicate with an Android phone
a message from phone displays

 serial port COM8 connect @ 115200 baud OK
hello due

I have updated the OP to add the other serial parts. Unfortunately I will need to communicate on more than 1 port at a time, thanks for the suggestion!

I'm missing the point of the above statement.

Horace’s code only works for one port…?
Thanks for the input sterretje

Should be easy to adjust.

If I can use my existing code which can communicate on multiple ports at once I would prefer that.
If I open the port first in another program (Serial Monitor from Arduino IDE or CoolTerm or any serial comms program) and then close the port, my C program works perfectly.

I think I am not setting the baud rate correctly as it is the only debug error I receive after opening the port. The databits, stopbits and parity are all set OK.

This function is passed the port number (or handle, I have tried both) and the rate CBR_9600 (have also tried just 9600).

int SetPortBaudRate(PORT com_port, int rate)
{
	DCB dcbSerialParams = { 0 };
	BOOL Status;
	dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
	Status = GetCommState(com_port, &dcbSerialParams);
	if (Status == FALSE)
		return FALSE;
	dcbSerialParams.BaudRate = rate;
	Status = SetCommState(com_port, &dcbSerialParams);
	return Status;
}

Is there something obvious I am missing here?
Does the Arduino require handshaking?

The Arduino does not require a handshake. The only thing that can happen is that your PC program can reset the Arduino when the port is opened; this can be prevented by playing with the DTR control; this however is more than likely not your problem at this moment.

I do strongly suggest that you post your complete PC program or a representative example that does compile and shows the problem.

Thanks, I have updated the OP to reflect more code :slight_smile:

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.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.