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

📄 scommdlg.cpp

📁 CSerialPort类做的串口通信编程
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//  the minimized window.
HCURSOR CSCOMMDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}


static long rxdatacount=0;  //该变量用于接收字符计数
//接收数据处理
//函数功能: 
LONG CSCOMMDlg::OnCommunication(WPARAM ch, LPARAM port)
{
	if (port <= 0 || port > 4)
	{
		return -1;
	}

	rxdatacount ++;   //接收的字节计数

	CString strTemp;
	strTemp.Format("%ld", rxdatacount);
	strTemp="接收:"+strTemp;
	m_ctrlRXCOUNT.SetWindowText(strTemp);  //显示接收计数
	
	//停止显示数据标志 0不停止1停止
	if (m_bStopDispRXData)   //如果选择了“停止显示”接收数据,则返回
	{
		return -1;          //注意,这种情况下,计数仍在继续,只是不显示
	}

	/////////////////////////////////////////////////////////////////////////////////////////////
	//////////////////////////// 在接收编辑框中显示接收到的数据 /////////////////////////////////
	////////////////////////////两种方案: 1.按"自动清空",     显示50 行后, 清屏继续显示//////////
	////////////////////////////          2.没有按"自动清空", 显示400行后, 清屏继续显示//////////
	////////////////////////////          3.按"十六进制显示", 显示BCD码                //////////
	////////////////////////////          4.没有按"十六进制显示", 显示ASCII码          //////////
	////////////////////////////注意: 接收到的字符, 一直显示在编辑框的最后             //////////
	/////////////////////////////////////////////////////////////////////////////////////////////
	//若设置了“自动清空”,则达到50行后,自动清空接收编辑框中显示的数据
	int ret;
	int line;
	ret = m_ctrlAutoClear.GetCheck();   //检测"自动清空" 单选复选框 选中状态 0未选中1选中
	if (ret == 1)
	{
		line = m_ctrlReceiveData.GetLineCount();
		if (line >= 50)
		{
			m_ReceiveData.Empty(); //将接收数据字符串 全部清空
			UpdateData(FALSE);    //将成员变量的值传给对应的控件, 并显示
		}
	}
	else  //如果没有“自动清空”,数据行达到400后,也自动清空
		  //因为数据过多,影响接收速度,显示是最费CPU时间的操作
	{
		line = m_ctrlReceiveData.GetLineCount();
		if (line >= 400)
		{
			m_ReceiveData.Empty();
			m_ReceiveData = "***The Length of the Text is too long, Emptied Automaticly!!!***\r\n";    //显示提示, 并将坐标移动到本行的开头
			//m_ReceiveData = "***The Length of the Text is too long, Emptied Automaticly!!!***\n";
			UpdateData(FALSE);
		}
	}

	//如果选择了"十六进制显示",则显示十六进制值
	CString str;
	ret = m_ctrlHexReceieve.GetCheck();
	if (ret == 1)
	{
		str.Empty();
		str.Format("%02X ",ch);
	}
	else   //如果没有选择"十六进制显示", 则显示ASCII值
	{
		str.Empty();
		str.Format("%c",ch);
	}

	//以下是将接收的字符加在字符串的最后,这里费时很多
	//但考虑到数据需要保存成文件,所以没有用List Control
	//将接收的字符接在字符串的末尾, 并在接收编辑框中显示出来, 是在编辑框的末尾坐标显示刚刚接收到的字符, 不是刷屏显示全部
	int nLen = m_ctrlReceiveData.GetWindowTextLength();    //获取编辑框控件中的字符总个数
	m_ctrlReceiveData.SetSel(nLen, nLen);  //移动到编辑框控件的末尾, 坐标设置
	m_ctrlReceiveData.ReplaceSel(str);     //添加文本

	m_ReceiveData += str;
	return 0;
}

//清空接收区
void CSCOMMDlg::OnButtonClearReciArea() 
{
	// TODO: Add your control notification handler code here
	m_ReceiveData.Empty();
	UpdateData(FALSE);
}

