S 串口编程 详解5 串口数据的接收

S  串口编程 详解5 串口数据的接收

接收数据的文件保存

       串口有时要把接收到的数据保存在文件。保存文件的缺省路径是C:\COMDATA.文件名为Rec**.txt.

”保存显示数据“按钮IDC_BUTTON_SAVEDATA添加响应函数OnButtonSavedata().代码如下:

//接收到的数据在文件中进行保存
void CSCOMMDlg::OnButtonSavedata() 
{
	UpdateData(TRUE);//由屏幕到 内存的
	int nLength;
        nLength=m_StrCurPath.GetLength(); 
	for(int nCount=0;nCount<nLength;nCount++)
	{
		if(m_StrCurPath.GetAt(nCount)=='\\')
		{		
			CreateDirectory(m_StrCurPath.Left(nCount+1),NULL);//创建一级目录或二级目录 三…… 
		}
	}
	CreateDirectory(m_StrCurPath,NULL);//创建目录
	CFile m_rFile;
	//LPCSTR是Win32和VC++所使用的一种字符串数据类型。LPCSTR被定义成是一个指向以NULL(‘\0’)结尾的常量字符的指针。
	LPCSTR lpszPath=m_StrCurPath;// "C:\\comdata"
	SetCurrentDirectory(lpszPath);
	
	//文件为Rec**.txt,一下的代码自动检测文件名是否存在,若存在,则后面序号自动增加
	char buf[200];
	for(int j=0;j<100;j++)//产生一个文件名
	{
		sprintf(buf,"Rec%02d.txt",j);
		if((access(buf,0))==-1)
			break;
	}
        //下面是创建模式 写的模式打开文件(当然,文件不存在的话就先创建)
	if(!m_rFile.Open(buf,CFile::modeCreate|CFile::modeWrite))//我的天呀:这里写成这样的CFile::modeCreate||File::modeWrite
	{
	AfxMessageBox("创建文件记录文件失败");
		return ;
	}

	if((access(buf,0))==-1)
	{
		AfxMessageBox("failed");
		return ;
	}

	//在文件开始处写上保存日期
	CTime t=CTime::GetCurrentTime();
	CString str=t.Format("%Y年 %m月 %d日 %H时 %M 分 %S秒\r\n");
	m_rFile.Write((LPCTSTR)str,str.GetLength());

	//保存显示数据
	m_rFile.Write((LPCTSTR)m_strReceiveData,m_strReceiveData.GetLength()); //向文件写数据
	m_rFile.Flush();//将缓存的内容写入文件  缓冲区是4k的内容,够4k了,就会自动写入文件,不够的话就需要flush一下,如果不flush的话,//文件的最后有可能会少一些内容
	m_rFile.Close();//关闭文件
	str="OK";
	for(int i=0;i<5;i++)
		str+=buf[i];
	str+=".txt saved";
	m_ctrlSavePath.SetWindowText(str);	
	SetTimer(2,5000,NULL);//在定时器中显示保存文件状态	
}
更改路径:为“更改”按钮IDC_BUTTON_DIRBROWSER添加单击响应函数OnButtonDirbrowser( )

