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

来源:互联网 发布:西安编程培训班 编辑:程序博客网 时间:2024/06/08 11:39

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 userBROWSEINFO 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 hereLPCTSTR 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.txtCString strFileExt =FileDlg.GetFileExt();//得到完整的文件扩展名,如:txtCString lpstrName =FileDlg.GetPathName();//得到完整的文件名,包括目录名和扩展名如:c:\ test\ test1.txtm_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 hereCFile 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_MSGDECLARE_MESSAGE_MAP()
添加消息映射:

//消息映射BEGIN_MESSAGE_MAP(CSCOMMDlg, CDialog)//{{AFX_MSG_MAP(CSCOMMDlg)ON_MESSAGE(WM_COMM_RXCHAR,OnCommunication)//}}AFX_MSG_MAPEND_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 defaultswitch (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);}
至此,一个小小的简单的串口调试助手,完毕
下一篇给整个串口的代码。




原创粉丝点击