//打开/关闭串口
void CSCOMMDlg::OnButtonOpenport() 
{
	// TODO: Add your control notification handler code here
	m_bOpenPort = !m_bOpenPort;   //m_bOpenPort 串口状态 1关0开
	int ret1;

	if (m_bOpenPort == TRUE)  //此时串口是打开的, 欲将串口关闭
	{
		//检测"自动发送" 普通复选框的状态
		//如果选中了, 提示关闭, 后返回;
		//如果没有选中, 继续执行
		ret1 = m_ctrlAutoSend.GetCheck();  //检测 普通复选框 "自动发送"状态, 0未选中, 1选中
		if (ret1)
		{
			m_bOpenPort = !m_bOpenPort;     //如果自动发送选中, 则将m_bOpenPort设置为0, 即串口打开
			AfxMessageBox("请先关掉自动发送");
			return;
		}
		
		//设置按键按钮的显示内容
		m_ctrlOpenPort.SetWindowText("打开串口");
		//m_Port.StopMonitoring();
		m_Port.ClosePort();//关闭串口
		
		//状态栏(自己做的一个静态文本)
		CString str;
		str.Empty();
		str.Format("当前状态: COM%d已关闭", m_nCom);
		m_ctrlPortStatus.SetWindowText(str);
		
		m_ctrlIconOpenoff.SetIcon(m_hIconOff);
	}
	else  //此时串口是关闭的, 欲将串口打开
	{
		ret1 = m_ctrlAutoSend.GetCheck();  //检测 普通复选框 "自动发送"状态, 0未选中, 1选中
		if (ret1)
		{
			m_bOpenPort = TRUE;
			AfxMessageBox("请先关掉自动发送");
			return;
		}
		
		m_ctrlOpenPort.SetWindowText("关闭串口");
		CString strStatus;

		BOOL ret;
		ret = m_Port.InitPort(this, m_nCom, m_nBaud, m_cParity, m_nDatabits, m_nStopbits, m_dwCommEvents, 512);
		if (ret)
		{
			m_Port.StartMonitoring();
			m_ctrlIconOpenoff.SetIcon(m_hIconRed);
			
			strStatus.Empty();
			strStatus.Format("当前状态: COM%d已打开,%dbps,%c,%d,%d",m_nCom, m_nBaud,m_cParity,m_nDatabits,m_nStopbits);
			//"当前状态:串口打开,无奇偶校验,8数据位,1停止位");
			
			m_ctrlPortStatus.SetWindowText(strStatus);
		}
		else
		{
			m_ctrlIconOpenoff.SetIcon(m_hIconOff);
			strStatus.Empty();
			strStatus.Format("当前状态: COM%d被占用或没有发现此串口", m_nCom);

			AfxMessageBox(strStatus);
			
			//状态栏(自己做的一个静态文本)
			m_ctrlPortStatus.SetWindowText(strStatus);
		}
	}
}


//停止/继续显示接收数据
void CSCOMMDlg::OnButtonStopdisp()
{
	// TODO: Add your control notification handler code here
	m_bStopDispRXData = !m_bStopDispRXData;   //停止显示数据标志 0不停止1停止

	if (m_bStopDispRXData)
	{
		m_ctrlStopDisp.SetWindowText("继续显示");
	}
	else
	{
		m_ctrlStopDisp.SetWindowText("停止显示");
	}
}


//将一个字符串作为十六进制串转化为一个字节数组,字节间可用空格分隔,
//返回转换后的字节数组长度,同时字节数组长度自动设置。
int CSCOMMDlg::Str2Hex(CString str, char *data)
{
	/*int t,t1;
	int rlen=0,len=str.GetLength();
	//data.SetSize(len/2);
	for(int i=0;i<len;)
	{
		char l,h=str[i];
		if(h==' ')
		{
			i++;
			continue;
		}
		i++;
		if(i>=len)
			break;
		l=str[i];
		t=HexChar(h);
		t1=HexChar(l);
		if((t==16)||(t1==16))
			break;
		else 
			t=t*16+t1;
		i++;
		data[rlen]=(char)t;
		rlen++;
	}
	return rlen;*/
	int len, i, k=0;
	unsigned char buf[1024], tmpbuf[1024];
	len = str.GetLength();   //字符串总的长度

	memset(buf,    0, sizeof(buf   ));
	memset(tmpbuf, 0, sizeof(tmpbuf));
	for (i=0; i<len; i++)
	{
		//前一个字符 范围在['0', '9']或['a', 'f']或['A', 'F']
		//后一个字符 范围在['0', '9']或['a', 'f']或['A', 'F']
		if ((((str[i]>=0X30) && (str[i]<=0X39)) || ((str[i]>='A') && (str[i]<='Z')) || ((str[i]>='a') && (str[i]<='z'))) && (((str[i+1]>=0X30) && (str[i+1]<=0X39)) || ((str[i+1]>='A') && (str[i+1]<='Z')) || ((str[i+1]>='a') && (str[i]<='z'))))
		{
			buf[k] = str[i];
			buf[k+1] = str[i+1];
			k += 2;
			i ++;
		}
		else if ((((str[i]>=0X30) && (str[i]<=0X39)) || ((str[i]>='A') && (str[i]<='Z')) || ((str[i]>='a') && (str[i]<='z'))) && (str[i+1]==' '))
		{
			break;
		}
	}

	ASCToBCD(tmpbuf, buf, k);
	memcpy(data, tmpbuf, k/2);
	return k/2;
}


long TX_count=0;
//手动发送 处理函数
void CSCOMMDlg::OnButtonManualsend() 
{
	// TODO: Add your control notification handler code here
	if (m_Port.m_hComm == NULL)
	{
		m_ctrlAutoSend.SetCheck(0);
		CString str;
		str.Empty();
		str.Format("COM%d没有打开,请打开串口", m_nCom);
		AfxMessageBox(str);
		return;
	}
	else
	{
		//将控件的值传给对应的成员变量
		UpdateData(TRUE);
		
		int ret;
		//检测"16进制发送" 普通复选框按钮, 是否选中, 如果选中, 将发送编辑框中的数据按16进制数发送到选择串口
		ret = m_ctrlHexSend.GetCheck();
		if (ret == 1)
		{
			char data[512];
			int len = Str2Hex(m_strSendData, data);
			m_Port.WriteToPort(data, len);
			TX_count += len;//(long)((m_strSendData.GetLength()+1)/3);
			//m_Port.WriteToPort(hexdata);
		}
		else 
		{
			m_Port.WriteToPort((LPCTSTR)m_strSendData);	//发送数据
			TX_count += m_strSendData.GetLength();
		}

		CString strTemp;
		strTemp.Empty();
		strTemp.Format("发送:%d", TX_count);
		m_ctrlTXCount.SetWindowText(strTemp);
	}
}


//自动发送" 普通复选框 选中处理函数
void CSCOMMDlg::OnCheckAutosend()
{
	// TODO: Add your control notification handler code here
	m_bAutoSend = !m_bAutoSend;   //自动发送标志, 0不自动发送, 1自动发送

	if (m_bAutoSend == TRUE)
	{
		if (m_Port.m_hComm == NULL)
		{
			m_bAutoSend = !m_bAutoSend;
			m_ctrlAutoSend.SetCheck(0);
			CString str;
			str.Empty();
			str.Format("COM%d没有打开,请打开串口", m_nCom);
			AfxMessageBox(str);
			return;
		}
		else
		{
			SetTimer(1, m_nCycleTime, NULL);
		}
	}
	else
	{
		KillTimer(1);
	}
}

//定时器 超时的消息处理
void CSCOMMDlg::OnTimer(UINT nIDEvent)
{
	// TODO: Add your message handler code here and/or call default
	CString strStatus;

	switch (nIDEvent)
	{
		default:
			break;

		case 1:   //选中"自动发送" 普通普选框后, 到达定时器极限时, 发送数据到串口;之后在从新计数, 从新发送, 一直到取消"自动发送"为止.
			OnButtonManualsend();   //手动发送消息处理函数
			break;

		case 2:
			m_strCurPath = m_strBak;
			m_ctrlSavePath.SetWindowText(m_strCurPath);
			KillTimer(2);
			m_ctrlSaveData.EnableWindow(TRUE);
			break;

		case 3:
			m_ctrlManualSend.EnableWindow(TRUE);   //"手动发送" 允许
			m_ctrlAutoSend.EnableWindow(TRUE);     //"自动发送" 允许
			m_ctrlSendFile.EnableWindow(TRUE);     //"发送文件" 允许
			m_strSendFilePathName = m_strTempSendFilePathName;
			m_ctrlEditSendFile.SetWindowText(m_strSendFilePathName);//m_strSendFilePathName
			KillTimer(3);

			//恢复串口的原本设置, 串口缓冲区为512字节
			if(!(m_ctrlAutoSend.GetCheck()))
			{
				BOOL ret;
				ret = m_Port.InitPort(this, m_nCom, m_nBaud, m_cParity, m_nDatabits, m_nStopbits, m_dwCommEvents, 512);
				if (ret)
				{
					m_Port.StartMonitoring();
					//strStatus.Format("STATUS:COM%d OPENED,%d,%c,%d,%d",m_nCom, m_nBaud,m_cParity,m_nDatabits,m_nStopbits);					
					m_ctrlIconOpenoff.SetIcon(m_hIconRed);
					
					strStatus.Empty();
					strStatus.Format("当前状态: COM%d已打开,%dbps,%c,%d,%d", m_nCom, m_nBaud, m_cParity, m_nDatabits, m_nStopbits);
					m_ctrlPortStatus.SetWindowText(strStatus);
				}
				else
				{
					AfxMessageBox("Failed to reset send buffer size!");
					m_ctrlIconOpenoff.SetIcon(m_hIconOff);

					strStatus.Empty();
					strStatus.Format("当前状态: COM%d已关闭", m_nCom);
					m_ctrlPortStatus.SetWindowText(strStatus);
				}
			}
			break;

		case 4:
			m_animIcon.ShowNextImage();
			break;

		case 5:   //显示时间  静态文本 处理
			//str = CurrentTime.Format("%Y年%m月%d日 星期%w\n%X");
			int ret;
			CString str;
			CString str1[] = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
			CTime CurrentTime = CTime::GetCurrentTime();
			str = CurrentTime.Format("%Y年%m月%d日 ");
			ret = CurrentTime.GetDayOfWeek();
			str += str1[ret-1];
			str += CurrentTime.Format("\n%X");
			m_ctrltime.SetWindowText(str);
			break;
	}

	CDialog::OnTimer(nIDEvent);
}