void CSCOMMDlg::OnButtonDirbrowser() 
{	
	static char displayname[MAX_PATH];
	static char path[MAX_PATH];
	LPITEMIDLIST pidlBrowse; //PIDL selected by user

	BROWSEINFO bi;//BROWSEINFO结构中包含有用户选中目录的重要信息
	bi.hwndOwner=this->m_hWnd;//获得窗口自己的句柄  浏览文件夹对话框的父窗体句柄。
	bi.pidlRoot=NULL;  //ITEMIDLIST结构的地址,包含浏览时的初始根目录,而且只有被指定的目录和其子目录才显示在浏览文件夹对话框中///。该成员变量可以是NULL,在此时桌面目录将被使用。
	bi.pszDisplayName= displayname;//用来保存用户选中的目录字符串的内存地址。该缓冲区的大小缺省是定义的MAX_PATH常量宏。
	bi.lpszTitle ="请选择保存接收数据的文件夹";  //该浏览文件夹对话框对话框的显示文本,用来提示该浏览文件夹对话框的功能、作用和目的。
	bi.ulFlags=BIF_EDITBOX;//BIF_EDITBOX:浏览对话框中包含一个编辑框,在该编辑框中用户可以输入选中项的名字。
	bi.lpfn=NULL;//lpfn:应用程序定义的浏览对话框回调函数的地址。当对话框中的事件发生时,该对话框将调用回调函数。该参数可用为NULL。
	pidlBrowse=SHBrowseForFolder(&bi);
	if(pidlBrowse!=NULL)
	{
		SHGetPathFromIDList(pidlBrowse,path);//功能是把项目标志符列表转换为文档系统路径
	}
	CString str=path;//得到路径
	if(str.IsEmpty())   //没选择则返回
		return ;        
	m_StrCurPath=str; //接收路径编辑框对应的变量
	UpdateData(FALSE);
}
代码分析:上面代码主要涉及到路径的选择和变更
BROWSEINFO bi;//BROWSEINFO结构中包含有用户选中目录的重要信息
该结构如下:
typedef struct_browseinfo
{
HWND hwndOwner;
LPCITEMIDLIST pidlRoot;
LPSTR pszDisplayName;
LPCSTR lpszTitle;
UINT ulFlags;
BFFCALLBACK lpfn;
LPARAM lParam;
int iImage;
}BROWSEINFO,*PBROWSEINFO,*LPBROWSEINFO;
这一句 pidlBrowse=SHBrowseForFolder(&bi);就是显示下面这个目录选择对话框。通时,对用户返回用户选择的内容。


而上面的pidlBrowse是这样定义的LPITEMIDLIST pidlBrowse; //PIDL selected by user。

当单击确定时,会执行SHGetPathFromIDList(pidlBrowse,path);这句把pidlBrowse对应的目录复制到字符串path中保存,即功能是把项目标志符列表转换为文档系统路径:。单击确定,则跳过该语句。


实现小文件的发送

为“选择发送文件”IDC_BUTTON_FILEBROWSER添加单击响应函数OnButtonFilebrowser( ).代码如下:

//下面代码是实现文件的小发送
//选择要发送的文件
void CSCOMMDlg::OnButtonFilebrowser() 
{
	// TODO: Add your control notification handler code here
	LPCTSTR lpszPath="c:\\comdata";
	SetCurrentDirectory(lpszPath);

	static char BASED_CODE szFilter[]="文本文件(*.txt)|*.txt|所有文件(*.*)|*.*||";
	
	CFileDialog FileDlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,szFilter)

  
  
//OFN_READONLY Causes the Read Only check box to be selected initially when the dialog box is created. This flag indicates the state of the// Read Only check box when the dialog box is closed.
//OFN_OVERWRITEPROMPT Causes the Save As dialog box to generate a message box if the selected file already exists. The user must c//onfirm whether to overwrite the file.
FileDlg.m_ofn.lpstrInitialDir=lpszPath; if(FileDlg.DoModal()==IDOK) { CString strFileName =FileDlg.GetFileName();//得到完整的文件名,包括扩展名如:test1.txt CString strFileExt =FileDlg.GetFileExt();//得到完整的文件扩展名,如:txt CString lpstrName =FileDlg.GetPathName();//得到完整的文件名,包括目录名和扩展名如:c:\ test\ test1.txt m_strSendFilePathName=lpstrName; UpdateData(FALSE); } }
代码分析:

CFileDialog FileDlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,szFilter)
产生下面这样的一个对话框

选好文件后,就可以发送啦。“发送文件”按钮 IDC_BUTTON_SENDFILE添加单击响应函数OnButtonSendfile( )

