⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial.html

📁 这是一个串口调试程序,带有源代码的,还是比较好用的.
💻 HTML
📖 第 1 页 / 共 3 页
字号:
    DWORD dwBytesRead = 0;
    BYTE  abBuffer[100];
    do
    {
        // Read data from the COM-port
        serial.Read(abBuffer,sizeof(abBuffer),&dwBytesRead);
        if (dwBytesRead > 0)
        {
            // TODO: Process the data
        }
    }
    while (dwBytesRead == sizeof(abBuffer));
</pre>

<p>
 The Listener sample (included in the ZIP-file) demonstrates the
 technique as described above. The entire sample code isn't listed
 in this document, because it would take too much space.
</p>

<h3>
 Using the Win32 synchronization objects
</h3>

<p>
 In most cases, blocking for a single event (as described above) isn't
 appropriate. When the application blocks, then it is completely out
 of your control. Suppose you have created a service which listens on
 multiple COM-ports and also monitors a Win32 event (used to indicate
 that the service should stop). In such a case, you'll need
 multithreading, message queues or the Win32 function for
 synchronization. The synchronization objects are the most efficient
 method to implement this, so I'll try to explain them. Before you
 continue reading I assume you're a bit familiar with the use of the
 synchronization objects and overlapped operations. If you're not,
 then first read the section about Synchronization in the Win32 API.
</p>

<p>
 The only call that blocks for a fairly long time is the
 <code>WaitEvent</code> method. In the next paragraphs, I will show you
 how to implement this call using the Win32 synchronization objects
 (all other overlapped calls work identical). A complete implementation
 can be found in the Overlapped project, which is quite similar to the
 Listener project, but it now uses overlapped I/O.
</p>

<p>
 First the the COM-port needs to be initialized. This works identical
 as in the Listener sample. Then two events are created. The first
 event will be used in the overlapped structure. Note that it should
 be a manual reset event, which is initially not signaled. The second
 one is an external event, which is used to stop the program. The first
 event will be stored inside the <code>OVERLAPPED</code> structure.
<p>

<pre>
    // Create a handle for the overlapped operations
    HANDLE hevtOverlapped = ::CreateEvent(0,TRUE,FALSE,0);;

    // Open the &quot;STOP&quot; handle
    HANDLE hevtStop = ::CreateEvent(0,TRUE,FALSE,_T(&quot;Overlapped_Stop_Event&quot;));

    // Setup the overlapped structure
    OVERLAPPED ov = {0};
    ov.hEvent = hevtOverlapped;
</pre>

<p>
 All events have been setup correctly and the overlapped structure has
 been initialized. We can now call the <code>WaitEvent</code> method
 in overlapped mode.
</p>

<pre>
    // Wait for an event
    serial.WaitEvent(&amp;ov);
</pre>

<p>
 The overlapped I/O operation is now in progress and whenever an event
 occurs, that would normally unblock this call, the event handle in the
 overlapped structure will become signalled. It is not allowed to
 perform an I/O operation on this port, before it has completed, so we
 will wait until the event arrives or the stop event has been set.
</p>

<pre>
    // Setup array of handles in which we are interested
    HANDLE ahWait[2];
    ahWait[0] = hevtOverlapped;
    ahWait[1] = hevtStop;

    // Wait until something happens
    switch (::WaitForMultipleObjects(2,ahWait,FALSE,INFINITE))
    {
    case WAIT_OBJECT_0:
        // Serial port event occurred
        ...

    case WAIT_OBJECT_0+1:
        // Stop event raised
        ...
    }
</pre>

<p>
 That's all you need to do, when you want to use the serial class in
 overlapped I/O mode.
</p>

<h3>
 Using Windows messages
</h3>

<p>
 Most Windows developers are used to receive a Windows message,
 whenever a certain event occurs. This fits perfectly in the Windows
 event-driven model, but the Win32 API doesn't provide such a
 mechanism for serial communication. This library includes a class
 called <code>CSerialWnd</code>, which will send a special message
 whenever a serial event occurs. It is pretty simple, when you are
 already familiar with the event-driven programming model of Windows.
</p>

<p>
 Instead of using the <code>CSerial</code> class, you must use the
 <code>CSerialWnd</code> class (which is in fact derived from
 <code>CSerial</code>). <code>CSerialWnd</code> works just like
 <code>CSerial</code>, but there are some tiny differences in opening
 the port and waiting on its events. Note that the
 <code>CSerialWnd</code> doesn't have a window itself and neither
 should you derive from it, when you want to use it. Just define a
 member variable and use that from within your window.
</p>

<p>
 Because <code>CSerialWnd</code> posts its messages to a window, it
 requires additional information. Therefore the <code>Open</code>
 method accepts three additional parameters, which specify the
 window handle, message and optional argument. The prototype
 looks like:
</p>

<pre>
    LONG Open (
               LPCTSTR lpszDevice, 
               HWND    hwndDest, 
               UINT    nComMsg    = WM_NULL,
               LPARAM  lParam     = 0, 
               DWORD   dwInQueue  = 2048, 
               DWORD   dwOutQueue = 2048
              )
</pre>

<p>
 The <code>lpszDevice</code>, <code>dwInQueue</code> and
 <code>dwOutQueue</code> are used as in <code>CSerial</code>. The
 <code>hwndDest</code> argument specifies the window, where the message
 should be sent to. The library registers a default message during
 startup, which can be used in most cases. Simply pass
 <code>WM_NULL</code> to use this message. The value of this message
 is stored in the <code>CSerialWnd::mg_nDefaultComMsg</code> variable,
 which is a static member variable of <code>CSerialWnd</code>. If
 you prefer one of your own messages, then you can use that instead.
 The optional <code>lParam</code> argument is sent as the second
 parameter (<code>lParam</code>) in each message that is being sent
 by <code>CSerial</code>. The serial library doesn't do anything with
 this value, so be free to use it as you like.
