📄 serialport.cpp
字号:
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 + -