Basic principle of serial communication and use MFC to implement serial communication programming

zhaozj2021-02-17  60

In the development of Windows applications, we often need to face problems with peripheral data source devices. Both computer and microcontrollers (such as MCS-51) have serial communication ports to design corresponding serial communication programs to complete data communication tasks between them. It is very much when using serial ports in actual work. There are some articles to introduce serial programming published on computer magazines. But the total feelings are not comprehensive, especially the 32-bit programming, and it is very unharequentiful. The author has accumulated more experience in practical work, combined with hardware, software, and focusing on comparing new technologies, and needs to pay attention to the point of view. I hope to have some help to friends who need to write a serial communication program. One. The basic principle of serial communication The essential function of serial port is an encoded converter between CPU and serial devices. When the data is sent from the CPU through the serial port, byte data is converted to a serial bit. When receiving data, the serial bit is converted to byte data. Under the Windows environment (Windows NT, Win98, Windows 2000), serial port is part of the system resource. The application is to communicate using the serial port. The resource application requirements (open serial port) must be filed to the operating system before use, and the resources must be released after the communication is complete. The process of serial communication programs is shown below: II. The connection of serial port signal lines A complete RS-232C interface has 22 wires, using standard 25-core socket (or 9-core plug-in). The 25 core and the main signal line of the 9th core are the same. The following introduction is as an example of 25 core RS-232C. 1 Main signal line definition: 2 foot: send data TXD; 3 foot: receive data RXD; 4 foot: request to send RTS; 5 foot: Clear Send CTS; 6 foot: Data Equipment Ready DSR; 20 Heart: Data terminal Ready DTR; 8-pin: Data carrier detection DCD; 1 foot: Protective ground; 7 foot: Signal ground. 2 Electrical characteristics: The data transmission rate is up to 20K bps, the maximum distance is only 15m. Note: I have seen Microsoft's MSDN 6.0, and the serial communication device in the Windows API (not necessarily serial port RS-232C or RS-422 or RS-449) Rate setting, up to RS_256000, 256K BPS! Norwareness, what is the serial communication device? However, in any case, the general host and the single-chip serial communication are mostly at 9600 bps, which can meet the communication needs. 3 Typical application of the interface: Most computer application systems and smart units can work with only 3 to 5 signal lines. At this time, in addition to TXD, RXD, RTS, CTS, DCD, DTR, DSR, etc. are required. (Of course, the corresponding signal line is also required in the program.) The above connection, when the program is designed, the reception and transmission of the data directly, does not require judgment or setting of the state of the signal line. (If the application is required, you need to use a handshake signal, etc., you need to monitor or set the status of the corresponding signal line.

)three. 16-bit serial application Simple review In the 16-bit serial application, the 16-bit Windows API communication function: 1 OpenComm () opens the serial resource and specifies the input, output the size of the buffer (in bytes); CloseComm () Turn off the serial port; int idcomdev; idcomdev = Opencomm ("COM1", 1024, 128); CloseComm (IDCOMDEV); 2 Buildcommdcb (), setcommstate () Fill in the device control block DCB, then perform the open serial port to perform parameters Configuration; example: DCB DCB; Buildcommdcb ("COM1: 2400, N, 8, 1", & DCB); SetCommState (& DCB); 3 Readcomm, WriteComm () is read and write on the serial port, i.e., data reception, and transmission. Example : Char * m_precieve; int count; readcomm (idcomdev, m_precieve, count); char WR [30]; int count2; writecomm (idcomdev, wr, count2); 16-bit serial communication program's largest feature is: serial port, etc. The operation of the external device has its own unique API function; and 32-bit programs will unite serial operation (and parallel port, etc.) and file operations, using similar operations. four. 32-bit serial application 32-bit serial communication programs under the MFC can be implemented in two ways: using the ActiveX control; use the API communication function. Using the ActiveX control, the program is very simple, the structure is clear, the disadvantage is that it is indeed inherently; the advantages and disadvantages of the API communication function are basically opposite. The following describes a program that adds serial communication capabilities in a single document (SDI) application. (I) Using the ActiveX Control: The MSCOMM control provided by VC 6.0 sends and receives data via the serial port, providing a serial communication function for the application. It is very convenient to use, but unfortunately, there are very few information about the MSCOMM control. (1). Insert the MSCOMM control in the current Workspace. Project Menu -----> Add to Project ----> Components and Controls ----> Registered ActiveX Controls ---> Select Components: Microsoft Communications Control, Version 6.0 inserted into the current Workspace. The result is added CMSCOMM (and corresponding files: MSCOMM.H and MSComm.cpp). (2). Add MSCOMM controls in Mainfrm.h.

Protected: cmscomm m_comport; in mainfrm.cpp :: oncreare (): DWORD style = ws_visible | ws_child; if (! m_comport.create (null, style, crect (0, 0), this, id_commctrl)) {Trace0 ("Failed to Create Ole Communications Control"); Return -1; // Fail to create} (3). Initializing serial port m_comport.setcommport (1); // Select COM? M_comport. Setinbuffersize (1024); // Setting The size of the buffer, bytesm_comport. SetoutBuffersize (512); // Set the size of the input buffer, bytes // if (! M_comport.getPortopen ()) // Open the serial port m_comport.setportopen (TRUE); m_comport.setInputMode (1) ; // Setting the input mode m_comport.setSettings ("9600, N, 8, 1"); // Setting the baud rate or the like M_comport.sethreshold (1); / / 1 means there is a character to trigger an event m_comport.setInputlen (0); ⑷. Capture the serial entity. The MSCOMM control can obtain data from the port with polling or event-driven methods. We introduce the comparison Event Drive Method: The program is notified when there is an event (such as receiving data). These communication events are required and processed in the program. In MainFrm.h in: protected: afx_msg void OnCommMscomm (); DECLARE_EVENTSINK_MAP () in MainFrm.cpp in: BEGIN_EVENTSINK_MAP (CMainFrame, CFrameWnd) ON_EVENT (CMainFrame, ID_COMMCTRL, 1, OnCommMscomm, VTS_NONE) // mapping ActiveX control events END_EVENTSINK_MAP () . The serial port is read or written. The function of the read and written function is indeed very simple, getInput () and setOutput () can. The prototype of the two functions is: Variant GetInput (); and Void SetOutput (Const Variant & NewValue); use the Variant Type (all IDispatch :: invoke parameters and return values ​​are processed as a Variant object). Whether in the PC read data or when the PC is sent to the downlink command, we are used to using the form of a string (or as an array form). Check out the Variant documentation, you can use BSTR to represent a string, but unfortunately all BSTR is included in the wide character, even if we don't define _unicode_unicode is also true! Winnt supports wide characters, while Win95 does not support.

In order to solve the above problem, we use CByteArray in actual work to give the appropriate partial programs as follows: void cmainframe :: oncommmscomm () {variant VRESPONSE; INT K; if (m_commctrl.getcommmevent () == 2) {k = m_commctrl .GetinbufferCount (); // received character number IF (k> 0) {vResponse = m_commctrl.getinput (); // readsavedata (k, (unsigned char *) vresponse.parray-> pvdata);} // Receive To the characters, MSCOMM control sends event}. . . . . // Handle other MSCOMM control} void cmainframe :: oncommsend () {. . . . . . . . // Prepare the command to send, put in TXData [] CByteArray array; array.removeall (); for (i = 0; IARRAY.SETAT (I, TXData [i]); m_comport. SetOutput (Colevariant (array)); // Send data} Please pay attention to the contents of the first, ⑸, focus on actual work, difficult to point. II III use 32-bit API communication functions: Many friends will feel surprised: Writing a serial communication program with a 32-bit API function, isn't it to change the 16-bit API to 32 bits? The 16-bit serial communication program can be a lot of people in many years ago ... This article mainly wants to introduce the serial port in the API How to combine non-blocking communication, multi-threading, etc., write high quality communication programs. In particular, when the CPU processing task is heavy, there is a large number of communication data in the peripheral device. 1 1 1 Mainfrm.cpp defines global variables handle hcom; // Prepare the handle hndsmwatchthread; // assist thread global function (2). Open the serial port HCOM = CreateFile ("COM2", generic_read | generic_write, // Allow reading Write 0, // This item must be 0 null, // no security attrs open_existing, // setting generation method file_flag_overlapped, // We are ready to use asynchronous communication null); please pay attention to, we use the file_flag_overlapped structure. This is useful The key to the API implements non-blocking communication.

Assert (hcom! = Invalid_handle_value); // Detects whether the open serial operation is successful setcommmask (hcom, ev_rxchar | ev_txempty); // Set the type setUpComm (HCOM, 1024, 512) of the event-driven, // set input, output buffer size PurgeComm (hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); // clean and clear input, output buffer COMMTIMEOUTS CommTimeOuts; // define a timeout structure, the structure and fill ............ SetCommTimeouts (hCom, & CommTimeOuts); // set The timeout DCB DCB that is allowed by reading and writing; // Defines the data control block structure getcommstate (hcom, & dcb); // read the original parameter setting dcb.baudrate = 9600; dcb.bytesize = 8; dcb.parity = noparity; DCB.Stopbits = onestopbit; dcb.fbinary = true; dcb.fparity = false; setcommstate (hcom, & dcb); // Serial port parameter Configuration The above COMMTIMEOUTS structure and DCB are very important, actually need to be carefully selected parameters. (3) Start an auxiliary thread for processing of serial events. Windows offers two threads, auxiliary threads, and user interface threads. The difference is that the auxiliary thread has no windows, so it does not have its own message loop. But the auxiliary thread is easy to program, and is usually very useful. At times, we use the auxiliary thread. It mainly uses it to monitor the serial port state, see if there is no number, there is no error; and the main thread can focus on data processing, providing a friendly user interface and other important work. HCommwatchthread = CreateThread ((LPSecurity_attributes) null, // security attribute 0, // Initialized thread stack size, default is the same as the main thread size (lpthread_start_routine "CommWatchProc, // thread global function getSafehWnd (), // here Passing the handle 0, & dwthread! = Null; ⑷⑷); Note how the Overlapped structure is used, and how to achieve non-blocking communication.

Uint CommWatchProc (HWND HSENDWND) {DWORD DWEVTMASK = 0; setcommmask (hcom, ev_rxchar | ev_txempty); // What are the serial events need to be monitored? Waitcommmevent (HCOM, & DWEVTMASK, OS); // Wait for the detection of the serial port communication event to detect DWEVTMASK, know what serial port event: if (DWEVTMASK & EV_RXCHAR) == EV_RXCHAR) {// Buffer has data to arrive in COMSTAT COMSTAT; DWORD DWLENGTH; ClearcomMerror (hcom, & dwerrorflags, & comstat); DWLENGTH = comStat.cbinque; // How many data is there included in the buffer? if (dwLength> 0) {BOOL fReadStat; fReadStat = ReadFile (hCom, lpBuffer, dwLength, & dwBytesRead; & READ_OS (npTTYInfo)); // read data Note: We used the FILE_FLAG_OVERLAPPED (time) at CreareFile, now the ReadFile () must be Using the LPOVERLAPPED structure. Otherwise, the function will correctly report the read operation. Using the lpoverlapped structure, readfile () immediately returns, do not wait for the read operation to complete, realize non-blocking communication. At this point, readfile () Returns false, getLastError ) returns ERROR_IO_PENDING.if (fReadStat) {if (GetLastError (!) == ERROR_IO_PENDING) {while) {dwError = GetLastError () (GetOverlappedResult (hCom, & READ_OS (npTTYInfo), & dwBytesRead, TRUE!); if (dwError == ERROR_IO_INCOMPLETE) Continue; // Buffer data is not finished, continue ... ... :: postMessage ((hwnd) hsendwnd, wm_notifyprocess, 0, 0); // Notify the main thread, serial port receive data} so-called non-blocking communication Also asynchronous communications. When the data read and write operation that needs to spend a lot of time (not only the serial communication operation), the readFile (), WriteFile () can be called immediately, and the actual read and write operation is running in the background. Conversely, if using blocking communication, you must return after the read or write operation is completed. Since the operation may require any long time to complete, then the problem will appear. Very obstruction operation also allows reading, write operations can be carried out at the same time (ie overlapping operations?) Is very useful in actual work. To use non-blocking communication, you must use file_flag_overlapped when CreateFile (); then at ReadFile (), the lpoverlapped parameter must not be NULL, then check the return value of the function call, call getLastError (), see if returning error_io_pending.

转载请注明原文地址:https://www.9cbs.com/read-30732.html

New Post(0)