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

📄 serial.cpp

📁 Wince下的串口通讯
💻 CPP
字号:
// Serial.cpp: implementation of the CSerial class.
  
//
  
////////////////
  
#include "stdafx.h"
#include "Serial.h"

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


HANDLE hPort;//声明串口句柄,作为全局变量
HWND m_hWnd;//用于向调用该类成员的对话框发送信息

const BYTE STR={0x3};//定义帧头和帧尾
//////////////////////////////////////////
// Construction/Destruction
CSerial::CSerial()
{
}
CSerial::~CSerial()
{
    if(hPort != INVALID_HANDLE_VALUE)
     ClosePort();
}
BOOL CSerial::OpenPort(CString lpszPortName,HWND hWnd,UINT m_strCom1)
{
	m_hWnd=hWnd;//将调用对话框的窗口句柄赋给m_hWnd,以备在ReadPortThread中使用
    DWORD dwError, dwThreadID;
    if(hPort)//如果hport为0说明串口没有打开
	{
		MessageBox (NULL, TEXT("你已经打开该串口!"),TEXT("错误!"), MB_OK);
        return FALSE;
	}
    //打开串口
//	MessageBox (NULL, TEXT("测试!"),TEXT("错误!"), MB_OK);
    hPort = CreateFile (lpszPortName, GENERIC_READ|GENERIC_WRITE,0, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);
    //如果打开端口出错, 返回FALSE
    if ( hPort == INVALID_HANDLE_VALUE ) 
	{
		//不能打开端口
        CString strError;
        strError.Format(_T("不能打开  %s, 错误编号=%d"),lpszPortName, GetLastError());
        MessageBox (NULL, strError,TEXT("错误!"), MB_OK);
        return FALSE;
	}
    //指定端口监测的事件集
    //SetCommMask (hPort, EV_RXCHAR|EV_TXEMPTY); 
    //配置串行端口
    if(!InitDCB(m_strCom1))
    return FALSE;
    //设置端口超时值
    if(!InitCommTimeouts())
    return FALSE;
    //分配设备缓冲区  
    SetupComm(hPort,512,512);
    //初始化缓冲区中的信息
    PurgeComm(hPort,PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
    ///设置端口上指定信号的状态
    // SETDTR: 发送DTR (data-terminal-ready)信号
    // SETRTS: 发送RTS (request-to-send)信号
    EscapeCommFunction(hPort,SETDTR);
    EscapeCommFunction(hPort,SETRTS);

    //创建一个从串口读取数据的线程
    if (hReadThread = CreateThread (NULL, 0, ReadPortThread, 0, 0,&dwThreadID))
    {

        CloseHandle(hReadThread);
    }
    else
	{
		//不能创建线程
		MessageBox (NULL, TEXT("不能创建线程!"), TEXT("错误!"), MB_OK);
		dwError = GetLastError ();
		return FALSE;
	}
	//m_bConnected=TRUE;//程序返回真时就必是初始化成功,所以这个变量其实不需要,以节省内存
    return TRUE;
}

DWORD CSerial::WritePort(TCHAR *buf,DWORD dwCharToWrite)
{
    BOOL fWriteState;
    DWORD dwBytesWritten;
	//buf=buf-1;
	//buf[0]=STR;//加入帧头
    //dwCharToWrite++;//待写入数据加1
	//buf[dwCharToWrite]=STR;//加入帧头
	//dwCharToWrite++;
    //写入数据
	//PurgeComm(hPort,PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
	PurgeComm(hPort,0);
    
	if(!hPort)
	{
		MessageBox(NULL,TEXT("你没有打开串口!"),TEXT("错误!"),MB_OK);
		return 0;
	}
	else
	{
		fWriteState=WriteFile(hPort,(BYTE *)buf,dwCharToWrite*sizeof(TCHAR),&dwBytesWritten,NULL);
		if(!fWriteState)
		{
			//不能写数据
			MessageBox(NULL,TEXT("写串口数据失败!"),TEXT("错误!"),MB_OK);
			dwBytesWritten=0;
		}
	}
	//PurgeComm(hPort,PURGE_TXCLEAR|PURGE_RXCLEAR);
    return dwBytesWritten;
}

BOOL CSerial::ClosePort()
{
    if (hPort != INVALID_HANDLE_VALUE)
	{
		//结束线程中WaitCommEvent的等待
		SetCommMask(hPort,0);
		//阻塞至线程停止
		if(hReadThread)
		{
			 //仅做提示性质,意义不大
			// if(MessageBox(NULL,TEXT("串口数据读取线程正在进行!你确定要关闭吗?"),TEXT("警告!"),MB_YESNO))
			 
			 TerminateThread(hReadThread,0);//阻塞线程
			 CloseHandle(hReadThread);
			 hReadThread=0;
		
		}
		//清除端口上指定信号的状态
		EscapeCommFunction(hPort,CLRDTR);
		EscapeCommFunction(hPort,CLRRTS);
		//清除驱动程序内部的发送和接收队列
		PurgeComm(hPort,PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
		//关闭串口
		CloseHandle (hPort);
		hPort = 0;//使串口句柄恢复到初始状态
		return TRUE;

	}
    else
	{
		hPort=0;//使串口句柄恢复到初始状态
		return TRUE;
	}
}

BOOL CSerial::InitDCB(UINT m_strCom1)

{

    DCB PortDCB;//声明一个DCB结构
    DWORD dwError;
    PortDCB.DCBlength = sizeof (DCB);//初始化 DCBlength
    //得到端口的默认设置信息
    GetCommState (hPort, &PortDCB);
	//改变DCB结构设置
    PortDCB.BaudRate =m_strCom1;//9600; //波特率 
    PortDCB.fBinary = TRUE; //Win32不支持非二进制串行传输模式,必须为TRUE 
    PortDCB.fParity = TRUE; //启用奇偶校验 
	PortDCB.fOutxCtsFlow = FALSE; //串行端口的输出由CTS线控制
    PortDCB.fOutxDsrFlow = FALSE;//关闭串行端口的DSR流控制
    PortDCB.fDtrControl = DTR_CONTROL_ENABLE; //启用DTR线
    PortDCB.fDsrSensitivity = FALSE; //如果设为TRUE将忽略任何输入的字节,除非DSR线被启用 
    PortDCB.fTXContinueOnXoff = TRUE;//当为TRUE时,如果接收缓冲区已满且驱动程序已传送XOFF字符,将使驱动程序停止传输字符
    PortDCB.fTXContinueOnXoff = FALSE;
    PortDCB.fOutX = FALSE;//设为TRUE指定XON/XOFF控制被用于控制串行输出 
    PortDCB.fInX = FALSE; //设为TRUE指定XON/XOFF控制被用于控制串行输入 
    PortDCB.fErrorChar = FALSE;//WINCE串行驱动程序的默认执行将忽略这个字段 
    PortDCB.fNull = FALSE;//设为TRUE将使串行驱动程序忽略收到的空字节 
    PortDCB.fRtsControl = RTS_CONTROL_ENABLE; //启用RTS线 
    PortDCB.fAbortOnError = FALSE; //WINCE串行驱动程序的默认执行将忽略这个字段
    PortDCB.ByteSize = 8; //每字节的位数 
    PortDCB.Parity = NOPARITY;//无奇偶校验 
    PortDCB.StopBits = ONESTOPBIT; //每字节一位停止位 
    //根据DCB结构配置端口
    if (!SetCommState (hPort, &PortDCB))
	{
		//不能配置串行端口
        MessageBox (NULL, TEXT("不能配置串口!"),TEXT("错误!"), MB_OK);
        dwError = GetLastError ();//获得错误原因的代码
        return FALSE;
	}
    return TRUE;
}
BOOL CSerial::InitCommTimeouts()

{
    COMMTIMEOUTS CommTimeouts;//声明一个COMMTIMEOUTS结构
    DWORD dwError;
    //得到超时参数
    GetCommTimeouts (hPort, &CommTimeouts);
    //改变COMMTIMEOUTS结构设置
	//不使用这个逾时功能,ReadFile直到所有字符接收完才会返回
    CommTimeouts.ReadIntervalTimeout = 0;
    CommTimeouts.ReadTotalTimeoutMultiplier = 0;
    CommTimeouts.ReadTotalTimeoutConstant = 0;
	//不使用这个逾时功能,WriteFile直到所有字符接收完才会返回
    CommTimeouts.WriteTotalTimeoutMultiplier = 0;
    CommTimeouts.WriteTotalTimeoutConstant=0;
    //设置端口超时值  
    if (!SetCommTimeouts(hPort,&CommTimeouts))
	{     
		//不能设置超时值  
		MessageBox (NULL, TEXT("不能设置超时参数!"),TEXT("错误!"), MB_OK);
        dwError = GetLastError ();//获得错误原因的代码
        return FALSE;
	}
    return TRUE;
}

DWORD  WINAPI  ReadPortThread(LPVOID lpvoid)
{
    BOOL fReadState;//读入信息时返回值,若为TRUE就是正确读入
    DWORD dwCommModemStatus;//串口状态,以判断是否有事件发生
	DWORD dwLength;//读入信息的长度
	COMSTAT ComStat;//串口状态的详细情况表,
	//DWORD i;
	DWORD dwBytesread;
	DWORD dwErrorFlags;//读串口状态的标志
	BOOL readStatus=FALSE;//读入信息的状态,若为TRUE就是正在读入但还没有读完	
	//设置程序响应的事件
    SetCommMask (hPort, EV_RXCHAR);
	//程序在串口有效的状态下,无限循环
	SetCommMask (hPort, EV_RXCHAR);//重新设置程序响应的事件,但这个只是保证程序的安全性
    while (hPort != INVALID_HANDLE_VALUE) 
	{
        //等待串口的事件发生,当dwCommModemStatus值为1时表示接收到数据      	
        WaitCommEvent (hPort, &dwCommModemStatus, 0);	
        if (dwCommModemStatus & EV_RXCHAR) //检测收到的事件是否为"接收字符"的事件
		{ 			
 		    ClearCommError(hPort,&dwErrorFlags,&ComStat);//清除串口状态标志,并返回当前状态
			//cbInQue返回在串行驱动程序输入队列中的字符数
		    dwLength=ComStat.cbInQue;
            if(dwLength>0)//防止无故产生事件
			{
				TCHAR * tempbuf=new TCHAR[4096], *ptemp=tempbuf;
				TCHAR * fbuf=new TCHAR[2048],*pbuf=fbuf;//设置缓冲区,并多定义一个指针以方便移动
				do 
				{   
					fReadState=ReadFile (hPort, pbuf, 1, &dwBytesread,0);
					//printf("%s",pbuf); 			
					if (dwBytesread == 1)  
					{
						if(!fReadState)
						{
							//不能从串口读取数据
							MessageBox(NULL,TEXT("从串口获取数据失败!"),TEXT("读数据出错!"),MB_OK);
						}
						else
						{
    						::SendMessage(m_hWnd,WM_COMM_RCHAR,(WPARAM)(pbuf),0);
							ptemp[1] =pbuf[0]>>8;
							ptemp[0] =pbuf[0] & 0x00ff;
							//printf("%s",ptemp);
							ptemp=ptemp+1;
						}
					}
				}while (dwBytesread == 1); 
			//printf("OK1");
			//SendMessage(m_hWnd,WM_COMM_RCHAR,(WPARAM)(tempbuf),0);
			}			
		}			
        PurgeComm(hPort,PURGE_RXCLEAR);//清空串口的接收缓冲区,必要性不大,但有保证作用
		//重新获得串口状态,必要性不大,48表示没有事件产生
        GetCommModemStatus (hPort, &dwCommModemStatus);
	 }    	
     return 0;
}

⌨️ 快捷键说明

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