</p>

<p>
 Sending data and setting up the serial port is exactly the same as
 with <code>CSerial</code>, so I won't discuss that again anymore. The
 biggest difference is the way you receive the events, but that is
 exactly why you want to use this class anyway.
</p>

<p>
 If everything is fine, then you have registered all interesting events
 with the <code>SetMask</code> method. Whenever one of these events
 occur, the specified message will be sent to the window you have
 registered before. The <code>wParam</code> will contain the event and
 error-code. The <code>lParam</code> contains whatever you passed to
 <code>CSerialWnd::Open</code>, when you have opened the port. A
 typical handler for these messages looks like:
</p>

<pre>
LRESULT CALLBACK MyWndProc (HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
   if (nMsg == CSerialWnd::mg_nDefaultComMsg)
   {
       // A serial message occurred
       const CSerialWnd::EEvent eEvent = CSerialWnd::EEvent(LOWORD(wParam));
       const CSerialWnd::EError eError = CSerialWnd::EError(HIWORD(wParam));

       switch (eEvent)
       {
       case CSerialWnd::EEventRecv:
           // TODO: Read data from the port
           break;

           ...
       }
         
       // Return successful
       return 0;
   }

   // Perform other window processing
   ...
}
</pre>

<p>
 The methods <code>WaitEvent</code>, <code>GetEventType</code> and
 <code>GetError</code> from <code>CSerial</code> are hidden in the
 <code>CSerialWnd</code> class, because they cannot be used anymore.
 All the information is passed in the window message, so it shouldn't
 be necessary to use them anymore.
</p>

<h3>
 Using the library with MFC
</h3>

<p>
 Personally, I don't like MFC, but I know many people out there use it
 so there is also support in this library for MFC. Instead of using
 <code>CSerialWnd</code>, you can use <code>CSerialMFC</code>. It works
 exactly the same, but it can also handle a <code>CWnd</code> pointer
 and it provides a macro, which can be used in the message map for
 better readability. The message map of a window, which can receive
 events from <code>CSerialMFC</code> should look like this:
</p>

<pre>
    DECLARE_MESSAGE_MAP(CMyClass,CWnd)
        ...
        ON_WM_SERIAL(OnSerialMsg)
        ...
    END_MESSAGE_MAP()
</pre>

<p>
 The handler itself looks something like this:
</p>

<pre>
afx_msg LRESULT CMyClass::OnSerialMsg (WPARAM wParam, LPARAM lParam)
{
    const CSerialMFC::EEvent eEvent = CSerialMFC::EEvent(LOWORD(wParam));
    const CSerialMFC::EError eError = CSerialMFC::EError(HIWORD(wParam));

    switch (eEvent)
    {
    case CSerialMFC::EEventRecv:
        // TODO: Read data from the port
        break;
        ...
    }
   
    // Return successful
    return 0;
}
</pre>

<p>
 A complete sample, including property sheets for setting up the
 COM-port, is shipped with this library. Look for the SerialTestMFC
 project for an example how to use this library in your MFC programs.
</p>

<h2>
 Integrating this library into your code.
</h2>

<p>
 This library is very lightweight, so it can easily be integrated into
 your application without using a separate DLL. I used a static library
 for the <code>CSerial</code> (and derived) classes, because I think
 that is exactly where a library is meant for. Just insert the Serial
 project into your workspace and make a dependency to it. The linker
 will then automatically compile and link the serial classes to your
 application. Some people don't like libraries. In that case you can
 just add the Serial files to your project and recompile.
</p>

<h2>
 References
</h2>

<p>Of course the first place to look for information about serial communications is in the
Platform SDK section &quot;Windows Base Services, Files and I/O, Communications&quot;.
There's probably enough in there to implement your own serial communications, but for a
better explanation read Allen Denver's article called &quot;Serial Communications in
Win32&quot;, which is in the MSDN's Technical Articles.</p>

<h2>Comments and disclaimer</h2>

<p>
 If you have any comments or questions about these classes, then you
 can reach me using email at
 <a href="mailto:R.de.Klein@iaf.nl">R.de.Klein@iaf.nl</a>. This
 library is free for both commercial and non-commercial use (if you
 insist, you can send me money though). Unfortunately, I cannot guarantee any support for these classes. I cannot test every situation
 and the use of these classes is at your own risk.
</p>

<p>
 Because this library is distributed with full source-code included, I
 cannot stop you from changing the code. I don't mind if you change
 the code, but I don't want to be blamed for your bugs. So please mark
 your changes and keep my name in the copyrights as well. If you added
 a cool feature, then please let me know so I can integrate it with a
 new version of this library.
</p>

<p>
 Please don't mirror this code or documentation on another
 website or removable media (such as a CD-ROM) with the intent to
 redistribute it. I don't want to have old versions floating around,
 which might contain bugs that are solved in later versions. Just
 mention the URL where users can download the archive and
 documentation.
</p>

<p>
 I would like to thank my friend and colleague Remon Spekreijse for
 pointing out some problems, adding some features in this library and
 encouraging me to put this library on the net.
</p>

<!-------------------------------    That's it!   --------------------------->
</body>
</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -