MFC实现的串口通信助手
需要用到VC串口调试程序,于是写了一个串口调试助手作参考,源码地址:http://download.csdn.net/detail/hc260164797/4360519,欢迎大家拍砖~~
程序界面是
串口设置是,9600波特率,8数据位,1位停止位,无校验位
该程序实现两个线程,一个线程串口读数据,并更新界面,一个座位主界面和串口发送数据。
主要实现函数:
1.枚举所有可用串口:
//枚举串口
void EnumerateSerialPorts(CUIntArray& ports)
{
//Make sure we clear out any elements which may already be in the array
ports.RemoveAll();
//Determine what OS we are running on
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
BOOL bGetVer = GetVersionEx(&osvi);
//On NT use the QueryDosDevice API
if (bGetVer && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT))
{
//Use QueryDosDevice to look for all devices of the form COMx. This is a better
//solution as it means that no ports have to be opened at all.
TCHAR szDevices[65535];
DWORD dwChars = QueryDosDevice(NULL, szDevices, 65535);
if (dwChars)
{
int i=0;
for (;;)
{
//Get the current device name
TCHAR* pszCurrentDevice = &szDevices[i];
//If it looks like "COMX" then
//add it to the array which will be returned
int nLen = _tcslen(pszCurrentDevice);
if (nLen > 3 && _tcsnicmp(pszCurrentDevice, _T("COM"), 3) == 0)
{
//Work out the port number
int nPort = _ttoi(&pszCurrentDevice[3]);
ports.Add(nPort);
}
// Go to next NULL character
while(szDevices[i] != _T('\0'))
i++;
// Bump pointer to the next string
i++;
// The list is double-NULL terminated, so if the character is
// now NULL, we're at the end
if (szDevices[i] == _T('\0'))
break;
}
}
else
TRACE(_T("Failed in call to QueryDosDevice, GetLastError:%d\n"), GetLastError());
}
else
{
//On 95/98 open up each port to determine their existence
//Up to 255 COM ports are supported so we iterate through all of them seeing
//if we can open them or if we fail to open them, get an access denied or general error error.
//Both of these cases indicate that there is a COM port at that number.
for (UINT i=1; i<256; i++)
{
//Form the Raw device name
CString sPort;
sPort.Format(_T("\\\\.\\COM%d"), i);
//Try to open the port
BOOL bSuccess = FALSE;
HANDLE hPort = ::CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if (hPort == INVALID_HANDLE_VALUE)
{
DWORD dwError = GetLastError();
//Check to see if the error was because some other app had the port open or a general failure
if (dwError == ERROR_ACCESS_DENIED || dwError == ERROR_GEN_FAILURE)
bSuccess = TRUE;
}
else
{
//The port was opened successfully
bSuccess = TRUE;
//Don't forget to close the port, since we are going to do nothing with it anyway
CloseHandle(hPort);
}
//Add the port number to the array which will be returned
if (bSuccess)
ports.Add(i);
}
}
}
2.初始化串口:
void CSerial1AppDlg::OnBnClickedOpencomBtn()
{
// TODO: 在此添加控件通知处理程序代码
/*串口的初始化*/
CString str_com=L"";
com_combobox.GetWindowTextW(str_com);
hCom=CreateFile(str_com,GENERIC_READ|GENERIC_WRITE,
0,NULL,OPEN_EXISTING,0,NULL); //打开串口
if(hCom==(HANDLE)-1)
{
MessageBox(L"打开COM失败!");
}
else{
open_btn.EnableWindow(FALSE);
close_btn.EnableWindow(TRUE);
send_btn.EnableWindow(TRUE);
com_combobox.EnableWindow(FALSE);
SetupComm(hCom,100,100); //输入缓冲区和输出缓冲区的大小都是100
COMMTIMEOUTS TimeOuts;
//设定读超时
TimeOuts.ReadIntervalTimeout=MAXDWORD;
TimeOuts.ReadTotalTimeoutMultiplier=0;
TimeOuts.ReadTotalTimeoutConstant=0;
//在读一次输入缓冲区的内容后读操作就立即返回,
//而不管是否读入了要求的字符。
//设定写超时
TimeOuts.WriteTotalTimeoutMultiplier=100;
TimeOuts.WriteTotalTimeoutConstant=500;
SetCommTimeouts(hCom,&TimeOuts); //设置超时
DCB dcb;
GetCommState(hCom,&dcb);
dcb.BaudRate=9600; //波特率为9600
dcb.ByteSize=8; //每个字节有8位
dcb.Parity=NOPARITY; //无奇偶校验位
dcb.StopBits=ONESTOPBIT ; //停止位
SetCommState(hCom,&dcb);
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
//创建新线程读取串口数据
hThread_receiver=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)UpdateUIThread, this, 0, (unsigned long *)&ThreadID);
}
}
3.串口发送:
HCURSOR CSerial1AppDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CSerial1AppDlg::OnBnClickedSendBtn()
{
// TODO: 在此添加控件通知处理程序代码
//UpdateData(true);
CString str_senddata=L"";
send_edit.GetWindowTextW(str_senddata);//需要发送到数据
CStringA str_senddataA="";
str_senddataA=CStrW2CStrA(str_senddata);
int len=str_senddata.GetLength();
DWORD dwBytesWrite=len;
COMSTAT ComStat;
DWORD dwErrorFlags;
BOOL bWriteStat;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
bWriteStat=WriteFile(hCom,str_senddataA,dwBytesWrite,&
dwBytesWrite,NULL);
if(!bWriteStat)
{
MessageBox(L"写串口失败!");
}
}
4.读串口,并更新界面:
//读数据
CString readdata(){
char str[100];
memset(str,'\0',100);
DWORD wCount=100;//读取的字节数
BOOL bReadStat;
bReadStat=ReadFile(hCom,str,wCount,&wCount,NULL);
if(!bReadStat){
AfxMessageBox(L"读串口失败!,点击确定关闭程序");
exit(0);
}
PurgeComm(hCom, PURGE_TXABORT|
PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
return (CString)str;
}
//更新线程函数
void UpdateUIThread(CSerial1AppDlg *p){
CString str=L"";
CString str_previous=L"";
while(1){
str_previous=str;
str.Append(readdata());
if(str_previous!=str){
p->receive_edit.SetWindowTextW(str);
}
//p->SendMessage(WM_MYUPDATEDATA,FALSE);
}
}