Windows Api, COM口:接收后发送数据

Windows Api, COM port: transmit data after receiving

我有一个微控制器,我通过 FT232RL 与我的 windows 电脑通信。 在计算机端,我正在制作一个 C 库来发送和接收数据,使用 windows API.

我已经做到了:

  1. 接收数据(或多次接收),
  2. 传输数据(或多次传输),
  3. 先发送(或多次发送)再接收数据(或多次接收)

但我还没有成功:

  1. 传输数据然后接收。

如果我收到任何东西,然后尝试传输,我会收到错误消息。所以,我想当我收到数据时,HANDLE hComm 的配置发生了变化,但我找不到。

所以问题是,当我接收数据时,我的 HANDLE hComm 配置发生了什么变化,之后不允许我传输?

这是我的 code/functions 和 main() 给我的错误。如果我 运行 这个,我会得到这个“错误 6” - 下面的错误截图 -:

#include <Windows.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
    //Create Handler
    HANDLE hComm = comPortSetup("\\.\COM5");//change this to the com port of your mcu
    //Setup the Receiver
    rx_setup(hComm);

    sleep(1);


    char  SerialBuffer[256];
    //Receive data
    rx_receive(hComm, &SerialBuffer);//<---- Works fine

    char firstData[125] = ".";
    tx_transmit(hComm, &firstData);//<----Wont work, since I received data first.

    CloseHandle(hComm);//Closing the Serial Port
    _getch();//press any key to close the window

}

处理 comPortSetup:

HANDLE comPortSetup(char ComPrt[])
{
    int CharLoop=0;

    HANDLE HandleCom;                 // Handle to the Serial port

    /*----------------------------------- Opening the Serial Port --------------------------------------------*/

    /*
    There might be a case where one would need to use CreateFileA instead. (Depending on the compiler)
    More can be found here: 
    */
    HandleCom = CreateFile( ComPrt,                       // Name of the Port to be Opened
                        GENERIC_READ | GENERIC_WRITE,      // Read/Write Access
                        0,                                 // No Sharing, ports cant be shared
                        NULL,                              // No Security
                        OPEN_EXISTING,                     // Open existing port only
                        0,                                 // Non Overlapped I/O (0 does not match any of the flags of dwFlagsAndAttributes.
                                                           // This means we are setting no flags or attributes (We dont care about it) 
                        NULL);                             // Null for Comm Devices

    if (HandleCom == INVALID_HANDLE_VALUE)
        printf("\n   Error! - Port %s can't be opened", ComPrt);
    else
        printf("\n   Port %s Opened\n ", ComPrt);

    /*------------------------------- Setting the Parameters for the SerialPort ------------------------------*/

    DCB dcbSerialParams = { 0 };

                        // Initializing DCB structure
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    BOOL StatusFun;

    StatusFun = GetCommState(HandleCom, &dcbSerialParams);     //retreives  the current settings

    if (StatusFun == FALSE)
        printf("\n   Error! in GetCommState()");

    dcbSerialParams.BaudRate = CBR_9600;      // Setting BaudRate = 9600
    dcbSerialParams.ByteSize = 8;             // Setting ByteSize = 8
    dcbSerialParams.StopBits = ONESTOPBIT;    // Setting StopBits = 1
    dcbSerialParams.Parity   = NOPARITY;      // Setting Parity = None

    StatusFun = SetCommState(HandleCom, &dcbSerialParams);  //Configuring the port according to settings in DCB

    if (StatusFun == FALSE)
        {
            printf("\n   Error! in Setting DCB Structure");
        }
    else
        {
            printf("\n   Setting DCB Structure Successfull\n");
            printf("\n       Baudrate = %d", dcbSerialParams.BaudRate);
            printf("\n       ByteSize = %d", dcbSerialParams.ByteSize);
            printf("\n       StopBits = %d", dcbSerialParams.StopBits);
            printf("\n       Parity   = %d", dcbSerialParams.Parity);
        }
    /*------------------------------------ Setting Timeouts --------------------------------------------------*/

    COMMTIMEOUTS timeouts = { 0 };

    //miliseconds (ms) intervals
    //interval between the arrival of any two bytes. Terminates the ReadFile
    timeouts.ReadIntervalTimeout         = 100; //Default =50
    //Total = (TimeoutMultiplier*BytesToRead + TimeoutConstant)
    timeouts.ReadTotalTimeoutConstant    = 10; //Default = 50
    timeouts.ReadTotalTimeoutMultiplier  = 20; //Default = 10
    //Total = (TimeoutMultiplier*BytesToRead + TimeoutConstant)
    timeouts.WriteTotalTimeoutConstant   = 10; //Default = 50
    timeouts.WriteTotalTimeoutMultiplier = 20; //Default = 10

    if (SetCommTimeouts(HandleCom, &timeouts) == FALSE)
        printf("\n   Error! in Setting Time Outs");
    else
        printf("\n\n   Setting Serial Port Timeouts Successfull");

    return HandleCom;
}

