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

📄 serialport.cpp

📁 串口通信高级编程
💻 CPP
📖 第 1 页 / 共 2 页
字号:
            TEXT("串口句柄无效,无法发送数据."), 
            TEXT("错误"), MB_ICONSTOP);
        return FALSE;
    }
    // 初始化重叠结构 
    m_ov_Write.Offset = 0;
    m_ov_Write.OffsetHigh = 0;
    // 写串口 
    DWORD dwBytesSent = 0;

#ifdef UNICODE
	const int iBufLen = 16;
	static char szTemp[iBufLen] = { '\0' };
	iLength = WideCharToMultiByte(CP_ACP, 0, &ucTxChar, -1, szTemp, iBufLen, NULL, NULL) - 1;
    BOOL  bResult = WriteFile(  m_hComm, //串口句柄 
                                szTemp, //输出缓冲区 
                                iLength,       //每次发送字符个数
                                &dwBytesSent, //实际发送的字符数 
                                &m_ov_Write); //重叠结构 
#else
    BOOL  bResult = WriteFile(  m_hComm, //串口句柄 
		&ucTxChar, //输出缓冲区 
		iLength,       //每次发送字符个数
		&dwBytesSent, //实际发送的字符数 
		&m_ov_Write); //重叠结构 
#endif

    if ( !bResult )  // 写串口失败
    {
        DWORD dwError = GetLastError(); //得到失败原因
        switch(dwError) 
        {
        case ERROR_IO_PENDING:  //串口操作正在后台进行:
            dwBytesSent = 0;
            //等待重叠结果
            bResult = GetOverlappedResult(  m_hComm, 
                                            &m_ov_Write,
                                            &dwBytesSent,   //实际发送字符数
                                            TRUE);
            if (!bResult)   //重叠操作失败
            {
                return FALSE;
            }
        	break;
        default:    //失败
            return FALSE;
            break;
        }
    }
    // 检查实际发送的字符数是否与要求相符 
    if (dwBytesSent != iLength) 
    {
        return FALSE;
    }
    return TRUE;
}

//串口初始化,可用于串口1到4,参数意义如下:
//hParent-父窗口,dwPortNo-串口号,dwBaud-波特率,cParity-奇偶校验,dwDataBits-数据位数,
//dwStopBits-停止位数, dwCommEvents-需要监控的串口事件
BOOL CSerialPort::InitPort(HWND hParent, DWORD dwPortNo, 
                   DWORD dwBaud, TCHAR cParity, DWORD dwDataBits, DWORD dwStopBits,
                   DWORD dwCommEvents)
{
    if (hParent == NULL) 
    {
        MessageBox(hParent, 
            TEXT("Serial port's Parent Window handle invalid"), 
            NULL, 
            MB_ICONSTOP);
        return FALSE;
    }
    m_hwndParent = hParent;
    TCHAR   szTemp[256];
    if (dwPortNo < 1 || dwPortNo > 4) 
    {
        wsprintf(szTemp, 
            TEXT("Can not open serial port COM%d,\nYou must use COM1 to COM4"), 
            dwPortNo);
        MessageBox(hParent, szTemp, NULL, MB_ICONSTOP);
        return FALSE;
    }
    wsprintf(szTemp, TEXT("COM%d"), dwPortNo); // 合成串口号字符串
    // 打开串口,获取串口句柄 
    HANDLE hTemp = CreateFile(szTemp,    //串口号
        GENERIC_READ|GENERIC_WRITE, //读写方式
        0,                          //通讯设备必须以独占方式打开
        NULL,                       //无安全属性
        OPEN_EXISTING,              //通讯设备已存在
        FILE_FLAG_OVERLAPPED,       //异步 I/O 
        0);                         //通讯设备不能用模板打开
    if (hTemp == INVALID_HANDLE_VALUE)    //句柄无效,打开串口失败 
    {
        wsprintf(szTemp, TEXT("Can not Open Serial Port COM%d"), dwPortNo); 
        MessageBox(hParent, szTemp, NULL, MB_ICONSTOP);
        CloseHandle(hTemp); 
        return FALSE;
    }
    m_hComm = hTemp;
    // 设置超时参数, 总时间 = Multiplier * 字符数 + Constant 
    // Interval 为读入的字符串中任意两个字符间的最大间隔 
    m_CommTimeouts.ReadIntervalTimeout = 1000; 
    m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000; 
    m_CommTimeouts.ReadTotalTimeoutConstant = 1000;
    m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000;
    m_CommTimeouts.WriteTotalTimeoutConstant = 1000; 
    // 配置串口 
    if (SetCommTimeouts(m_hComm, &m_CommTimeouts))  //超时参数
    {
        if (SetCommMask(m_hComm, dwCommEvents))     //需要监控的事件
        {
            if (GetCommState(m_hComm, &m_CommDCB))  //获取原始DCB
            {
                // 禁止硬流控, 因为本系统不需要 
                m_CommDCB.fOutxCtsFlow = FALSE;
                m_CommDCB.fOutxDsrFlow = FALSE;
                m_CommDCB.fDsrSensitivity = FALSE;
                m_CommDCB.fDtrControl = DTR_CONTROL_DISABLE; 
                m_CommDCB.fRtsControl = RTS_CONTROL_DISABLE;
                m_CommDCB.BaudRate = dwBaud;
                // 合成串口参数字符串 
                wsprintf(szTemp, TEXT("baud=%d parity=%c data=%d stop=%d"), 
                        dwBaud, cParity, dwDataBits, dwStopBits);
// 设置串口设备控制块(DCB), 下边这个API有BUG, 只有在奇偶校验设置为"无"时才正常
                if (BuildCommDCB(szTemp, &m_CommDCB)) 
                {
                    if ( !SetCommState(m_hComm, &m_CommDCB)) 
                    {
                        ProcessErrorMessage(TEXT("设置串口"));
                    }
                }
                else
                    ProcessErrorMessage(TEXT("建立串口设备控制块"));
            }
            else
                ProcessErrorMessage(TEXT("获取串口状态")); 
        }
        else
            ProcessErrorMessage(TEXT("设置串口事件掩码"));
    }
    else
        ProcessErrorMessage(TEXT("串口超时参数设置"));
    // 清空串口缓冲区, 退出所有相关操作 
    PurgeComm(m_hComm, PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);

    DWORD temp;
    m_Param.hCommPort = m_hComm;
    m_Param.hwndParent = m_hwndParent;
    // 创建串口监控线程 
    m_hMonitorThread = CreateThread(NULL, 0, 
        CSerialPort::MonitorCommThreadProc,  // 线程处理过程的函数地址
        &m_Param,               // 传递给线程过程的参数
        CREATE_SUSPENDED,       // 线程创建以后是挂起状态 
        &temp); 
    if (m_hMonitorThread == INVALID_HANDLE_VALUE) 
    {
        ProcessErrorMessage(TEXT("创建线程"));
        return FALSE;
    }
    return TRUE;
}

BOOL CSerialPort::IsNT(VOID)
{
    OSVERSIONINFO osvi;
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionEx(&osvi);
    if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) 
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}


BOOL CSerialPort::WriteToPort(LPCTSTR lpszOutPut)
{
    if (m_hComm == INVALID_HANDLE_VALUE || m_hComm == NULL) 
    {
        MessageBox(m_hwndParent, 
            TEXT("Serial Port not OPEN or not present"), NULL, MB_ICONSTOP);
        return FALSE;
    }
    DWORD nNumberOfBytesToWrite = _tcslen(lpszOutPut); 
    DWORD nNumberOfBytesWritten = 0;
#ifdef UNICODE 
    char  *lpszTemp = new char[(nNumberOfBytesToWrite + 1) * 2];
	nNumberOfBytesToWrite = WideCharToMultiByte(CP_ACP, 
                                                0, 
                                                lpszOutPut, 
                                                -1, 
                                                lpszTemp,
                                                (nNumberOfBytesToWrite + 1) * 2, 
                                                NULL, 
                                                NULL);
    BOOL  bResult = WriteFile(  m_hComm, //串口句柄 
								(LPCVOID)lpszTemp,  
								nNumberOfBytesToWrite,       //每次发送字符个数
								&nNumberOfBytesWritten, //实际发送的字符数 
								&m_ov_Write); //重叠结构 
#else
    // 向串口写字符串 
    BOOL bResult = WriteFile(   m_hComm,    
                                (LPCVOID)lpszOutPut, 
                                nNumberOfBytesToWrite,  // 想要发送的字符串的长度 
                                &nNumberOfBytesWritten, // 实际发送的字符串的长度 
                                &m_ov_Write);           // 异步发送所需要的重叠结构体 
#endif
//*
        // 这段代码让人黯然神伤 在 Debug 版时, 将会在GetOverlappedResult()函数处挂起
        // 而在 Release 版时则很正常 
        if ( IsNT() )
        {
            bResult = GetOverlappedResult(m_hComm, &m_ov_Write, &nNumberOfBytesWritten, TRUE);
            if ( ! bResult )
            {
                CloseHandle(m_ov_Write.hEvent);
                ProcessErrorMessage(TEXT("WriteToPort(): GetOverlappedResult() failed"));
                return FALSE;
            }
        }    
        else 
//*/
    if (!bResult) 
    {
        DWORD dwError = GetLastError();
        switch(dwError) 
        {
        case ERROR_IO_PENDING: 
            nNumberOfBytesWritten = 0;
            bResult = GetOverlappedResult(  m_hComm,
                                            &m_ov_Write,
                                            &nNumberOfBytesWritten,//实际发送的字符数
                                            TRUE);         // 如果操作未完成则等待
            if ( !bResult )  
			{
#ifdef UNICODE 
                delete lpszTemp;
#endif
                return FALSE;
			}
        	break;
        case ERROR_INVALID_PARAMETER:
            // 不知道什么原因, 如果是DEBUG版, 返回的错误码肯定是这个, 大家凑合用吧 
            break;
        default:
#ifdef UNICODE 
			delete lpszTemp;
#endif
            return FALSE;
            break;
        }
    }
    if ( nNumberOfBytesWritten != nNumberOfBytesToWrite ) 
	{
#ifdef UNICODE 
		delete lpszTemp;
#endif
        return FALSE;
	}
#ifdef UNICODE 
	delete lpszTemp;
#endif
    return TRUE;
}

⌨️ 快捷键说明

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