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

📄 serialport.cpp

📁 串口通信高级编程
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// SerialPort.cpp: implementation of the CSerialPort class.

#include "stdafx.h"     //这一行让人生气, 如果没有,VC6里如果使用MFC将不能编译
#include "SerialPort.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

DWORD WINAPI CSerialPort::MonitorCommThreadProc(LPVOID lpParameter)
{
    static OVERLAPPED ov_Read;		//异步读串口时用到的重叠结构
	ov_Read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    volatile LPMONITORCOMMPARAMS lpParam;

    if (NULL == lpParameter) 
    {
        return -1;
    }
    lpParam = (LPMONITORCOMMPARAMS)lpParameter;
    if ( (lpParam->hCommPort) == INVALID_HANDLE_VALUE) 
    {
        ProcessErrorMessage(TEXT("串口句柄无效,串口监控线程无法工作."));
        return -1;
    }
    // 清空串口缓冲区, 退出所有相关操作 
    PurgeComm( lpParam->hCommPort,
        PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
    COMSTAT ComStat;    // 串口状态
    DWORD dwEvent, dwError, dwResult; 
    // 进入无限循环, 直到线程被关闭 
    while ( !(lpParam->bTerminated) ) 
    {
        //调用WaitCommEvent().这一调用将立即返回,因为用异步方式
        //(FILE_FLAG_OVERLAPPED)打开串口,并且指定重叠操作结构,
        //如果有一个字符到达串口,重叠结构中的事件将被置为有信号态
        BOOL bResult = WaitCommEvent(   (lpParam->hCommPort), 
                                        &dwEvent,
                                        &ov_Read	);
        if (!bResult) 
        {
            // 如果WaitCommEvent()返回FALSE,调用GetLastError()判断原因
            dwError = GetLastError();
            switch(dwError) 
            {
            case ERROR_IO_PENDING:      //重叠操作正在后台进行
                // 如果串口这时无字符,这是正常返回值,继续
            	break;
            case 87:
                //在WIN NT下这是一个可能结果,但我没有找到
                //它出现的原因,我什么也不做,继续
                break;
            default:
                //所有其它错误代码均显示串口出错,显示出错信息
                ProcessErrorMessage(TEXT("等待串口事件"));
                return -1;    // return;  ?????????????????????????????
            }
        }
        else
        {
            //如果WaitCommEvent()返回true,检查输入缓冲区是否确实有字节可读,
            //若没有,则继续下一循环
            //ClearCommError()将更新串口状态结构并清除所有串口硬件错误
            ClearCommError( (lpParam->hCommPort), &dwError, &ComStat);
            if (ComStat.cbInQue == 0)   //输入缓冲队列长为0,无字符
            {
                continue;
            }
        }
        // 等待串口事件产生 
        dwResult = WaitForSingleObject( ov_Read.hEvent, 1000); //???????????
        if (dwResult == WAIT_OBJECT_0)  // 事件产生 
        {
            // 获取串口事件掩码 
            GetCommMask( (lpParam->hCommPort), &dwEvent );
            if (dwEvent & EV_RXCHAR)    // 有一个字符
            {
                CSerialPort::ReceiveAChar(lpParam, &ov_Read);    //接收一个字符
            }
        }
    }
	CloseHandle(ov_Read.hEvent);
    return 0;
}

void CSerialPort::ReceiveAChar(LPMONITORCOMMPARAMS lpParameter, LPOVERLAPPED lpOv)
{
    COMSTAT ComStat;
    DWORD   dwError = 0;
    BOOL    bResult;
    DWORD   BytesRead = 0;
    char	ucRxBuff;
    if (lpParameter == NULL || lpParameter->hCommPort == NULL) 
    {
        return;
    }
    //开始无限循环,因为我不知到需要循环多少次.我的解决方法是开始一个无限循环,
    //当我已处理了所有的有效数据后才退出.使用这种方法应小心的保证您的程序能
    //正常退出循环.即便如此,我仍觉得这是最有效的解决办法
    while(TRUE)
    {
        // ClearCommError()将更新串口状态结构并清除所有串口硬件错误 
        ClearCommError( (lpParameter->hCommPort), &dwError, &ComStat);
        if (ComStat.cbInQue == 0) 
        {
            // 缓冲区中已无数据, 退出循环 
            break;
        }
        // 读串口 
        bResult = ReadFile( (lpParameter->hCommPort), 
            &ucRxBuff,
            1,
            &BytesRead,
            lpOv);
        TRACE(_T("bResult = %d\n"), bResult);
        if (IsNT()) 
        {
            bResult = GetOverlappedResult( (lpParameter->hCommPort), 
                lpOv, &BytesRead, TRUE);
            if ( ! bResult )
            {
                ProcessErrorMessage(TEXT("ReceiveAChar(): GetOverlappedResult() failed"));
                return ;
            }
        }
        else if (!bResult)
        {
            switch(dwError = GetLastError()) 
            {
            case ERROR_IO_PENDING:  // 重叠操作在后台进行 
                BytesRead = 0;
                // 等待重叠操作结果 
                bResult = GetOverlappedResult(  (lpParameter->hCommPort),//串口句柄
                    lpOv,      //重叠结构
                    &BytesRead,                 //实际读入字符数
                    TRUE);              //等待直到串口操作超时
                if (!bResult) // 重叠操作失败 
                {
                    ProcessErrorMessage(TEXT("(读串口时)获取重叠操作结果"));
                    return; 
                }
                break;
            default:
                ProcessErrorMessage(TEXT("Read SerialPort"));
                return;
            }
        }
        if (BytesRead != 1) 
        {
            continue;
        }
        // 将收到的字符当作消息的参数投递到父窗口
#ifndef UNICODE
        PostMessage( (lpParameter->hwndParent), WM_COMM_RXCHAR, (WPARAM)ucRxBuff, NULL);
#else
        union tagRutBuff
        {
            WORD wBuffer;
            BYTE byteBuffer[2];
            DWORD dwDummy;
        };
        static tagRutBuff  uReturn;
        if (uReturn.byteBuffer[0] == '\0' ) 
        {
            uReturn.byteBuffer[0] = ucRxBuff;
            if ( uReturn.byteBuffer[0] < 0x80 ) // 这里有 BUG , 0x80 这个值有待修正 
            {
                PostMessage((lpParameter->hwndParent), 
                            WM_COMM_RXCHAR, 
                            (WPARAM)uReturn.wBuffer, 
                            NULL);
                uReturn.wBuffer = 0;
            }
        }
        else
        {
            uReturn.byteBuffer[1] = ucRxBuff;
            int iLength = MultiByteToWideChar(  CP_ACP, 
                                                0, 
                                                (LPCSTR)(&(uReturn.byteBuffer[0])), 
                                                2, 
                                                NULL, 
                                                0); 
            PWSTR   pWideStr = (PWSTR)malloc(iLength  * sizeof(WCHAR)); 
            MultiByteToWideChar(CP_ACP, 
                                0, 
                                (LPCSTR)(&(uReturn.byteBuffer[0])), 
                                2, 
                                pWideStr, 
                                iLength); 
            PostMessage((lpParameter->hwndParent), 
                WM_COMM_RXCHAR, 
                (WPARAM)(*pWideStr), 
                NULL);
            free(pWideStr);
            uReturn.wBuffer = 0;
        }
#endif  // UNICODE
    }
}

CSerialPort::CSerialPort()
{
    m_hComm = INVALID_HANDLE_VALUE;     // 串口句柄
    m_hMonitorThread = INVALID_HANDLE_VALUE;     // 监控线程句柄
    m_ov_Write.hEvent = CreateEvent(NULL, TRUE, FALSE, TEXT("")); 
    m_hwndParent = NULL; 

    // 线程过程的参数清零 
    memset(&m_Param, 0, sizeof(m_Param));
}

CSerialPort::~CSerialPort()
{
    m_Param.bTerminated = TRUE; //告诉监控线程结束循环
    StartMonitoring();      // 如果监控线程已经挂起, 则在结束它之前启动它.
    if (m_ov_Write.hEvent) 
    {
        CloseHandle(m_ov_Write.hEvent);
        m_ov_Write.hEvent = NULL;
    }
    if (m_hMonitorThread != INVALID_HANDLE_VALUE) 
    {
        CloseHandle(m_hMonitorThread);
        m_hMonitorThread = NULL; 
    }

    if (m_hComm != INVALID_HANDLE_VALUE) 
    {
        CloseHandle(m_hComm);
    }
}

void CSerialPort::ProcessErrorMessage(LPTSTR ErrorText)
{
    TCHAR ErrorMsg[400];
    LPVOID lpMsgBuf;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,GetLastError(),     //获取错误信息标识
        MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),//使用系统缺省语言
        (LPTSTR)&lpMsgBuf, //消息缓冲区
        0,
        NULL);
    wsprintf(ErrorMsg, TEXT("\"%s\" 由于以下错误而失败: \n\n%s"),ErrorText,lpMsgBuf); 
    MessageBox(NULL/*m_hwndParent*/, ErrorMsg, TEXT("串口错误"), MB_ICONSTOP); 
    LocalFree(lpMsgBuf); 
}

//启动串口监控线程
void CSerialPort::StartMonitoring()
{
    ResumeThread(m_hMonitorThread); 
}

//挂起线程
void CSerialPort::StopMonitoring()
{
    SuspendThread(m_hMonitorThread); 
}

//向串口写一个字符
BOOL CSerialPort::WriteToPort(TCHAR ucTxChar)
{
	DWORD iLength = 1;
    if (m_hComm == INVALID_HANDLE_VALUE || m_hComm == NULL) 
    {
        MessageBox(m_hwndParent, 

⌨️ 快捷键说明

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