S 串口编程 详解3 串口的初始化、打开/关闭

串口编程 详解3  串口的初始化

程序打开串口,采用两种方法:

1、程序启动,调用OnInitDialog( )函数,打开串口,缺省串口号为COM1,如果COM1不存在或被占用,就给出提示(其实,我觉得在OnInitDialog( )函数中打开串口不大好)

BOOL CSCOMMDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);//获得系统菜单
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}
	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon 程序显示时,左上角就会显示定义了的图标,生成的EXE程序也显示了这个图标
	SetIcon(m_hIcon, FALSE);		// Set small icon在程序运行的时候,当用Alt+TAB时,会显示定义的这个图标,要不不显示
	// TODO: Add extra initialization here
    
	//下面初始化串口的 串口号  波特率  奇偶校验  数据位   停止位
	m_bOpenPort=FALSE;
	m_nCom=1;
	m_nBaud=115200;
	m_cParity='N';
	m_nDatabits=8;
	m_nStopbits=1;
	m_dwCommEvents=EV_RXCHAR||EV_RXFLAG;//串口事件

	CString strStatus;
	if(m_Port.InitPort(this,m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits,m_dwCommEvents,512))//这句是串口的初始化 会在串口的打开和关闭中进行分析
	{
		m_Port.StartMonitoring();  //启动检测辅助线程
		m_ctrlIconOpenoff.SetIcon(m_hIconRed); //打开串口成功 设置ICON图标 为ON 
		strStatus.Format("STATUS: COM %d OPENED, %d, %c, %d, %d",m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits);
		//当前的状态                  端口号     奇偶 数据位  停止位
		m_ctrlOpenPort.SetWindowText("关闭串口");
			m_bOpenPort=TRUE;
	}
	else
	{
		AfxMessageBox("没有发现该串口或 已被占用");
		m_ctrlIconOpenoff.SetIcon(m_hIconOff);  //打开串口失败 设置ICON图标 为OFF
		m_bOpenPort=FALSE;
	}
		m_ctrlPortStatus.SetWindowText(strStatus);

		m_ctrlStopDisp.SetWindowText("停止显示");
		
		//端口的初始化
		m_ctrlPort.SetCurSel(0);
		m_ctrlPort.GetWindowText(m_strPort);
		//波特率的初始化
		m_ctrlBaud.InsertString(0,_T("4800"));
		m_ctrlBaud.InsertString(1,_T("14400"));
		m_ctrlBaud.InsertString(2,_T("19200"));
		m_ctrlBaud.InsertString(3,_T("38400"));
		m_ctrlBaud.InsertString(4,_T("56000"));
		m_ctrlBaud.InsertString(5,_T("57600"));
		m_ctrlBaud.InsertString(6,_T("115200"));
	//	m_ctrlBaud.InsertString(7,_T("128000"));
	//	m_ctrlBaud.InsertString(8,_T("256000"));
		m_ctrlBaud.SetCurSel(6);
		m_ctrlBaud.GetWindowText(m_strBaud);
		//校验初始化
		m_ctrlPartity.SetCurSel(0);
		m_ctrlPartity.GetWindowText(m_strPartity);
		//数据位初始化
		m_ctrlDatabits.SetCurSel(0);
		m_ctrlDatabits.GetWindowText(m_strDatabits);
		//停止位
		m_ctrlStopbits.SetCurSel(0);
		m_ctrlStopbits.GetWindowText(m_strStopbits);
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

代码分析:

串口的打开:(m_Port.InitPort(this,m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits,m_dwCommEvents,512)

以及m_Port.StartMonitoring();  //启动检测辅助线程

当然这里第一次用到ICON控件和COMBOX控件的知识

如: m_ctrlIconOpenoff.SetIcon(m_hIconRed);


m_ctrlBaud.InsertString(6,_T("115200"));
m_ctrlBaud.SetCurSel(6);
m_ctrlBaud.GetWindowText(m_strBaud); //获取当前控件框内的值到m_strBaud

2、打开/关闭串口(IDC_BUTTON_OPENPORT添加响应函数)

//打开/关闭串口
void CSCOMMDlg::OnButtonOpenport() 
{
	if(m_bOpenPort)//串口先是打开的,现在点击按钮进行关闭
	{
		if(m_ctrlAutoSend.GetCheck())
		{
			m_bOpenPort=!m_bOpenPort;
			AfxMessageBox("请先关掉自动发送");
			return;
		}
		m_ctrlOpenPort.SetWindowText("打开串口");
		m_Port.ClosePort();//关闭串口
		m_ctrlPortStatus.SetWindowText("STATUS: COM Port Close");
		m_ctrlIconOpenoff.SetIcon(m_hIconOff);
		m_bOpenPort=FALSE;
	}
	else//打开串口
	{
		m_ctrlOpenPort.SetWindowText("关闭串口");
		CString strStatus;
		//	BOOL  InitPort(CWnd* pPortOwner, UINT portnr = 1, UINT baud = 19200, \
		char parity = 'N', UINT databits = 8, UINT stopbits = 1, DWORD dwCommEvents = EV_RXCHAR, UINT writebuffersize = 1024);
		if(m_Port.InitPort(this,m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits,m_dwCommEvents,512))
		{
			m_Port.StartMonitoring();
			m_ctrlIconOpenoff.SetIcon(m_hIconRed);
			strStatus.Format("STATUS: COM %d OPENED, %d, %c, %d, %d",m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits);
			//当前的状态                 端口号     奇偶 数据位  停止位
				m_bOpenPort=TRUE;
		}
		else
		{
			AfxMessageBox("没有发现该串口或 已被占用");
			m_ctrlIconOpenoff.SetIcon(m_hIconOff);
				m_bOpenPort=FALSE;
		}
		m_ctrlPortStatus.SetWindowText(strStatus);
	}	
}

代码分析:现在我们得看InitPort( )里边都是些什么。

//SerialPort.cpp
// Initialize the port. This can be port 1 to 4.
BOOL CSerialPort::InitPort(CWnd* pPortOwner, // the owner (CWnd) of the port (receives message)
						   UINT  portnr,  // portnumber (1..4)
						   UINT  baud,   // baudrate
						   char  parity,  // parity 
						   UINT  databits,  // databits 
						   UINT  stopbits,  // stopbits 
						   DWORD dwCommEvents, // EV_RXCHAR, EV_CTS etc
						   UINT  writebuffersize) // size to the writebuffer
{
	// assert(portnr > 0 && portnr < 5);
	assert(portnr > 0 && portnr < 20);
	assert(pPortOwner != NULL);
	// if the thread is alive: Kill
	if (m_bThreadAlive)
	{
		do
		{
			SetEvent(m_hShutdownEvent);
		} while (m_bThreadAlive);
		TRACE("Thread ended/n");
	}
	// create events
	if (m_ov.hEvent != NULL)
		ResetEvent(m_ov.hEvent);
	m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	if (m_hWriteEvent != NULL)
		ResetEvent(m_hWriteEvent);
	m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	
	if (m_hShutdownEvent != NULL)
		ResetEvent(m_hShutdownEvent);
	m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	// initialize the event objects
	m_hEventArray[0] = m_hShutdownEvent; // highest priority
	m_hEventArray[1] = m_ov.hEvent;
	m_hEventArray[2] = m_hWriteEvent;
	// initialize critical section
	InitializeCriticalSection(&m_csCommunicationSync);
	
	// set buffersize for writing and save the owner
	m_pOwner = pPortOwner;
	if (m_szWriteBuffer != NULL)
		delete [] m_szWriteBuffer;
	m_szWriteBuffer = new char[writebuffersize];
	m_nPortNr = portnr;
	m_nWriteBufferSize = writebuffersize;
	m_dwCommEvents = dwCommEvents;
	BOOL bResult = FALSE;
	char *szPort = new char[50];
	char *szBaud = new char[50];
	// now it critical!
	EnterCriticalSection(&m_csCommunicationSync);
	// if the port is already opened: close it
	if (m_hComm != NULL)
	{
		CloseHandle(m_hComm);
		m_hComm = NULL;
	}
	// prepare port strings
	sprintf(szPort, "COM%d", portnr);
	sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);
	// get a handle to the port
	m_hComm = CreateFile(szPort,      // communication port string (COMX)
		GENERIC_READ | GENERIC_WRITE, // read/write types
		0,        // comm devices must be opened with exclusive access
		NULL,       // no security attributes
		OPEN_EXISTING,     // comm devices must use OPEN_EXISTING
		FILE_FLAG_OVERLAPPED,   // Async I/O
		0);       // template must be 0 for comm devices
	if (m_hComm == INVALID_HANDLE_VALUE)
	{
		// port not found
		delete [] szPort;
		delete [] szBaud;
		return FALSE;
	}
	// set the timeout values
	m_CommTimeouts.ReadIntervalTimeout = 1000;
	m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000;
	m_CommTimeouts.ReadTotalTimeoutConstant = 1000;
	m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000;
	m_CommTimeouts.WriteTotalTimeoutConstant = 1000;
	// configure
	if (SetCommTimeouts(m_hComm, &m_CommTimeouts))
	{         
		if (SetCommMask(m_hComm, dwCommEvents))
		{
			if (GetCommState(m_hComm, &m_dcb))
			{
				m_dcb.EvtChar = 'q';
				m_dcb.fRtsControl = RTS_CONTROL_ENABLE;  // set RTS bit high!
				if (BuildCommDCB(szBaud, &m_dcb))
				{
					if (SetCommState(m_hComm, &m_dcb))
						; // normal operation... continue
					else
						ProcessErrorMessage("SetCommState()");
				}
				else
					ProcessErrorMessage("BuildCommDCB()");
			}
			else
				ProcessErrorMessage("GetCommState()");
		}
		else
			ProcessErrorMessage("SetCommMask()");
	}
	else
		ProcessErrorMessage("SetCommTimeouts()");
	delete [] szPort;
	delete [] szBaud;
	// flush the port
	PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
	// release critical section
	LeaveCriticalSection(&m_csCommunicationSync);
	TRACE("Initialisation for communicationport %d completed./nUse Startmonitor to communicate./n", portnr);
	return TRUE;
}
启动检测辅助线程m_Port.StartMonitoring();  
//SerialPort.cpp
// start comm watching
BOOL CSerialPort::StartMonitoring()
{
 if (!(m_Thread = AfxBeginThread(CommThread, this)))
  return FALSE;
 TRACE("Thread started/n");
 return TRUE; 
}
用户界面线程和工作者线程都是由AfxBeginThread创建的。现在,考察该函数:MFC提供了两个重载版的AfxBeginThread.下面只说工作者线程 工作者线程的AfxBeginThread的原型如下:

CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,

LPVOID lParam,
  int nPriority = THREAD_PRIORITY_NORMAL,
  UINT nStackSize = 0,
  DWORD dwCreateFlags = 0,
  LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
  );//用于创建工作者线程
返回值: 一个指向新线程的线程对象的指针
pfnThreadProc : 线程的入口函数,声明一定要如下: UINT MyThreadFunction(LPVOID pParam),不能设置为NULL;
pParam : 传递入线程的参数,注意它的类型为:LPVOID,所以我们可以传递一个结构体入线程.
程序关闭后要关闭串口并释放所占用的资源。在CSCOMMDlg添加WM_DISTROY消息响应函数OnDestroy( ).该函数即将撤销时调用。
void CSCOMMDlg::OnDestroy() 
{
	CDialog::OnDestroy();
		m_ctrlAutoSend.SetCheck(0);//强行关闭自动发送
		KillTimer(1);
		KillTimer(4);
		m_Port.ClosePort();//关闭串口
		m_strReceiveData.Empty();//清空接收数据字符串
}
其实,要是自己来说设计程序的话,可能就不会考虑到这么全面的(建立后得撤销)
从上面可以看到一个串口打开、撤销代码都有啊






                




  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
CSerialPort First Version by Remon Spekreijse on 2000-02-08 http://www.codeguru.com/cpp/i-n/network/serialcommunications/article.php/c2483/A-communication-class-for-serial-port.htm Second Version by mrlong on 2007-12-25 https://code.google.com/p/mycom/ 增加 ClosePort 增加 WriteToPort 两个方法 增加 SendData 与 RecvData 方法 by liquanhai on 2011-11-04 http://blog.csdn.net/liquanhai/article/details/4955253 增加 ClosePort 中交出控制权,防止死锁问题 by liquanhai on 2011-11-06 http://blog.csdn.net/liquanhai/article/details/6941574 增加 ReceiveChar 中防止线程死锁 by viruscamp on 2013-12-04 https://github.com/viruscamp/CSerialPort 增加 IsOpen 判断是否打开 修正 InitPort 中 parity Odd Even 参数取值错误 修改 InitPort 中 portnr 取值范围,portnr>9 时特殊处理 取消对 MFC 的依赖,使用 HWND 替代 CWnd,使用 win32 thread 函数而不是 MFC 的 增加用户消息编号自定义,方法来自 CnComm by itas109 on 2014-01-10 http://blog.csdn.net/itas109/article/details/18358297 解决COM10以上端口无法显示的问题 扩展可选择端口,最大值MaxSerialPortNum可以自定义 添加QueryKey()和Hkey2ComboBox两个方法,用于自动查询当前有效的串口号。 by liquanhai on 2014-12-18 增加一些处理措施,主要是对减少CPU占用率 by itas109 on 2016-05-07 http://blog.csdn.net/itas109 修复每次打开串口发送一次,当串口无应答时,需要关闭打开或者接收完数据才能发送的问题。 解决办法:在m_hEventArray中调整m_hWriteEvent的优先级高于读的优先级。CommThread(LPVOID pParam)函数中读写的位置也调换。 参考:http://zhidao.baidu.com/link?url=RSrbPcfTZRULFFd2ziHZPBwnoXv1iCSu_Nmycb_yEw1mklT8gkoNZAkWpl3UDhk8L35DtRPo5VV5kEGpOx-Gea 修复停止位在头文件中定义成1导致SetCommState报错的问题,应为1对应的停止位是1.5。UINT stopsbits = ONESTOPBIT switch(stopbits)和switch(parity)增加默认情况,增强程序健壮性 by itas109 on 2016-06-22 http://blog.csdn.net/itas109 增加ReceiveStr方法,用于接收字符串(接收缓冲区有多少字符就接收多少字符)。 解决ReceiveChar只能接收单个字符的问题。 by itas109 on 2016-06-29 http://blog.csdn.net/itas109 解决RestartMonitoring方法和StopMonitoring方法命令不准确引起的歧义,根据实际作用。 将RestartMonitoring更改为ResumeMonitoring,将StopMonitoring更改为SuspendMonitoring。 增加IsThreadSuspend方法,用于判断线程是否挂起。 改进ClosePort方法,增加线程挂起判断,解决由于线程挂起导致串口关闭死锁的问题。 增加IsReceiveString宏定义,用于接收时采用单字节接收还是多字节接收 by itas109 on 2016-08-02 http://blog.csdn.net/itas109 https://github.com/itas109 改进IsOpen方法,m_hComm增加INVALID_HANDLE_VALUE的情况,因为CreateFile

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gdliweibing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值