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

📄 pc2pcview.cpp

📁 VisualC实践与提高——串口通信与工程应用篇代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// PC2PCView.cpp : implementation of the CPC2PCView class
//

#include "stdafx.h"
#include "PC2PC.h"

#include "PC2PCDoc.h"
#include "PC2PCView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


HANDLE hCom;                                //串口的句柄
HANDLE hThreadEvent;                      //事件线程句柄
DWORD ThreadProcEvent(LPVOID pParam);      //事件响应函数
bool fEventRun;                            //事件线程函数执行标志
HWND hWnd;                                  //窗口句柄
DWORD dwThreadID;                          //事件线程ID
OVERLAPPED Eol={0};                       //事件线程使用的OVERLAPPED结构Eol
OVERLAPPED Wol={0};                       //写操作使用的OVERLAPPED结构Wol
OVERLAPPED Rol={0};                       //读操作使用的OVERLAPPED结构Rol
DWORD	dwTimeoutValue;					//定义接收超时时间,ms为单位,在事件线程中使用


/////////////////////////////////////////////////////////////////////////////
// CPC2PCView

IMPLEMENT_DYNCREATE(CPC2PCView, CEditView)

BEGIN_MESSAGE_MAP(CPC2PCView, CEditView)
	//{{AFX_MSG_MAP(CPC2PCView)
	ON_COMMAND(ID_SETUPCOM, OnSetupcom)
	ON_COMMAND(ID_SENDFILE, OnSendfile)
	ON_COMMAND(ID_OPENCOM, OnOpencom)
	ON_COMMAND(ID_CLOSECOM, OnClosecom)
	ON_UPDATE_COMMAND_UI(ID_SENDFILE, OnUpdateSendfile)
	ON_UPDATE_COMMAND_UI(ID_SETUPCOM, OnUpdateSetupcom)
	ON_UPDATE_COMMAND_UI(ID_OPENCOM, OnUpdateOpencom)
	ON_UPDATE_COMMAND_UI(ID_CLOSECOM, OnUpdateClosecom)
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_UPDATE_COMMAND_UI(ID_APP_EXIT, OnUpdateAppExit)
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_MYMSG,OnReceiveEvent)

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPC2PCView construction/destruction

CPC2PCView::CPC2PCView()
{
	// TODO: add construction code here
	myCom="COM4";            //默认设置
	myBaudRate=CBR_4800;
	myfParity=false;
	myParity=NOPARITY;
}

CPC2PCView::~CPC2PCView()
{
}

BOOL CPC2PCView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	BOOL bPreCreated = CEditView::PreCreateWindow(cs);
	cs.style &= ~(ES_AUTOHSCROLL|WS_HSCROLL);	// Enable word-wrapping

	return bPreCreated;
}

/////////////////////////////////////////////////////////////////////////////
// CPC2PCView drawing

void CPC2PCView::OnDraw(CDC* pDC)
{
	CPC2PCDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
}

/////////////////////////////////////////////////////////////////////////////
// CPC2PCView diagnostics

#ifdef _DEBUG
void CPC2PCView::AssertValid() const
{
	CEditView::AssertValid();
}

void CPC2PCView::Dump(CDumpContext& dc) const
{
	CEditView::Dump(dc);
}

CPC2PCDoc* CPC2PCView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPC2PCDoc)));
	return (CPC2PCDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CPC2PCView message handlers

void CPC2PCView::OnSetupcom() 
{
	// TODO: Add your command handler code here
	CString strStatus;
	if(mySetupDlg.DoModal()==IDOK)
	{
		switch (mySetupDlg.m_Com)
		{
		case 0:
			{
			strStatus="COM1";
			strStatus+="  ";
			myCom="COM1";
			break;
			}
		case 1:
			{
			strStatus="COM2";
			strStatus+="  ";
			myCom="COM2";
			break;
			}

		case 2:
			{
			strStatus="COM3";
			strStatus+="  ";
			myCom="COM3";
			break;
			}

		case 3:
			{
			strStatus="COM4";
			strStatus+="  ";
			myCom="COM4";
			break;
			}

		case 4:
			{
			strStatus="COM5";
			strStatus+="  ";
			myCom="COM5";
			}
			break;
		case 5:
			{
			strStatus="COM6";
			strStatus+="  ";
			myCom="COM6";
			}
			break;
		}
		switch(mySetupDlg.m_BaudRate)
		{

		case 0:
			{
			strStatus+="19200";
			strStatus+="  ";
			myBaudRate=CBR_19200;
			break;
			}
		case 1:
			{
			strStatus+="9600";
			strStatus+="  ";
			myBaudRate=CBR_9600;
			break;
			}
		case 2:
			{
			strStatus+="4800";
			strStatus+="  ";
			myBaudRate=CBR_4800;
			break;
			}
		case 3:
			{
			strStatus+="2400";
			strStatus+="  ";
			myBaudRate=CBR_2400;
			break;
			}
		}
		switch(mySetupDlg.m_Parity)
		{
		case 0:
			{
			myfParity=false;
			myParity=NOPARITY;
			strStatus+="N";
			strStatus+="-8-1";
			break;
			}
		case 1:
			{
			myfParity=TRUE;
			myParity=ODDPARITY;
			strStatus+="O";
			strStatus+="-8-1";
			break;
			}
		case 2:
			{
			myfParity=true;
			myParity=EVENPARITY;
			strStatus+="E";
			strStatus+="-8-1";
			break;
			}
		}

		CMainFrame* m_pGetFrame=(CMainFrame*) AfxGetApp()->m_pMainWnd ;
		CStatusBar* m_pStatus=&m_pGetFrame->m_wndStatusBar;
		m_pStatus->SetPaneText(1,strStatus);     //将通信参数显示在状态条上
		blnSeted=true;
		
	}
}

void CPC2PCView::OnSendfile() 
{
	// TODO: Add your command handler code here
	
	CFileDialog myFileDlg(true);      //打开文件对话框
	CEdit& myEdit=this->GetEditCtrl();
	BYTE bytFileNameLen;              //文件名字符串的长度
	BYTE bytTemp;
	DWORD dwTemp1,dwTemp2;
	int i;
	CString myStr,myFileName,myPathName;
	CFileException e;                 //文件异常变量
	bytActStatus=1;                   //置为发送态
	if(myFileDlg.DoModal()==IDOK)     //调出文件选择对话框,选择传送的文件
	{
		myPathName=myFileDlg.GetPathName();
		myFileName=myFileDlg.GetFileName();
		if(myFileName.GetLength()>100)
		{
			AfxMessageBox("文件名长度应小于100!");	
			bytActStatus=10;          //恢复为接收态
			return;
		}
		else
		{
			bytFileNameLen=(BYTE)myFileName.GetLength();
		}
	}
	else
	{
		bytActStatus=10;              //恢复为接收态

		return;
	}
	myPathName.Replace("\\","\\\\");  //将文件名中的单“\”替换成双“\\”

	//打开选定的文件
	if(!myFile.Open(myPathName,CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite,&e))
	{
		myStr.Format("%02X",e.m_cause);//文件打开错误处理,错误代码为m_cause
		myStr+="error";
		AfxMessageBox(myStr);
		bytActStatus=10;               //恢复为接收态
		return;
	}
	dwFileLen=myFile.GetLength();
	if(dwFileLen>=67108864)
	{
		AfxMessageBox("文件必须小于64MB!");//检查文件尺寸<64MB
		bytActStatus=10;                //恢复为接收态
		return;
	}
	arrSendData[0]=05;                  //ENQ
	arrSendData[4]=(BYTE)(dwFileLen/16777216);
	dwTemp1=dwFileLen%16777216;
	arrSendData[3]=(BYTE)(dwTemp1/65536);
	dwTemp2=dwTemp1%65536;
	arrSendData[2]=(BYTE)(dwTemp2/256);
	arrSendData[1]=(BYTE)(dwTemp2%256);
	arrSendData[5]=bytFileNameLen;
	
	for(i=6;i<=bytFileNameLen+5;i++)    //保存文件名称
	{
		arrSendData[i]=myFileName.GetAt(i-6);
	}
	
	bytTemp=0;

	for(i=0;i<=bytFileNameLen+5;i++)
	{
		bytTemp^=arrSendData[i];
	}
	arrSendData[bytFileNameLen+6]=bytTemp;//计算出校验位

	bytSendStatus=1;
	bytResendCount=0;

	Write(arrSendData,bytFileNameLen+7);
	myEdit.SetSel(1000000,1000000);
	myEdit.ReplaceSel("发出传输请求。\15\12");

	blnNoTimeout=false;

}

void CPC2PCView::OnOpencom() 
{
	// TODO: Add your command handler code here
	//打开串口操作
	hCom=CreateFile(myCom,              //打开串口COM2
		GENERIC_READ | GENERIC_WRITE, //使用读写方式
		0,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //使用重叠方式
		NULL);
	if( hCom !=INVALID_HANDLE_VALUE) 
	{
		SetupComm(hCom,1500,1500);      //设置发送缓冲1500,接收缓冲区1500
		DCB myDCB;
		GetCommState( hCom, &myDCB ); //获取当前串口参数
		myDCB.BaudRate=myBaudRate;
		myDCB.fBinary=TRUE;
		myDCB.fParity=myfParity;
		myDCB.ByteSize=8;
		myDCB.Parity=myParity;
		myDCB.StopBits=ONESTOPBIT;
		SetCommState(hCom,&myDCB);     //设置串口通信参数
		blnOpened=true;

		//创建并立即执行线程函数
		DWORD dwParam;
		if (!SetCommMask(hCom,EV_RXCHAR))// | EV_TXEMPTY))//设置允许的事件类型
		{
			AfxMessageBox("建立事件掩码失败!");
		}
		hThreadEvent=CreateThread(NULL,                 //创建事件线程
			0,
			(LPTHREAD_START_ROUTINE )ThreadProcEvent,   //指定线程函数名称
			&dwParam,
			0,                                               //创建线程函数后,立即执行
			&dwThreadID);
		if (hThreadEvent==INVALID_HANDLE_VALUE)
		{
			AfxMessageBox("事件线程创建失败!");
		}
		fEventRun=true;                                    //允许事件函数执行循环体
		bytActStatus=10;
		bytSendStatus=0;
		bytRcvStatus=0;
		bytResendCount=0;
		uintStxCurNo=0;
	}
	else
	{
		AfxMessageBox("创建串口失败!");
	}
	
}

void CPC2PCView::OnClosecom() 
{
	// TODO: Add your command handler code here
	fEventRun=false;                     //停止事件线程循环体的操作
	WaitForSingleObject(hThreadEvent,    //等待事件线程函数退出
		INFINITE);                        //无限时地等待,直到事件线程函数退出
	CloseHandle(hThreadEvent);        //关闭事件线程句柄
	CloseHandle(hCom);                  //关闭串口句柄
	blnOpened=false;
}

//事件线程函数
DWORD ThreadProcEvent(LPVOID pParam)
{
	DWORD dwErrors;
	COMSTAT Rcs;
	DWORD dwEvtMask,dwRes;
	Eol.hEvent=CreateEvent(NULL, //设置Eol.hEvent成员为无信号状态
		TRUE, 
		FALSE, 
		NULL);
	while(fEventRun)
	{
		WaitCommEvent(hCom,                            //监视串口事件
			&dwEvtMask,                                 //存放事件掩码组合值
			&Eol);                                       //OVERLAPPED结构
		dwRes=WaitForSingleObject(Eol.hEvent,        //等待的事件对象句柄
			dwTimeoutValue);                       //超时时间(ms)
		
		switch (dwRes)
		{
			case  WAIT_OBJECT_0:                      //成功得到事件监视结果
				{
					switch (dwEvtMask)
					{
					case EV_RXCHAR:                      //接收到数据
						{
							//向主线程发送消息,接收到数据
							ClearCommError(hCom,                //串口句柄
								&dwErrors,                        //存放出错信息的掩码组合
								&Rcs);                             //COMSTAT类型结构变量
							if(Rcs.cbInQue!=0)
							{
							::PostMessage(hWnd,         //目的窗口句柄
								WM_MYMSG,              //消息名称
								0,                      //传递的参数1
								(LPARAM)EV_RXCHAR );    //传递的参数2
							}
							break;
						}
					case EV_TXEMPTY:                    //发送缓冲区已空
						{
							   //这里可加入发送缓冲区空的处理代码,或向主线程发送消息
							break;
						}
					}
					break;
				}

			case WAIT_TIMEOUT:
				{
					//传递超时消息给主线程
					::PostMessage(hWnd,         //目的窗口句柄
						WM_MYMSG,              //消息名称
						0,                      //传递的参数1
						(LPARAM)100 );         //传递的参数100
					break;
				}
		}
	}
	return true;
}

//消息响应函数
LONG CPC2PCView::OnReceiveEvent(WPARAM wParam,LPARAM lParam)
{
	CFileDialog myFileDlg(false);         //保存文件对话框
	BYTE myByte[1100];
	BYTE bytTemp;
	CString strDis,strDis1;
	char *myChar;                       //获取文件名时使用
	char myName[300];
	char myExt[5];
	int i;
	CEdit& myEdit=this->GetEditCtrl();
	CMainFrame* m_pGetFrame=(CMainFrame*) AfxGetApp()->m_pMainWnd ;
	CStatusBar* m_pStatus=&m_pGetFrame->m_wndStatusBar;
	CFileException e;

	switch(bytActStatus)
	{
	case 1://发送操作
		{
			switch(bytSendStatus)//发送的不同状态
			{
			case 1://发送操作的1态
				{
					switch(lParam)
					{
					case EV_RXCHAR://lParam=EV_RXCHAR即1,说明读线程收到数据
						{
							blnNoTimeout=true;
							bytTimeoutCounter=0;
							switch(Detect(1))
							{
							case 0://收到指定数量的字符
								{
									break;
								}
							case 4://超时错误
								{
									DisSend(4);
									blnNoTimeout=false;
									return -1;
									break;
								}

							case 8://无效,输入缓冲区中字符数量为0
								{
									blnNoTimeout=false;
									return 0;
									break;
								}

							}
							switch(Read(myByte,1))
							{
							case 0:
								{
									//继续后面的操作
									break;
								}
							case 4://超时错误
								{
									DisSend(4);
									return -1;
									break;
								}
							case 16://读操作失败
								{
									DisSend(16);
									return -1;
									break;
								}
							}
							switch(myByte[0])
							{
							case 6://响应是ACK
								{
									//发送当前序号的数据
									uintStxCurNo=1;

									myEdit.SetSel(1000000,1000000);
									myEdit.ReplaceSel("正在传送数据……\15\12");

⌨️ 快捷键说明

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