//当自动发送周期编辑框的内容改变时, 调用此函数
void CSCOMMDlg::OnChangeEditCycletime()
{
	// TODO: If this is a RICHEDIT control, the control will not
	// send this notification unless you override the CDialog::OnInitDialog()
	// function and call CRichEditCtrl().SetEventMask()
	// with the ENM_CHANGE flag ORed into the mask.
	
	// TODO: Add your control notification handler code here
	/*CEdit *pEdit=(CEdit*)GetDlgItem(IDC_EDIT_CYCLETIME);
	CString strText;
	pEdit->GetWindowText(strText);
	m_nCycleTime = atoi(strText);*/

	UpdateData(1);
	m_nCycleTime = atoi((LPCTSTR)m_strCycleTime);

	/*CString strText;
	strText.Empty();
	strText.Format("m_nCycleTime=%dms", m_nCycleTime);
	MessageBox(strText);*/
}

//"发送编辑框"的内容改变时, 调用此函数
void CSCOMMDlg::OnChangeEditSend()
{
	// TODO: If this is a RICHEDIT control, the control will not
	// send this notification unless you override the CDialog::OnInitDialog()
	// function and call CRichEditCtrl().SetEventMask()
	// with the ENM_CHANGE flag ORed into the mask.
	// TODO: Add your control notification handler code here
	UpdateData(TRUE);
}

void CSCOMMDlg::OnButtonClearrecasenda() 
{
	// TODO: Add your control notification handler code here
	m_strSendData.Empty();
	UpdateData(FALSE);
}


void CSCOMMDlg::SetPortParameter()
{
	CString strStatus;
	BOOL ret;
	ret = m_Port.InitPort(this, m_nCom, m_nBaud, m_cParity, m_nDatabits, m_nStopbits, m_dwCommEvents, 512);
	if (ret)
	{
		/*strStatus.Empty();
		strStatus.Format("ret=%d, m_bOpenPort=%d", ret, m_bOpenPort);
		MessageBox(strStatus);*/

		//依靠 标志 m_bOpenPort 串口状态, 来设置状态栏该显示的提示
		if (m_bOpenPort == FALSE)   //m_bOpenPort 串口状态 1关0开
		{
			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);
			strStatus.Empty();
			strStatus.Format("当前状态: COM%d已打开,%dbps,%c,%d,%d", m_nCom, m_nBaud, m_cParity, m_nDatabits, m_nStopbits);
			m_ctrlPortStatus.SetWindowText(strStatus);
		}
		else
		{
			//m_Port.StopMonitoring();
			m_Port.ClosePort();

			m_ctrlIconOpenoff.SetIcon(m_hIconOff);
			
			strStatus.Empty();
			//strStatus.Format("STATUS:COM%d CLOSED,%d,%c,%d,%d",m_nCom, m_nBaud,m_cParity,m_nDatabits,m_nStopbits);
			strStatus.Format("当前状态: COM%d已关闭", m_nCom);
			m_ctrlPortStatus.SetWindowText(strStatus);
		}
	}
	else
	{
		m_ctrlIconOpenoff.SetIcon(m_hIconOff);
		strStatus.Empty();
		strStatus.Format("当前状态: COM%d被占用或没有发现此串口", m_nCom);

⌨️ 快捷键说明

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