简体   繁体   中英

Windows COM Communication via CDC COM Port to Arduino

I have just bought a SparkFun Pro Micro ( https://www.sparkfun.com/products/12640 ) and am attempting to communicate to it using ReadFile and WriteFile on Windows 10.

I have tested and run my code with a Stellaris, Tiva, Arduino Mega, and even the Arduino Leonardo with little to no problems (it worked). However I have not been able to send any data from the Pro Micro or receive data on my computer using the micro USB cable and my own custom program. I can use the Arduino serial monitor to send and receive data just fine. I can also use a PuTTY terminal. The baud rates in both Arduino IDE and PuTTY seem to have no effect on the ability to send/receive data using the Pro Micro.

I want to be able to send and receive data using my own program as I am using it as a server for data logging, post-processing, and real-time graphing/display. If this project didn't require a smaller hardware package I would use the Arduino Mega, but that is sadly not an option.

I'm compiling on Windows 10, using Visual Studio 2015. I'm also using the official Arduino IDE with SparkFuns addon/drivers, v1.6.7 (updated to 1.6.8 with same problems).

This is my code to connect to the COM port, I have tried various baud rates as well as the BAUD_XXXX macros:

*port = CreateFile(COM, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); //CreateFile(TEXT("COM8:"), ...
if (*port == INVALID_HANDLE_VALUE){
    printf("Invalid handle\n");
    return(1);
}

/// COM Port Configuration
portDCB.DCBlength = sizeof(DCB);                         ///< Initialize the DCBlength member
GetCommState(*port, &portDCB);                           ///< Get the default port setting information.
/// Change the DCB structure settings
portDCB.BaudRate = 115200;                              ///< Current baud 
portDCB.fBinary = TRUE;                                   ///< Binary mode; no EOF check 
portDCB.fParity = FALSE;                                  ///< Disable parity checking 
portDCB.fOutxCtsFlow = FALSE;                             ///< No CTS output flow control 
portDCB.fOutxDsrFlow = FALSE;                             ///< No DSR output flow control 
portDCB.fDtrControl = DTR_CONTROL_DISABLE;                ///< Disable DTR flow control type 
portDCB.fDsrSensitivity = FALSE;                          ///< DSR sensitivity 
portDCB.fTXContinueOnXoff = TRUE;                         ///< XOFF continues Tx 
portDCB.fOutX = FALSE;                                    ///< No XON/XOFF out flow control 
portDCB.fInX = FALSE;                                     ///< No XON/XOFF in flow control 
portDCB.fErrorChar = FALSE;                               ///< Disable error replacement 
portDCB.fNull = FALSE;                                    ///< Disable null stripping 
portDCB.fRtsControl = RTS_CONTROL_DISABLE;                ///< Disable RTS flow control 
portDCB.fAbortOnError = FALSE;                            ///< Do not abort reads/writes on error
portDCB.ByteSize = 8;                                     ///< Number of bits/byte, 4-8 
portDCB.Parity = NOPARITY;                                ///< 0-4 = no, odd, even, mark, space 
portDCB.StopBits = ONESTOPBIT;                            ///< 0, 1, 2 = 1, 1.5, 2 

if (!SetCommState(*port, &portDCB)){
    printf("Error Configuring COM Port\n");
    return(1);
}

GetCommTimeouts(*port, &comTimeOut);

comTimeOut.ReadIntervalTimeout = 20;
comTimeOut.ReadTotalTimeoutMultiplier = 10;
comTimeOut.ReadTotalTimeoutConstant = 100;
comTimeOut.WriteTotalTimeoutMultiplier = 10;
comTimeOut.WriteTotalTimeoutConstant = 100;

SetCommTimeouts(*port, &comTimeOut);

My read and write functions:

char inChar(HANDLE port){
    char output = 0;
    DWORD noOfBytesRead = 0;
    int retval = ReadFile(port, &output, 1, &noOfBytesRead, NULL);
    if (retval == 0) {
        return (0);
    }
    return(output);
}

void outChar(HANDLE port, char output){
    DWORD bytesTransmitted = 0;
    char buffer[] = { output, 0 };
    WriteFile(port, buffer, 1, &bytesTransmitted, NULL);
}

I have this to test communication on the PC:

while (1) {
    outChar(portHandle, 'b');
    inchar = inChar(portHandle);
    printf("%c", inchar);
}

On the Arduino:

void setup(){Serial.begin(115200);}
void loop(){
    Serial.read();
    Serial.println('a');
    delay(10);
}

The Rx LED is flashing like crazy on the Arduino, but the Tx LED is doing nothing, signifying that there is only data going one way. I have done other tests and I have found the Arduino is reading the right information (tested by blinking an LED on and off if the input char is a specific char) but it just wont send anything to my program (PC side when not using Arduino IDE or PuTTY).

In PuTTY I have been able to initiate COM communication with any baud rate, regardless of the Arduinos Serial.begin(). 8 data bits, 1 stop bit, no parity, no flow control, the same as my setup in Visual Studio.

Edit: I thought if I didn't configure it myself, I would just be piggybacking off the COM configuration left over from PuTTy so I modified my code and removed all the excess:

/// COM Port Configuration
portDCB.DCBlength = sizeof(DCB);                         ///< Initialize the DCBlength member
GetCommState(*port, &portDCB);                           ///< Get the default port setting information.
/// Change the DCB structure settings
portDCB.BaudRate = 115200;                              ///< Current baud 
portDCB.ByteSize = 8;                                     ///< Number of bits/byte, 4-8 
portDCB.Parity = NOPARITY;                                ///< 0-4 = no, odd, even, mark, space 
portDCB.StopBits = ONESTOPBIT;                            ///< 0, 1, 2 = 1, 1.5, 2 
/*
portDCB.fBinary = TRUE;                                   ///< Binary mode; no EOF check 
portDCB.fParity = FALSE;                                  ///< Disable parity checking 
portDCB.fOutxCtsFlow = FALSE;                             ///< No CTS output flow control 
portDCB.fOutxDsrFlow = FALSE;                             ///< No DSR output flow control 
portDCB.fDtrControl = DTR_CONTROL_DISABLE;                ///< Disable DTR flow control type 
portDCB.fDsrSensitivity = FALSE;                          ///< DSR sensitivity 
portDCB.fTXContinueOnXoff = TRUE;                         ///< XOFF continues Tx 
portDCB.fOutX = FALSE;                                    ///< No XON/XOFF out flow control 
portDCB.fInX = FALSE;                                     ///< No XON/XOFF in flow control 
portDCB.fErrorChar = FALSE;                               ///< Disable error replacement 
portDCB.fNull = FALSE;                                    ///< Disable null stripping 
portDCB.fRtsControl = RTS_CONTROL_DISABLE;                ///< Disable RTS flow control 
portDCB.fAbortOnError = FALSE;                            ///< Do not abort reads/writes on error
*/

It works just fine with the commented code, but why? What makes this Pro Micro so different from the other micro-controllers I've used? I'll go through and test them all one-by-one until I find out which is responsible, as this only works if I connect after first opening and closing the port in PuTTY (inconvenient).

The SparkFun Pro Micro doesn't like it when you disable RTS control in Windows DCB Structure.

The issue is resolved with:

portDCB.fRtsControl = RTS_CONTROL_ENABLE; //was RTS_CONTROL_DISABLE
portDCB.fOutxCtsFlow = TRUE;              //was FALSE

As usual, it was a mistake in overlooking important information in the datasheet, I spent hours reading through the register information trying to confirm where or why I went wrong and the answer was simple as seen is the functionality list of the USART device in the datasheet:

USART:
...
• Flow control CTS/RTS signals hardware management
...
char inChar(HANDLE port){
        char output = 0;
        DWORD noOfBytesRead = 0;
        int retval = ReadFile(port, &output, 1, &noOfBytesRead, NULL);
        if (retval == NULL) {
            return (NULL);
        }
        return(output);
    }

This is not correct since you are comparing retval (which is int) to NULL, and your function returns NULL as return value of char function. Although I don't believe that this causes reported issue it should be changed.

Take a look on accepted answer here . I would suggest you to start from a working example on PC side and then to reduce it to your needs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM