In Win32, two programming methods can be used to implement serial communication. One is to use ActiveX controls. This method is simple but not flexible. The second is to call Windows API functions. This method can clearly master the serial communication mechanism and be free and flexible. This article only introduces the API Serial Communication Section.
Serial Port operations can be performed in two ways: synchronous operations and overlapping operations (also called asynchronous operations ). During synchronous operations, API functions will be blocked until the operation is completed before returning (in the multi-threaded mode, although the main thread is not blocked, the listening thread is still blocked). In the overlapping operation mode, the API function returns immediately, and the operation is performed in the background to avoid thread blocking.
Regardless of the operation method, it is generally completed in four steps:
(1)Open serial port
(2)Configure serial port
(3)Read/write serial port
(4)Close serial port
(1) Open the serial port
The Win32 system extends the file concept. Whether it is a file, communication device, named pipe, mail slot, disk, or console, it is opened or created using the createfile API function. The function is prototype:
HANDLE CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDistribution, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
- Lpfilename: name of the serial port to be opened, for example, "//./COM1 ";
- Dwdesiredaccess: Specifies the serial access type, which can be read, write, or parallel;
- Dww.mode: Specifies the sharing attribute. This parameter must be set to 0 because the serial port cannot be shared;
- Lpsecurityattributes: Security Attribute structure referenced. The default value is null;
- Dwcreationdistribution: Create a flag. You must set this parameter to open_existing for serial port operations;
- Dwflagsandattributes: attribute description, used to specify whether the serial port performs asynchronous operations. The value is file_flag_overlapped, indicating that asynchronous I/O is used; the value is 0, indicating synchronous I/O operations;
- Htemplatefile: For the serial port, this parameter must be set to NULL;
Sample Code for enabling the serial port in synchronous I/O mode:
Handle hcom; // global variable, serial port handle hcom = createfile ("COM1", // COM1 port generic_read | generic_write, // allow read and write 0, // The exclusive mode is null, open_existing, // open instead of creating 0, // synchronization mode null); If (hcom = (handle)-1) {afxmessagebox ("Opening com failed! "); Return false;} return true;
Sample Code for opening a serial port through overlapping I/O:
Handle hcom; // global variable, serial port handle hcom = createfile ("COM1", // COM1 port generic_read | generic_write, // allow read and write 0, // The exclusive mode is null, open_existing, // open instead of creating file_attribute_normal | file_flag_overlapped, // The overlapping mode is null); If (hcom = invalid_handle_value) {afxmessagebox ("failed to open com! "); Return false;} return true;
(2) configure the serial port
After opening the handle of the communication device, you often need to initialize the configuration of the serial port. This requires a DCB structure. The DCB structure contains information such as the baud rate, the number of data digits, and the parity checksum and the number of stop digits. When querying or configuring the properties of the serial port, you must use the DCB structure as the buffer.
After enabling the serial port with createfile, you can call the getcommstate function to obtain the initial configuration of the serial port. To modify the configuration of the serial port, you must first modify the DCB structure and then call the setcommstate function to set the serial port.
The DCB structure contains the parameter settings of the serial port. The following describes only a few common variables for this structure:
Typedef struct _ DCB {......... // Baud rate, which specifies the transmission rate of the communication device. This member can be the actual baud rate or one of the following constant values: DWORD baudrate; cbr_110, cbr_300, cbr_600, cbr_1200, clerk, cbr_19200, cbr_38400, cbr_56000, clerk, cbr_115200, cbr_128000, cbr_256000, cbr_14400dword fparity; // specify the parity enabling function. If this member is 1, the parity check is allowed... Byte bytesize; // number of bytes for communication, 4-8byte parity; // specify the parity method. This member can have the following values: evenparity, even, noparity, non-checksum, markparity, Mark, verify, oddparity, Odd, byte stopbits; // specifies the number of bits to be stopped. This member can have the following values: onestopbit 1-bit stop bit twostopbits 2-bit stop bit one5stopbits 1.5-bit stop bit .........} DCB; the constant used above is defined in the WINBASE. h file. As follows: # define noparity 0 # define oddparity 1 # define evenparity 2 # define onestopbit 0 # define limit 1 # define limit 2 # define limit 110 # define cbr_300 300 # define cbr_600 600 # define cbr_1200 # define limit 2400 # define limit 4800 # define limit 9600 # define cbr_14400 14400 # define cbr_19200 19200 # define limit 38400 # define limit 56000 # define cbr_57600 57600 # define cbr_115200 115200 # define br_128000 # define cbr_256000 256000
The getcommstate function obtains the Device Control Block of the comport to obtain the relevant parameters:
Bool getcommstate (handle hfile, // handle that identifies the communication port lpdcb // pointer to a device control block (DCB structure); setcommstate function sets the Device Control Block of the comport: bool setcommstate (handle hfile, lpdcb );
In addition to the BCD settings, the program generally needs to set the size and timeout of the I/O buffer. Windows uses an I/O buffer to store input and output data of the serial port. If the communication rate is high, a large buffer zone should be set. You can call the setupcomm function to set the input and output buffer sizes of the serial port.
Bool setupcomm (handle hfile, // communication device handle DWORD dwinqueue, // input buffer size (bytes) DWORD dwoutqueue // output buffer size (bytes ));
Timeout must be considered when readfile and writefile are used to read and write the serial port. The function of timeout is that a specified number of characters are not read or sent within the specified time, And the readfile or writefile operation will still end.
To query the current timeout settings, call the getcommtimeouts function, which will fill in a commtimeouts structure. You can call setcommtimeouts to set the timeout value using the content of a commtimeouts structure.
There are two types of read/write serial port Timeout: interval timeout and total timeout. The interval timeout refers to the maximum latency between two characters during receiving. Total timeout refers to the maximum time spent on read/write operations. Write operations only support total timeouts, while read Operations Support both timeouts. The commtimeouts structure can be used to specify the read/write operation timeout.
The commtimeouts structure is defined:
Typedef struct _ commtimeouts {DWORD readintervaltimeout; // DWORD readtotaltimeoutmultiplier; // read time coefficient DWORD readtotaltimeoutconstant; // read Time Constant DWORD internal; // write time coefficient DWORD internal; // write time constant} commtimeouts, * lpcommtimeouts;
Members of the commtimeouts structure are in milliseconds. The formula for calculating the total timeout is:
Total timeout = time coefficient × number of characters required to read/write + Time Constant
For example, to read 10 characters, the formula for calculating the total read operation timeout is as follows:
Total read timeout = readtotaltimeoutmultiplier × 10 + readtotaltimeoutconstant
It can be seen that the interval timeout and total timeout settings are irrelevant, which allows the communication program to flexibly set various timeout settings.
If all write timeout parameters are 0, write timeout is not used. If readintervaltimeout is 0, read interval timeout is not used. If both readtotaltimeoutmultiplier and readtotaltimeoutconstant are 0, the total read timeout is not used. If the read interval timeout is set to maxdword and the read time coefficient and read Time Constant are both 0, the read operation returns immediately after reading the content of the input buffer, whether or not the required characters are read.
When reading and writing serial ports through overlapping methods, although readfile and writefile may be returned before the operation is completed, the timeout still works. In this case, the timeout specifies the operation completion time, rather than the return time of readfile and writefile.
Sample Code for configuring the serial port:
Setupcomm (hcom, 1024,); // the size of the input buffer and output buffer is commtimeouts timeouts; // set the read timeout timeouts. readintervaltimeout = 1000; timeouts. readtotaltimeoutmultiplier = 500; timeouts. readtotaltimeoutconstant = 5000; // set the write timeout timeouts. writetotaltimeoutmultiplier = 500; timeouts. writetotaltimeoutconstant = 2000; setcommtimeouts (hcom, & Timeouts); // set the timeout DCB; getcommstate (hcom, & DCB); DCB. baudrate = 9600; // The baud rate is 9600dcb. bytesize = 8; // each byte has eight DCB bits. parity = noparity; // No parity bit DCB. stopbits = twostopbits; // two stop bits setcommstate (hcom, & DCB); purgecomm (hcom, purge_txclear | purge_rxclear );
Before reading and writing the serial port, use the purgecomm () function to clear the buffer. The function prototype is as follows:
Bool purgecomm (handle hfile, // serial port handle DWORD dwflags // operations to be completed );
The dwflags parameter specifies the operation to be completed. It can be a combination of the following values:
Purge_txabort interrupts all write operations and returns the result immediately, even if the write operation is not completed. Purge_rxabort interrupts all read operations and returns the result immediately, even if the read operation is not completed. Purge_txclear clear output buffer purge_rxclear clear input buffer
(3) Reading and Writing serial ports
We use readfile and writefile to read and write the serial port. The declaration of the two functions is as follows:
Bool readfile (handle hfile, // serial port handle // read data storage address, // that is, the read data will be stored in the lpvoid lpbuffer, DWORD nnumberofbytestoread, lpvoid lpbuffer, // The number of bytes of the data to be read // point to a DWORD value, which returns the number of bytes actually read by the read operation lpdword lpnumberofbytesread, // when overlapping operations are performed, this parameter points to an overlapped structure. During synchronization, this parameter is null. Lpoverlapped); bool writefile (handle hfile, // serial port handle // the address of the written data storage, // nnumberofbytestowrite // The data in bytes starting with the pointer value will be written into the sending data buffer of the serial port. Lpvoid lpbuffer, DWORD nnumberofbytestowrite, // number of bytes of data to be written // point to a DWORD value, which returns the number of bytes actually written lpdword lpnumberofbyteswritten. // when overlapping operations are performed, this parameter points to an overlapped structure. // during synchronization, this parameter is null. Lpoverlapped );
When readfile and writefile are used to read and write the serial port, both synchronous and overlapping operations can be performed. During synchronous execution, the function continues until the operation is complete.
. This means that the thread will be blocked during synchronization execution, resulting in lower efficiency. When overlapping operations are performed, these two functions are immediately executed even if the operation is not completed.
Returned. Time-consuming I/O operations are performed in the background.
Whether the readfile and writefile functions are synchronous or asynchronous depends on the createfile function. If you specify
The file_flag_overlapped flag indicates that operations performed on the handle by calling readfile and writefile should overlap;
If no overlap flag is specified, the read/write operations are synchronized. The synchronous or asynchronous functions of readfile and writefile should be used with createfile.
Functions are consistent. The readfile function reads a specified number of characters in the serial port input buffer, even if the operation is completed. The writefile function not only
You need to merge a specified number of characters into the output buffer, and the operation is completed only after these characters are sent out from the serial port.
If the operation is successful, both functions return true. Note that when readfile and writefile return false,
The operation may not necessarily fail. The thread should call the getlasterror function to analyze the returned results.
For example, if the operation is not completed before the overlapping operation, the function returns false, and the getlasterror function returns
Error_io_pending. This indicates that the overlap operation is not completed yet.
Synchronous reading and writing of serial ports is relatively simple. The following example shows the code for Synchronous reading and writing of serial ports:
// Synchronous reading of serial char STR [100]; DWORD wcount; // number of bytes read bool breadstat; breadstat = readfile (hcom, STR, 100, & wcount, null ); if (! Breadstat) {afxmessagebox ("failed to read the serial port! "); Return false;} return true; // synchronous writing serial char lpoutbuffer [100]; DWORD dwbyteswrite = 100; COMSTAT; DWORD dwerrorflags; bool bwritestat; clearcommerror (hcom, & dwerrorflags, & COMSTAT); bwritestat = writefile (hcom, lpoutbuffer, dwbyteswrite, & dwbyteswrite, null); If (! Bwritestat) {afxmessagebox ("failed to write the serial port! ");} Purgecomm (hcom, purge_txabort | purge_rxabort | purge_txclear | purge_rxclear );
When overlapping operations are performed, the function is returned if the operation is not completed.
Overlapping I/O is flexible, and it can also implement blocking (for example, we can set that we must read a data before proceeding to the next operation ). There are two ways to wait for the Operation to complete: one is to wait for the hevent Member of the overlapped structure with a wait function like waitforsingleobject; the other is to call the getoverlappedresult function to wait, the description will be demonstrated later.
The overlapped structure and the getoverlappedresult function are described as follows:
Overlapped Structure
The overlapped structure contains overlapping I/O information, which is defined as follows:
typedef struct _OVERLAPPED { // o DWORD Internal; DWORD InternalHigh; DWORD Offset; DWORD OffsetHigh; HANDLE hEvent; } OVERLAPPED;
When the readfile and writefile overlapping operations are used, the thread needs to create an overlapped structure for the two functions to use.
The thread obtains the current operation status through the overlapped structure. The most important member of this structure is the hevent. Hevent is a read/write event.
When the serial port uses asynchronous communication, the operation may not be completed when the function returns, and the program can check whether the read/write is complete by checking the event.
When the readfile and writefile functions are called, the Member is automatically set to the stateless state. After the overlap operation is complete,
This member variable is automatically set to a signal state.
Getoverlappedresult function bool getoverlappedresult (handle hfile, // serial port handle // point to the overlapped structure specified at the beginning of the overlap operation lpoverlapped, // point to a 32-bit variable, the value of this variable returns the number of bytes transmitted by the actual read/write operation. Lpdword lpnumberofbytestransferred, // this parameter is used to specify whether the function waits until the overlap operation ends. // If this parameter is true, the function will not return until the operation is complete. // If this parameter is set to false, the function returns directly. If the operation is not completed, // by calling the getlasterror () function, error_io_incomplete is returned. Bool bwait );
This function returns the result of the overlapped operation to determine whether the asynchronous operation is complete. It is implemented by determining whether the hevent In the overlapped structure is set.
Sample Code for asynchronous serial port reading:
Char lpinbuffer [1024]; DWORD dwbytesread = 1024; COMSTAT; DWORD dwerrorflags; overlapped m_osread; memset (& m_osread, 0, sizeof (overlapped); bytes = createevent (null, true, false, null); clearcommerror (hcom, & dwerrorflags, & COMSTAT); dwbytesread = min (dwbytesread, (DWORD) COMSTAT. cbinque); If (! Dwbytesread) return false; bool breadstatus; breadstatus = readfile (hcom, lpinbuffer, dwbytesread, & dwbytesread, & m_osread); If (! Breadstatus) // If the readfile function returns false {If (getlasterror () = error_io_pending) // The getlasterror () function returns error_io_pending, indicating that the serial port is performing read Operations {waitforsingleobject, 2000); // use the waitforsingleobject function to wait until the read operation is completed or the delay has reached 2 seconds. // After the serial port read operation is completed, m_osread's hevent event will become a signal purgecomm (hcom, purge_txabort | purge_rxabort | purge_txclear | purge_rxclear); Return dwbytesread;} return 0;} purgecomm (hcom, purge_txabort | purge_rxabort | purge_txclear | purge_rxclear); Return dwbytesread;
A brief description of the above Code: Use the clearcommerror function to clear errors before using the readfile function for read operations.
The clearcommerror function is prototype as follows:
Bool clearcommerror (handle hfile, // serial port handle lpdword lperrors, // point to the variable lpcomstat lpstat that receives the error code // point to the communication status buffer );
This function gets a communication error and reports the current status of the serial port. It also clears the serial port error mark to continue the input and output operations.
The lpstat parameter points to a COMSTAT structure, which returns the serial port status information. The COMSTAT structure contains serial port information,
The structure is defined as follows:
typedef struct _COMSTAT { // cst DWORD fCtsHold : 1; // Tx waiting for CTS signal DWORD fDsrHold : 1; // Tx waiting for DSR signal DWORD fRlsdHold : 1; // Tx waiting for RLSD signal DWORD fXoffHold : 1; // Tx waiting, XOFF char rec''d DWORD fXoffSent : 1; // Tx waiting, XOFF char sent DWORD fEof : 1; // EOF character sent DWORD fTxim : 1; // character waiting for Tx DWORD fReserved : 25; // reserved DWORD cbInQue; // bytes in input buffer DWORD cbOutQue; // bytes in output buffer } COMSTAT, *LPCOMSTAT;
This document only uses the cbinque member variable. The value of this member variable represents the number of bytes in the input buffer.
Finally, use the purgecomm function to clear the input and output buffer of the serial port.
This Code uses the waitforsingleobject function to wait for hevent members in the overlapped structure. Next we will demonstrate a sample code of asynchronous reading serial port waiting to call the getoverlappedresult function:
Char lpinbuffer [1024]; DWORD dwbytesread = 1024; bool breadstatus; DWORD dwerrorflags; COMSTAT; overlapped m_osread; clearcommerror (hcom, & dwerrorflags, & COMSTAT); If (! COMSTAT. cbinque) return 0; dwbytesread = min (dwbytesread, (DWORD) COMSTAT. cbinque); breadstatus = readfile (hcom, lpinbuffer, dwbytesread, & dwbytesread, & m_osread); If (! Breadstatus) // If the readfile function returns false {If (getlasterror () = error_io_pending) {getoverlappedresult (hcom, & m_osread, & dwbytesread, true ); // The last parameter of the getoverlappedresult function is set to true. // The function waits until the read operation is completed or the result is returned due to an error. Return dwbytesread;} return 0;} return dwbytesread;
Sample Code for asynchronous serial port writing:
char buffer[1024];DWORD dwBytesWritten=1024;DWORD dwErrorFlags;COMSTAT ComStat;OVERLAPPED m_osWrite;BOOL bWriteStat;bWriteStat=WriteFile(hCom,buffer,dwBytesWritten,&dwBytesWritten,&m_OsWrite);if(!bWriteStat){if(GetLastError()==ERROR_IO_PENDING){WaitForSingleObject(m_osWrite.hEvent,1000);return dwBytesWritten;}return 0;}return dwBytesWritten;
(4) disable the serial port
Using the API function to close the serial port is very simple. You only need to use the handle returned by the createfile function as the parameter to call closehandle:
BOOL CloseHandle( HANDLE hObject; //handle to object to close );
An example of serial ProgrammingTo help you better understand the serial programming, We will compile two routines (see the source code section ).
The serial communication of the Baxter display instrument through the RS485 interface. The first routine uses synchronous serial port operations, and the second routine uses asynchronous serial port operations.
We will only introduce the software, but do not introduce the RS485 interface wiring method. Interested readers can refer to the relevant information.
Routine 1
Open VC ++ 6.0, create a project rs485comm Based on the dialog box, and add two buttons in the idd_rs485comm_dicomm window of the Main Dialog Box,
The IDS are idc_send and idc_receive, And the titles are "send" and "receive" respectively. A static text box idc_disp is added to display the serial port
Received content.
Add the global variable to the rs485commdlg. cpp file:
Handle hcom; // global variable, serial port handle
Add the following code to the oninitdialog () function in the rs485commdlg. cpp file:
// Todo: add extra initialization herehcom = createfile ("COM1", // COM1 port generic_read | generic_write, // allow read and write 0, // exclusive mode null, open_existing, // open instead of creating 0, // synchronization mode null); If (hcom = (handle)-1) {afxmessagebox ("failed to open com! "); Return false;} setupcomm (hcom, 100,100); // the size of the input buffer and output buffer is 1024 commtimeouts timeouts; // set the read timeout timeouts. readintervaltimeout = maxdword; timeouts. readtotaltimeoutmultiplier = 0; timeouts. readtotaltimeoutconstant = 0; // after reading the content of the input buffer, the read operation returns immediately, regardless of whether the required characters are read. // Set the write timeout timeouts. writetotaltimeoutmultiplier = 100; timeouts. writetotaltimeoutconstant = 500; setcommtimeouts (hcom, & Timeouts); // set the timeout DCB; getcommstate (hcom, & DCB); DCB. baudrate = 9600; // The baud rate is 9600dcb. bytesize = 8; // each byte has eight DCB bits. parity = noparity; // No parity bit DCB. stopbits = twostopbits; // two stop bits setcommstate (hcom, & DCB); purgecomm (hcom, purge_txclear | purge_rxclear );
Double-click the idc_send button and the idc_receive button to add the response functions of the two buttons:
Void crs485commdlg: onsend () {// todo: add your control notification handler code here // here we need to briefly introduce the communication protocol of Baxter xma5000: // The RS485 communication of the instrument adopts the host broadcast mode. // Serial half-duplex, 11-bit frame, 1 start bit (0), 8 data bits, 2 Stop bits (1) // For example, the instantaneous value displayed by the reading instrument, which is sent by the Host: DC1 aaa bb etx // where: DC1 is a control symbol of the standard ASCII code and the code value is 11 h (17 in decimal format) // In the xma5000 communication protocol, DC1 indicates that the read instantaneous value // AAA is the slave address code, that is, the xma5000 shows the meter's mailing address // BB is the channel number, when reading the instantaneous value, this value is 01 // etx, which is also a control symbol of the standard ASCII code. The code value is 03 h // In the xma5000 communication protocol, etx indicates the host Terminator char lpoutbuffer [7]; memset (lpoutbuffer, ''/0'', 7 ); // The first seven bytes are first cleared by lpoutbuffer [0] = ''/x11''; // The 1st bytes of the sending buffer are dc1lpoutbuffer [1] = ''0 ''; // The 2nd bytes are the characters 0 (30 h) lpoutbuffer [2] = '0 ''; // 3rd Bytes: 0 (30 h) lpoutbuffer [3] = '1'; // 4th Bytes: 1 (31 H) lpoutbuffer [4] = '0'; // 5th bytes are 0 (30 h) lpoutbuffer [5] = '1 ''; // The third byte is the character 1 (31 H) lpoutbuffer [6] = ''/x03''; // The third byte is the character etx // you can see from the code of this section, the instrument mailing address is 001 DWORD protocol = 7; COMSTAT; DWORD dwerrorflags; bool bwritestat; clearcommerror (hcom, & dwerrorflags, & COMSTAT); bwritestat = writefile (hcom, lpoutbuffer, dwbyteswrite, & dwbyteswrite, null); If (! Bwritestat) {afxmessagebox ("failed to write the serial port! ") ;}} Void crs485commdlg: onreceive () {// todo: add your control notification handler code herechar STR [100]; memset (STR,''/0 '', 100); DWORD wcount = 100; // number of bytes read bool breadstat; breadstat = readfile (hcom, STR, wcount, & wcount, null); If (! Breadstat) afxmessagebox ("failed to read the serial port! "); Purgecomm (hcom, purge_txabort | purge_rxabort | purge_txclear | purge_rxclear); m_disp = STR; updatedata (false );}
You can observe the returned string, which is the same as the display value of the instrument. You can perform corresponding string operations to retrieve the display value of the instrument.
Open classwizard, add the cstring type variable m_disp to the static text box idc_disp, and add the corresponding function of wm_close:
Void crs485commdlg: onclose () {// todo: add your message handler code here and/or call default closehandle (hcom); // close the serial port cdialog when the program exits :: onclose ();}
The corresponding part of the program has been described in detail in the code. Connect the hardware part, compile and run the program, and carefully understand the serial synchronous operation part.
Routine 2
Open VC ++ 6.0, create a project rs485comm Based on the dialog box, and add two buttons in the idd_rs485comm_dicomm window of the Main Dialog Box,
The IDS are idc_send and idc_receive, And the titles are "send" and "receive" respectively. Add a static text box idc_disp for display.
Content received by the serial port. Add the global variable to the rs485commdlg. cpp file:
Handle hcom; // global variable,
Add the following code to the oninitdialog () function of the serial port handle in the rs485commdlg. cpp file:
Hcom = createfile ("COM1", // COM1 port generic_read | generic_write, // allow read and write 0, // exclusive mode null, open_existing, // open instead of creating file_attribute_normal | file_flag_overlapped, // The overlap mode is null); If (hcom = (handle)-1) {afxmessagebox ("failed to open com! "); Return false;} setupcomm (hcom, 100,100); // the size of the input buffer and output buffer is 100 commtimeouts timeouts; // set the read timeout timeouts. readintervaltimeout = maxdword; timeouts. readtotaltimeoutmultiplier = 0; timeouts. readtotaltimeoutconstant = 0; // after reading the content of the input buffer, the read operation returns immediately, regardless of whether the required characters are read. // Set the write timeout timeouts. writetotaltimeoutmultiplier = 100; timeouts. writetotaltimeoutconstant = 500; setcommtimeouts (hcom, & Timeouts); // set the timeout DCB; getcommstate (hcom, & DCB); DCB. baudrate = 9600; // The baud rate is 9600dcb. bytesize = 8; // each byte has eight DCB bits. parity = noparity; // No parity bit DCB. stopbits = twostopbits; // two stop bits setcommstate (hcom, & DCB); purgecomm (hcom, purge_txclear | purge_rxclear );
Double-click the idc_send button and the idc_receive button to add the response functions of the two buttons:
Void outputs: onsend () {// todo: add your control notification handler code hereoverlapped m_oswrite; memset (& m_oswrite, 0, sizeof (overlapped); outputs = createevent (null, true, false, null); char lpoutbuffer [7]; memset (lpoutbuffer, ''/0'', 7); lpoutbuffer [0] = ''/X11 ''; lpoutbuffer [1] = '0'; lpoutbuffer [2] = '0'; lpoutbuffer [3] = '1 ''; lpoutbuffer [4] = '0'; lpoutbuffer [5] = '1'; lpoutbuffer [6] = ''/x03''; d Word success = 7; COMSTAT; DWORD dwerrorflags; bool bwritestat; clearcommerror (hcom, & dwerrorflags, & COMSTAT); bwritestat = writefile (hcom, lpoutbuffer, success, & success, & m_oswrite); If (! Bwritestat) {If (getlasterror () = error_io_pending) {waitforsingleobject (m_oswrite.hevent, 1000) ;}} void crs485commdlg: onreceive () {// todo: add your control notification handler code hereoverlapped m_osread; memset (& m_osread, 0, sizeof (overlapped); m_osread.hevent = createevent (null, true, false, null); COMSTAT; DWORD dwerrorflags; char STR [100]; memset (STR, ''/0'', 100); DWORD dwbytesread = 100; // number of bytes read bool B Readstat; clearcommerror (hcom, & dwerrorflags, & COMSTAT); dwbytesread = min (dwbytesread, (DWORD) COMSTAT. cbinque); breadstat = readfile (hcom, STR, dwbytesread, & dwbytesread, & m_osread); If (! Breadstat) {If (getlasterror () = error_io_pending) // The getlasterror () function returns error_io_pending, indicating that the serial port is reading {waitforsingleobject (m_osread.hevent, 2000 ); // use the waitforsingleobject function to wait until the read operation is completed or the delay has reached 2 seconds. // After the serial port read operation is completed, m_osread's hevent event will become a signal} purgecomm (hcom, purge_txabort | purge_rxabort | purge_txclear | purge_rxclear); m_disp = STR; updatedata (false );}
Open classwizard, add the cstring type variable m_disp to the static text box idc_disp, and add the corresponding function of wm_close:
Void crs485commdlg: onclose () {// todo: add your message handler code here and/or call default closehandle (hcom); // close the serial port cdialog when the program exits :: onclose ();}
You can carefully compare the two routines to understand the differences between synchronous and asynchronous operations on the serial port.