//发送文件
void CSCOMMDlg::OnButtonSendfile() 
{
	// TODO: Add your control notification handler code here
	CFile fp;
	if(!(fp.Open((LPCSTR)m_strSendFilePathName,CFile::modeRead)))//文件以只读的方式打开
	{
		AfxMessageBox("Open file failed!");
		return ;
	}
	fp.SeekToEnd(); //这里应该是设置光标到 文本的末尾,一遍统计字符文本字符数
	unsigned long fplength=fp.GetLength();
	m_nFileLength=fplength;
	char* fpBuff;
	fpBuff =new char[fplength];
	fp.SeekToBegin();
	if(fp.Read(fpBuff,fplength)<1)//读文件的数据到fpBuff中
	{
		fp.Close();//读文件失败 关闭文件
		return ;
	}
	fp.Close();
	CString strStatus;
	if(m_Port.InitPort(this,m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits,m_dwCommEvents,fplength))
	{
		
		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);
		m_bSendFile=TRUE;
		//	m_strTempSendFilePathName=m_strSendFilePathName;
		m_ctrlEditSendFile.SetWindowText("正在发送......");
		
		//发送文件时,一下功能不能使用
		m_ctrlManualSend.EnableWindow(FALSE);
		m_ctrlAutoSend.EnableWindow(FALSE);
		m_ctrlSendFile.EnableWindow(FALSE);
		m_Port.WriteToPort((LPCSTR)fpBuff,fplength);
	}
	else
	{
		AfxMessageBox("Failed to send file!");
		m_ctrlIconOpenoff.SetIcon(m_hIconOff);
	}
	delete fpBuff;//释放内存,一定得记得
}
怎样才知道文件的内容发送完了呢???还用串口类CSerialPort中有WM_COMM_TXEMPTY_DETECTED消息来告诉我们

添加串口字符发送完毕消息WM_COMM_TXEMPTY_DETECTED,并添加响应函数

函数的声明:

	//{{AFX_MSG(CSCOMMDlg)	
        afx_msg LONG OnFileSendingEnded(WPARAM wParam,LPARAM port);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
添加消息映射:

//消息映射
BEGIN_MESSAGE_MAP(CSCOMMDlg, CDialog)
	//{{AFX_MSG_MAP(CSCOMMDlg)
	ON_MESSAGE(WM_COMM_RXCHAR,OnCommunication)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

添加消息响应函数:

LONG CSCOMMDlg::OnFileSendingEnded(WPARAM wParam,LPARAM port)
{
	if(m_bSendFile)
	{
		m_ctrlEditSendFile.SetWindowText("发送完毕!");//
		TX_count+=m_nFileLength;
		SetTimer(3,3000,NULL);
		CString strTemp;
		strTemp.Format("TX: %d ",TX_count);
		m_ctrlTXCount.SetWindowText(strTemp);
	}
	return 0;
}
看到上面的函数中发送数据结束后启动  SetTimer(3,3000,NULL);以恢复状态。看来还要在定时函数中添加代码:

void CSCOMMDlg::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	switch (nIDEvent)
	{
	case 1: //定时器ID==1为自动发送时间
		OnButtonManualsend();   //周期到后自动发送
		break;
	case 2:
		m_ctrlSavePath.SetWindowText(m_StrCurPath);//重新显示路径
		KillTimer(2);//关闭定时器
		break;
	case 3:
		m_ctrlManualSend.EnableWindow(TRUE);
		m_ctrlAutoSend.EnableWindow(TRUE);
		m_ctrlSendFile.EnableWindow(TRUE);
		m_strSendFilePathName=m_strTempSendFilePathName;		
		KillTimer(3);
		if(!(m_ctrlAutoSend.GetCheck()))
		{
			CString strStatus;
			if(m_Port.InitPort(this,m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits,m_dwCommEvents,512))
			{
				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 );

			}
			else
			{
				AfxMessageBox("Failed to reset send buffer size!");
				m_ctrlIconOpenoff.SetIcon(m_hIconOff);
			}
			m_ctrlPortStatus.SetWindowText(strStatus);
		}
		break;
	default:
		break;
	}
	CDialog::OnTimer(nIDEvent);
}
至此,一个小小的简单的串口调试助手,完毕
下一篇给整个串口的代码。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

gdliweibing

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

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

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

打赏作者

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

抵扣说明:

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

余额充值