rx_setup:

BOOL rx_setup(HANDLE HandleCom)
{
/*------------------------------------ Setting Receive Mask ----------------------------------------------*/
    //https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setcommmask
    BOOL Status;
    Status = SetCommMask(HandleCom, EV_RXCHAR); //Configure Windows to Monitor the serial device for Character Reception

    if (Status == FALSE)
    {
         printf("\n\n    Error! in Setting CommMask");
    }

    /*------------------------------------ Setting WaitComm() Event   ----------------------------------------*/

    printf("\n\n    Waiting for Data Reception...");

    DWORD dwEventMask; // Event mask to trigger. 32-bit unsigned integer (range: 0 through 4294967295 decimal)
    //Wait for the first character to be received
    Status = WaitCommEvent(HandleCom, &dwEventMask, NULL); //dwEventMask Should be 1 for "A character was received and placed in the input buffer." AKA EV_RXCHAR
    /*-------------------------- Program will Wait here till one Character is received ------------------------*/

    if (Status == FALSE)
    {
        printf("\n  Error! in Setting WaitCommEvent()");
        exit(-1);
    }

    return Status;

}

rx_receive:

void rx_receive(HANDLE HandleCom, char SerialBufferFun[])
{
    char  TempChar;                        // Temperory Character
    BOOL Status;

    /*Receiver start*/
    DWORD NoBytesRead;                     // Bytes read by ReadFile()
    int loopArrayFun = 0;
    do
    {
        Status = ReadFile(HandleCom,
                          &TempChar,
                          sizeof(TempChar),         //No of bytes to be read
                          &NoBytesRead,             //How many bytes were actually read
                          NULL);
        SerialBufferFun[loopArrayFun] = TempChar;
        printf("%c",SerialBufferFun[loopArrayFun]);
        loopArrayFun = loopArrayFun+1;
    }while (NoBytesRead > 0);//NoBytesRead = 0 when bytes are finished reading.

SerialBufferFun[loopArrayFun-3] = '[=15=]'; //WHY -3
}

传送:

void tx_transmit(HANDLE HandleCom, char DataToTransmit[])
{
    BOOL Status;

        /*----------------------------- Writing a Character to Serial Port----------------------------------------*/
    //DataToTransmit should be  char or byte array, otherwise write will fail
    DWORD  dNoOFBytestoWrite;              // No of bytes to write into the port

    DWORD  dNoOfBytesWritten = 0;          // No of bytes written to the port

    dNoOFBytestoWrite = sizeof(DataToTransmit); // Calculating the no of bytes to write into the port


    if (HandleCom == INVALID_HANDLE_VALUE)
    {
        printf("\n   Invalid handle");
    }

        Status = WriteFile(HandleCom,               // Handle to the Serialport
                       DataToTransmit,            // Data to be written to the port
                       (dNoOFBytestoWrite),   // No of bytes to write into the port
                       &dNoOfBytesWritten,  // No of bytes written to the port
                       NULL);

    if (Status != TRUE)
        printf("\n\n   Error %d in Writing to Serial Port",GetLastError());
}

我在运行以上代码后得到的错误(错误6。'Heater Driver'等来自MCU):

我尝试了什么:

我注意到在接收时唯一可能影响我传输的变化不在 rx_receive 内,而是在 rx_setup 内:

SetCommMask(HandleCom, EV_RXCHAR);

和:

WaitCommEvent(HandleCom, &dwEventMask, NULL);

所以我尝试在接收后做 SetCommMask(HandleCom, 0x00); 但它没有用,我得到了同样的错误。我不知道我是否需要禁用 WaitCommEvent(HandleCom, &dwEventMask, NULL);,但是因为它在接收完成时停止 运行ning,所以它只是 运行s 在函数内部并且不会影响我的HANDLE hComm

根据MSDN:Sample,您可能需要在微控制器程序中设置引脚的信号状态以指示数据已sent/received。更多详细信息位于您的串行通信数据传输标准中。并且您应该根据 WaitCommEvent(hCom, &dwEvtMask, &o); 的结果编写代码,如链接示例。

找到解决办法了!解法:

我根本不需要在 main 中使用 rx_setup 函数!

我不确定为什么会这样,但我现在可以 receive/send 按我想要的任何顺序收集数据。

所以我的主要是:

#include <Windows.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
    //Create Handler
    HANDLE hComm = comPortSetup("\\.\COM5");//change this to the com port of your mcu
    //Setup the Receiver
    //rx_setup(hComm);

    sleep(1);


    char  SerialBuffer[256];
    //Receive data
    rx_receive(hComm, &SerialBuffer);//<---- Works fine

    char firstData[125] = ".";
    tx_transmit(hComm, &firstData);//<----Works as expected now

    CloseHandle(hComm);//Closing the Serial Port
    _getch();//press any key to close the window

}