6 years ago (2015-08-06)  Software development |   First to comment  17140 
post score 5 times, average 2.0

In industrial control, industrial computers (usually based on the Windows platform) often need to communicate with smart meters through the serial port.Serial communication is convenient and widely used. Under normal circumstances, IPCs and smart meters communicate through the RS485 bus.The communication mode of RS485 is half-duplex, and can only be polled by the industrial PC as the master node in turn to the sub-nodes of each intelligent control unit on the network.Each communication is issued by the PC through the serial port to the intelligent control unit and the intelligent control unit responds after receiving the correct command. C/C++ Serial Communication Principle and Read, Write and Operate In Win32, you can use two programming methods to achieve serial communication, the first is the use of ActiveX controls, this method is simple, but less flexible.The second is to call the Windows API function, this method can clearly grasp the serial communication mechanism, and free and flexible.In this article we only introduce the API serial communication section. The operation of the serial port can have two operation modes: synchronous operation mode and overlapping operation mode (also called asynchronous operation mode). In synchronous operation, the API function will block until the operation is completed to return (in multi-thread mode, although the main thread will not block, but still block the listener thread); and overlap operation, API function will immediately return, operation in the background Go ahead and avoid thread blocking. Regardless of the type of operation, it is generally done in four steps:

  • (1) Open the serial port
  • (2) Configure the serial port
  • (3) Read and write serial ports
  • (4) Close the serial port

1, open the serial port

The Win32 system extends the concept of the file.Whether it is a file, a communication device, a named pipe, a mail slot, a disk, or a console, it is created or created using the API function CreateFile.The prototype of this function is:

C++ code

  • lpFileName: logical name of the serial port to open, such as "COM1";
  • dwDesiredAccess: Specifies the type of serial access, which can be read, write, or both;
  • dwShareMode: Specifies the shared attribute. Since the serial port cannot be shared, this parameter must be set to 0.
  • lpSecurityAttributes: reference security attribute structure, the default value is NULL;
  • dwCreationDistribution: Create flag, this parameter must be set to OPEN_EXISTING for serial operation;
  • dwFlagsAndAttributes: attribute description used to specify whether the serial port for asynchronous operations, the value is FILE_FLAG_OVERLAPPED, said the use of asynchronous I / O; the value of 0, said synchronous I / O operations;
  • hTemplateFile: This parameter must be set to NULL for the serial port.

Example code to open the serial port in synchronous I/O mode: C++ code


Example code for overlapping I/O to open the serial port:

C++ code


2, configure the serial port

