Windows Api, COM口:接收后发送数据
Windows Api, COM port: transmit data after receiving
我有一个微控制器,我通过 FT232RL 与我的 windows 电脑通信。
在计算机端,我正在制作一个 C 库来发送和接收数据,使用 windows API.
我已经做到了:
- 接收数据(或多次接收),
- 传输数据(或多次传输),
- 先发送(或多次发送)再接收数据(或多次接收)
但我还没有成功:
- 传输数据然后接收。
如果我收到任何东西,然后尝试传输,我会收到错误消息。所以,我想当我收到数据时,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
}
我有一个微控制器,我通过 FT232RL 与我的 windows 电脑通信。 在计算机端,我正在制作一个 C 库来发送和接收数据,使用 windows API.
我已经做到了:
- 接收数据(或多次接收),
- 传输数据(或多次传输),
- 先发送(或多次发送)再接收数据(或多次接收)
但我还没有成功:
- 传输数据然后接收。
如果我收到任何东西,然后尝试传输,我会收到错误消息。所以,我想当我收到数据时,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
}