previously on
I wrote two blogs about serial port before
- Virtual serial port simulator and serial port debugging assistant tutorial
- The C language program periodically receives the data sent by the virtual serial port
The first part mainly introduces the use methods and software recommendations of virtual serial port simulator and serial port debugging assistant.
The second part mainly uses the above two software and C language program to periodically receive the data sent by the virtual serial port. The previous C language code is OK for testing, but if serial port communication is required in the actual project, we'd better install the serial port communication package into a reusable module, Next, I will recommend an easy-to-use serial communication module in C + + language, and give an example combined with virtual serial port simulator and serial port debugging assistant.
github address: https://github.com/ayowin/WzSerialPort
Reference blog: Realization of serial communication in windows pure C + +,Using C + + to realize serial communication under windows,[C + +] Windows API serial communication general class source code
First, the code files of the open source project are given. There are only three files. There are not many codes. All of them are posted below:
WzSerialPort.cpp
#include "WzSerialPort.h" #include <stdio.h> #include <string.h> #include <WinSock2.h> #include <windows.h> WzSerialPort::WzSerialPort() { } WzSerialPort::~WzSerialPort() { } bool WzSerialPort::open(const char* portname, int baudrate, char parity, char databit, char stopbit, char synchronizeflag) { this->synchronizeflag = synchronizeflag; HANDLE hCom = NULL; if (this->synchronizeflag) { //Synchronization mode hCom = CreateFileA(portname, //Serial port name GENERIC_READ | GENERIC_WRITE, //Support reading and writing 0, //Exclusive mode, serial port does not support sharing NULL,//Security property pointer, the default value is NULL OPEN_EXISTING, //Open the existing serial port file 0, //0: synchronization mode, FILE_FLAG_OVERLAPPED: asynchronous mode NULL);//Used to copy file handles. The default value is NULL. For serial ports, this parameter must be set to NULL } else { //Asynchronous mode hCom = CreateFileA(portname, //Serial port name GENERIC_READ | GENERIC_WRITE, //Support reading and writing 0, //Exclusive mode, serial port does not support sharing NULL,//Security property pointer, the default value is NULL OPEN_EXISTING, //Open the existing serial port file FILE_FLAG_OVERLAPPED, //0: synchronization mode, FILE_FLAG_OVERLAPPED: asynchronous mode NULL);//Used to copy file handles. The default value is NULL. For serial ports, this parameter must be set to NULL } if(hCom == (HANDLE)-1) { return false; } //Configure buffer size if(! SetupComm(hCom,1024, 1024)) { return false; } // configuration parameter DCB p; memset(&p, 0, sizeof(p)); p.DCBlength = sizeof(p); p.BaudRate = baudrate; // Baud rate p.ByteSize = databit; // Data bit switch (parity) //Check bit { case 0: p.Parity = NOPARITY; //No check break; case 1: p.Parity = ODDPARITY; //Odd check break; case 2: p.Parity = EVENPARITY; //Parity check break; case 3: p.Parity = MARKPARITY; //Mark verification break; } switch(stopbit) //Stop bit { case 1: p.StopBits = ONESTOPBIT; //1 stop bit break; case 2: p.StopBits = TWOSTOPBITS; //2-bit stop bit break; case 3: p.StopBits = ONE5STOPBITS; //1.5 stop bit break; } if(! SetCommState(hCom, &p)) { // set parameters failed return false; } //Timeout processing in milliseconds //Total timeout = time factor × Number of characters read or written + time constant COMMTIMEOUTS TimeOuts; TimeOuts.ReadIntervalTimeout = 1000; //Read interval timeout TimeOuts.ReadTotalTimeoutMultiplier = 500; //Reading time coefficient TimeOuts.ReadTotalTimeoutConstant = 5000; //Read time constant TimeOuts.WriteTotalTimeoutMultiplier = 500; // Write time coefficient TimeOuts.WriteTotalTimeoutConstant = 2000; //Write time constant SetCommTimeouts(hCom,&TimeOuts); PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);//Clear serial port buffer memcpy(pHandle, &hCom, sizeof(hCom));// Save handle return true; } void WzSerialPort::close() { HANDLE hCom = *(HANDLE*)pHandle; CloseHandle(hCom); } int WzSerialPort::send(const void *buf,int len) { HANDLE hCom = *(HANDLE*)pHandle; if (this->synchronizeflag) { // Synchronization mode DWORD dwBytesWrite = len; //Number of data bytes successfully written BOOL bWriteStat = WriteFile(hCom, //Serial port handle buf, //Data header address dwBytesWrite, //Number of data bytes to send &dwBytesWrite, //DWORD *, used to receive and return the number of data bytes successfully sent NULL); //NULL means synchronous transmission, OVERLAPPED * means asynchronous transmission if (!bWriteStat) { return 0; } return dwBytesWrite; } else { //Asynchronous mode DWORD dwBytesWrite = len; //Number of data bytes successfully written DWORD dwErrorFlags; //Error flag COMSTAT comStat; //Communication status OVERLAPPED m_osWrite; //Asynchronous I / O structure //Create an event handler for OVERLAPPED, which will not really be used, but the system requires it memset(&m_osWrite, 0, sizeof(m_osWrite)); m_osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, L"WriteEvent"); ClearCommError(hCom, &dwErrorFlags, &comStat); //Clear the communication error and obtain the current status of the device BOOL bWriteStat = WriteFile(hCom, //Serial port handle buf, //Data header address dwBytesWrite, //Number of data bytes to send &dwBytesWrite, //DWORD *, used to receive and return the number of data bytes successfully sent &m_osWrite); //NULL means synchronous transmission, OVERLAPPED * means asynchronous transmission if (!bWriteStat) { if (GetLastError() == ERROR_IO_PENDING) //If the serial port is writing { WaitForSingleObject(m_osWrite.hEvent, 1000); //Wait for the write event for 1 second } else { ClearCommError(hCom, &dwErrorFlags, &comStat); //Clear communication error CloseHandle(m_osWrite.hEvent); //Close and free haevent memory return 0; } } return dwBytesWrite; } } int WzSerialPort::receive(void *buf,int maxlen) { HANDLE hCom = *(HANDLE*)pHandle; if (this->synchronizeflag) { //Synchronization mode DWORD wCount = maxlen; //Number of data bytes successfully read BOOL bReadStat = ReadFile(hCom, //Serial port handle buf, //Data header address wCount, //Maximum number of bytes of data to read &wCount, //DWORD *, used to receive and return the number of data bytes successfully read NULL); //NULL means synchronous transmission, OVERLAPPED * means asynchronous transmission if (!bReadStat) { return 0; } return wCount; } else { //Asynchronous mode DWORD wCount = maxlen; //Number of data bytes successfully read DWORD dwErrorFlags; //Error flag COMSTAT comStat; //Communication status OVERLAPPED m_osRead; //Asynchronous I / O structure //Create an event handler for OVERLAPPED, which will not really be used, but the system requires it memset(&m_osRead, 0, sizeof(m_osRead)); m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, L"ReadEvent"); ClearCommError(hCom, &dwErrorFlags, &comStat); //Clear the communication error and obtain the current status of the device if (!comStat.cbInQue)return 0; //Returns false if the number of input buffer bytes is 0 BOOL bReadStat = ReadFile(hCom, //Serial port handle buf, //Data header address wCount, //Maximum number of bytes of data to read &wCount, //DWORD *, used to receive and return the number of data bytes successfully read &m_osRead); //NULL means synchronous transmission, OVERLAPPED * means asynchronous transmission if (!bReadStat) { if (GetLastError() == ERROR_IO_PENDING) //If the serial port is reading { //The last parameter of the GetOverlappedResult function is set to TRUE //The function waits until the read operation completes or returns due to an error GetOverlappedResult(hCom, &m_osRead, &wCount, TRUE); } else { ClearCommError(hCom, &dwErrorFlags, &comStat); //Clear communication error CloseHandle(m_osRead.hEvent); //Close and free the memory of heevent return 0; } } return wCount; } }
WzSerialPort.h
#ifndef _WZSERIALPORT_H #define _WZSERIALPORT_H /* Author: Ouyang Wei Date: December 14, 2017 Class name: WZSerialPort Purpose: serial port reading and writing Example: Refer to main cpp */ class WzSerialPort { public: WzSerialPort(); ~WzSerialPort(); // When the serial port is opened, true is returned for success and false is returned for failure // Portname (serial port name): under Windows, it is "COM1", "com2", etc.; under Linux, it is "/ dev/ttyS1", etc // Baudrate: 9600, 19200, 38400, 43000, 56000, 57600, 115200 // Parity: 0 means no parity, 1 means odd parity, 2 means even parity, and 3 means mark parity (only applicable to windows) // Data bit: 4-8(windows),5-8(linux), usually 8 bits // Stopbit: 1 is the 1-bit stop bit, 2 is the 2-bit stop bit, and 3 is the 1.5-bit stop bit // Synchronizeflag (synchronous, asynchronous, only applicable to windows): 0 is asynchronous, 1 is synchronous bool open(const char* portname, int baudrate, char parity, char databit, char stopbit, char synchronizeflag=1); //Close the serial port, parameters to be determined void close(); //When sending data or writing data, the length of the sent data is returned successfully, and 0 is returned if it fails int send(const void *buf,int len); //Accept data or read data, successfully return the length of reading actual data, and fail to return 0 int receive(void *buf,int maxlen); private: int pHandle[16]; char synchronizeflag; }; #endif
main.cpp
#include <iostream> #include "WzSerialPort.h" #include <windows.h> using namespace std; void sendDemo() { WzSerialPort w; if (w.open("COM1", 115200, 0, 8, 1)) //Open COM1 port, baud rate 115200 { cout << "open com1 success!" << endl; for (int i = 0;i < 10;i++) { while(1) { w.send("wuliyuan", 8); Sleep(1000); } } cout << "send demo finished..."; } else { cout << "open serial port failed..."; } } void receiveDemo() { WzSerialPort w; if (w.open("COM1", 115200, 0, 8, 1))//Open COM1 port, baud rate 115200 { char buf[1024]; while (true) { memset(buf, 0,1024); w.receive(buf, 1024); cout << buf << endl; } } } int main(int argumentCount, const char* argumentValues[]) { // Suppose COM1 has been connected to another serial port // Send demo sendDemo(); // Receive demo //receiveDemo(); getchar(); return 0; }
Source code analysis
It can be seen that the serial communication module includes wzserialport CPP and wzserialport H two files. When we need to use them, we only need to add them to our project and include the header file when we need to use them.
example
First use VSPD to open two virtual serial ports
Because we use the program to open COM1, we use the serial port debugging assistant to open COM2.
Next, let's test the sending function, comment out the receiveDemo() in the main function, and test the sending function regardless of the reception.
Run the program as shown below
The serial port debugging assistant is displayed as follows. You can see that the receiving data area continuously receives the data sent by the program
Next, we continue to test the receiving function, comment out the sendDemo function in the main function and cancel the comment of the receiveDemo function.
In addition, we also need to start the cycle sending and set the sending content in the serial port debugging assistant of COM2 port, and click send.
Run the program.
Conclusion: the serial communication module can be used directly by adding it to the project we use.