After opening the communication device handle, it is often necessary to perform some initial configuration work on the serial port.This needs to be done through a DCB structure.The DCB structure contains information such as baud rate, number of data bits, parity, and stop bits.When querying or configuring the properties of the serial port, use the DCB structure as a buffer. Generally use CreateFile to open the serial port, you can call GetCommState function to get the initial configuration of the serial port.To modify the configuration of the serial port, you should first modify the DCB structure, and then call the SetCommState function to set the serial port. The DCB structure contains various parameter settings of the serial port. The following describes only a few variables commonly used in this structure: typedef struct _DCB{ ......... DWORD BaudRate;// baud rate, specifies the transmission rate of the communication device.This member can be either an actual baud rate value or one of the following constant values: CBR_110, CBR_300, CBR_600, CBR_1200, CBR_2400, CBR_4800, CBR_9600, CBR_19200, CBR_38400, CBR_56000, CBR_57600, CBR_115200, CBR_128000, CBR_256000, CBR_14400 DWORD fParity; / / Specifies parity check enable.If this member is 1, allow parity check ... BYTE ByteSize; / / communication byte number, 4-8 BYTE Parity; / / specify the parity method.This member can have the following values: EVENPARITY Even check NOPARITY No check MARKPARITY Check check ODDPARITY Odd check BYTE StopBits; //Specify the number of stop bits.This member can have the following values: ONESTOPBIT 1 stop bit TWOSTOPBITS 2 stop bits ON 5 STOPBITS 1.5 stop bits The GetCommState function can get the COM port device control block to obtain the relevant parameters:

  In addition to the settings in the BCD, the program generally also needs to set the I/O buffer size and timeout.Windows uses I/O buffers to temporarily store serial input and output data.If the communication rate is high, a larger buffer should be set.Call the SetupComm function to set the input and output buffer size of the serial port. BOOL SetupComm( HANDLE hFile, // Handle of communication device DWORD dwInQueue, // Input buffer size (number of bytes) DWORD dwOutQueue // Output buffer size (bytes)); Read and write with ReadFile and WriteFile When serial port, you need to consider overtime issues.The role of the timeout is to not read or send the specified number of characters within the specified time, the ReadFile or WriteFile operation will still end. To query the current timeout settings, call the GetCommTimeouts function, which populates a COMMTIMEOUTS structure.Calling SetCommTimeouts can set the timeout with the contents of one of the COMMTIMEOUTS structures. There are two kinds of timeout for reading and writing serial ports: interval timeout and total timeout.Interval timeout refers to the maximum delay between two characters when receiving.The total timeout refers to the maximum amount of time spent on reading and writing operations.Write operations only support total timeouts, while read operations support both timeouts.Use the COMMTIMEOUTS structure to specify the timeout for read and write operations. The COMMTIMEOUTS structure is defined as:

  Members of the COMMTIMEOUTS structure are all in milliseconds. The total time-out calculation formula is: Total timeout = time coefficient × number of characters required to read / write + time constant For example, to read 10 characters, the total timeout for the read operation is calculated as: Read total timeout = ReadTotalTimeoutMultiplier × 10 + ReadTotalTimeoutConstant It can be seen that the setting of interval timeout and total timeout is irrelevant, which can facilitate the communication program to flexibly set various timeouts. If all write timeout parameters are 0, no write timeout is used.If ReadIntervalTimeout is 0, read interval timeout is not used.If ReadTotalTimeoutMultiplier and ReadTotalTimeoutConstant are both 0, the read timeout is not used.If the read interval timeout is set to MAXDWORD and both the read time coefficient and the read time constant are 0, the read operation returns immediately after reading the contents of the input buffer, regardless of whether the required character was read. When reading and writing to the serial port with overlap, although ReadFile and WriteFile may return before completing the operation, the timeout still works.In this case, the timeout specifies the completion time of the operation, not the return time of ReadFile and WriteFile.

Configure the sample code for the serial port:

  Before reading and writing the serial port, we must use the PurgeComm () function to empty the buffer, the function prototype: BOOL PurgeComm (HANDLE hFile, / / ​​serial handle DWORD dwFlags / / need to complete the operation); parameter dwFlags specified to complete the operation, you can Is a combination of the following values: PURGE_TXABORT interrupts all writes and returns immediately, even if the write operation has not been completed. PURGE_RXABORT interrupts all read operations and returns immediately, even if the read operation has not been completed. PURGE_TXCLEAR clear output buffer PURGE_RXCLEAR clear input buffer

3, read and write serial

We use ReadFile and WriteFile to read and write the serial port. Here are the declarations of the two functions:

When reading and writing serial ports with ReadFile and WriteFile, they can be executed synchronously or overlapped.In synchronous execution, the function does not return until the operation is completed.This means that threads are blocked during synchronous execution, resulting in reduced efficiency.In the overlapped execution, even if the operation is not completed yet, these two functions will return immediately and time-consuming I/O operations will be performed in the background. Whether the ReadFile and WriteFile functions are synchronous or asynchronous is determined by the CreateFile function. If the FILE_FLAG_OVERLAPPED flag is specified when the CreateFile handle is called, the operation of calling the ReadFile and WriteFile on the handle should be overlapped; if the overlap flag is not specified, then read Write operations should be synchronized.Synchronous or asynchronous ReadFile and WriteFile functions should be consistent with the CreateFile function. The ReadFile function simply completes the operation by reading the specified number of characters in the serial input buffer.The WriteFile function not only copies the specified number of characters into the output buffer, but also waits for these characters to be sent from the serial port before the operation is completed. If the operation is successful, both functions return TRUE.It should be noted that when ReadFile and WriteFile return FALSE, it is not necessarily an operation failure. The thread should call the GetLastError function to analyze the returned result.For example, if the operation is returned without completing the function during overlapping operations, the function returns FALSE, and the GetLastError function returns ERROR_IO_PENDING.This shows that the overlap operation has not been completed yet. Synchronous way to read and write the serial port is relatively simple, the following example illustrates the way to read and write the serial port synchronization:

  In the overlap operation, the operation is returned without completing the function. Overlapping I/O is very flexible, and it can also achieve blocking (for example, we can set a must-read data to proceed to the next step).There are two ways to wait for the operation to complete: one way is to wait for the hEvent member of the OVERLAPPED structure with a wait function like WaitForSingleObject; the other way is to wait for the call to the GetOverlappedResult function, which will be demonstrated later. Let's briefly talk about the OVERLAPPED structure and the GetOverlappedResult function: OVERLAPPED structure The OVERLAPPED structure contains some information about overlapping I/O, defined as follows:

  When using the ReadFile and WriteFile overlap operations, the thread needs to create an OVERLAPPED structure for use by these two functions.The thread obtains the current operating state through the OVERLAPPED structure. The most important member of this structure is hEvent.hEvent is a read-write event.When the serial port uses asynchronous communication, the operation may not be completed when the function returns. The program can check whether the reading and writing are completed by checking this event. When the ReadFile, WriteFile function is called, the member is automatically set to the no-signal state; when the overlap operation is completed, the member variable is automatically set to the signal state. GetOverlappedResult function BOOL GetOverlappedResult( HANDLE hFile, // Serial port handle // points to the OVERLAPPED structure specified at the beginning of the overlap operation LPOVERLAPPED lpOverlapped, // points to a 32-bit variable whose value returns the number of bytes actually transferred for read and write operations. LPDWORD lpNumberOfBytesTransferred, // This parameter is used to specify whether the function waits until the end of the overlap operation. // If this parameter is TRUE, the function does not return until the end of the operation. // If this parameter is FALSE, the function returns directly. At this time, if the operation is not completed, // ERROR_IO_INCOMPLETE will be returned by calling GetLastError() function. BOOL bWait ); This function returns the result of the overlap operation, used to determine whether the asynchronous operation is completed, it is achieved by determining whether the hEvent in the OVERLAPPED structure is set.

Example code for asynchronously reading the serial port:


Make a brief description of the above code:

Before using the ReadFile function for read operations, clear the error using the ClearCommError function. The prototype of the ClearCommError function is as follows:

  This function obtains a communication error and reports the current status of the serial port. At the same time, this function clears the error flag of the serial port to continue input and output operations. The parameter lpStat points to a COMSTAT structure, which returns the serial port status information. The COMSTAT structure COMSTAT structure contains the 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 article only used the cbInQue member variable, which is the member variable The value represents the number of bytes in the input buffer. Finally, use the PurgeComm function to clear the input and output buffers of the serial port. This code uses the WaitForSingleObject function to wait for the hEvent member of the OVERLAPPED structure. Next we demonstrate a wait for calling the GetOverlappedResult function.

Asynchronous read serial port example code:


Asynchronous write serial port example code:


4, close the serial port

Using the API function to close the serial port is very simple, just use the handle returned by the CreateFile function as a parameter to call CloseHandle:



This article is organized for Baiyuan's Blog. In order to respect the author's work, reprint please specify the reprint address: Http://www.jizhuomi.com/software/309.html, if you think this article is useful to you, you can click on the "Sponsored Author" below the article to reward the author!

Post comment


No Comment


Forget password?