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

📄 serial.cpp

📁 wince 4.0平台测试过的,绝对可用的多串口驱动
💻 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)
{
	m_hWnd=hWnd;//将调用对话框的窗口句柄赋给m_hWnd,以备在ReadPortThread中使用
    DWORD dwError,
     dwThreadID;
    if(hPort)//如果hport为0说明串口没有打开
	{
		MessageBox (NULL, TEXT("You have opened the communication prot!"), 
    TEXT("Error!"), MB_OK);
       return FALSE;
	}
    //打开串口
    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("Can't open  %s, Error No.=%d"), 
             lpszPortName, GetLastError());
         MessageBox (NULL, strError,TEXT("Error!"), MB_OK);
        return FALSE;
	}
    //指定端口监测的事件集
    //SetCommMask (hPort, EV_RXCHAR|EV_TXEMPTY);
 
    //配置串行端口
    if(!InitDCB())

     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("Can't create thread!"), 
    TEXT("Error!"), 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);
     fWriteState=WriteFile(hPort,(BYTE *)buf,dwCharToWrite*sizeof(TCHAR),&dwBytesWritten,NULL);
     if(!fWriteState)
	 {
     //不能写数据
        MessageBox(NULL,TEXT("You can't write the data to the port!"),TEXT("Error!"),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)
	  {
		  //仅做提示性质,意义不大
          MessageBox(NULL,TEXT("ReadThread is making now!Are you sure?"),TEXT("Notice!"),MB_OK);
          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()

{
    DCB PortDCB;//声明一个DCB结构
     DWORD dwError;
    PortDCB.DCBlength = sizeof (DCB);//初始化 DCBlength

     //得到端口的默认设置信息
     GetCommState (hPort, &PortDCB);
//改变DCB结构设置

    PortDCB.BaudRate = 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("Unable to configure the serial port!"), 
             TEXT("Error!"), 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("Unable to set the time-out parameters!"),
         TEXT("Error!"), 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 dwErrorFlags;//读串口状态的标志
	  BOOL readStatus=FALSE;//读入信息的状态,若为TRUE就是正在读入但还没有读完
	 TCHAR * fbuf=new TCHAR[128],*pbuf=fbuf;//设置缓冲区,并多定义一个指针以方便移动
	 TCHAR * tempbuf=new TCHAR[256], *ptemp=tempbuf;
	  //设置程序响应的事件
      SetCommMask (hPort, EV_RXCHAR);
	  //程序在串口有效的状态下,无限循环
     while (hPort != INVALID_HANDLE_VALUE) 
	 {
         //等待串口的事件发生,当dwCommModemStatus值为1时表示接收到数据
      
        WaitCommEvent (hPort, &dwCommModemStatus, 0);
        SetCommMask (hPort, EV_RXCHAR);//重新设置程序响应的事件,但这个只是保证程序的安全性
		                               //一般并不起作用
        if (dwCommModemStatus & EV_RXCHAR) //检测收到的事件是否为"接收字符"的事件
		{ 
            ClearCommError(hPort,&dwErrorFlags,&ComStat);//清除串口状态标志,并返回当前状态
			//cbInQue返回在串行驱动程序输入队列中的字符数
            dwLength=ComStat.cbInQue;

            if(dwLength>0)//防止无故产生事件
			{

               //从串口读取数据
                
			     //读入数据,并返回数据长度,采用同步方式                
				fReadState=ReadFile(hPort,pbuf,dwLength,&dwLength,NULL);
				for(i = 0; i < dwLength; i++)
				{
					ptemp[2*i] = pbuf[i]>>8;
					ptemp[2*i+1] =pbuf[i]&0x00ff;
				}
                if(!fReadState)
				{

                //不能从串口读取数据

                    MessageBox(NULL,TEXT("Can't fetch the data!"),TEXT("Reading Error!"),MB_OK);

				}
                else
				{
					pbuf[dwLength]=NULL;//在其末尾设置字符串结尾
					::SendMessage(m_hWnd,WM_COMM_RCHAR,(WPARAM)(tempbuf),0);
    
				}
			} 

		}
 //       PurgeComm(hPort,PURGE_RXCLEAR);//清空串口的接收缓冲区,必要性不大,但有保证作用
		//重新获得串口状态,必要性不大,48表示没有事件产生
        GetCommModemStatus (hPort, &dwCommModemStatus);
	 }
     delete[] fbuf;//释放缓冲区
	 delete[] tempbuf;
     return 0;
}

⌨️ 快捷键说明

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