为什么 串口通信 分多次接收数据解决思路
为什么 串口通信 分多次接收数据
参考的代码如下所示,我是直接把串口2、3脚短接后测试的。请教下为啥数据都是分几个来接收的呢?这样我不好处理数据呢。
参考的代码如下所示,我是直接把串口2、3脚短接后测试的。请教下为啥数据都是分几个来接收的呢?这样我不好处理数据呢。
- C/C++ code
// comDlg.cpp : implementation file // #include "stdafx.h" #include "com.h" #include "comDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif UINT CommProc(LPVOID pParam); //全局线程 ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CComDlg dialog CComDlg::CComDlg(CWnd* pParent /*=NULL*/) : CDialog(CComDlg::IDD, pParent) { //{{AFX_DATA_INIT(CComDlg) m_send = _T(""); //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CComDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CComDlg) DDX_Control(pDX, IDC_EDIT2, m_receive); DDX_Control(pDX, IDC_COMBO2, m_bord); DDX_Control(pDX, IDC_COMBO1, m_port); DDX_Text(pDX, IDC_EDIT1, m_send); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CComDlg, CDialog) //{{AFX_MSG_MAP(CComDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON3, OnConnect) ON_BN_CLICKED(IDC_BUTTON1, OnSend) //}}AFX_MSG_MAP ON_MESSAGE(WM_COMMNOTIFY, OnCommNotify) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CComDlg message handlers BOOL CComDlg::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 SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here m_port.AddString("COM1"); m_port.AddString("COM2"); m_port.AddString("COM3"); m_port.AddString("COM4"); m_port.SetCurSel(0); m_bord.AddString("9600"); m_bord.AddString("19200"); m_bord.AddString("38400"); m_bord.SetCurSel(0); //事件 memset(&m_osRead, 0, sizeof(OVERLAPPED)); memset(&m_osWrite, 0, sizeof(OVERLAPPED)); if((m_hPostMsgEvent=CreateEvent(NULL, TRUE, TRUE, NULL))==NULL) MessageBox("为WM_COMMNOTIFY消息创建事件对象失败"); // 为重叠读创建事件对象,手工重置,初始化为无信号的 if((m_osRead.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL))==NULL) MessageBox("为重叠读创建事件对象失败"); // if((m_osWrite.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL))==NULL) MessageBox("为重叠写创建事件对象失败"); return TRUE; // return TRUE unless you set the focus to a control } void CComDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CComDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CComDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } ///////////////////////////////////////////////////////// // 用户代码部分 // //////////////////////////////////////////////////////// //串口号列表 const CString ComName[4]={"COM1","COM2","COM3","COM4"}; //确认连接 void CComDlg::OnConnect() { CString sPort; COMMTIMEOUTS TimeOuts; //串口设置超时结构体 sPort=ComName[m_port.GetCurSel()]; //获得所选串口号 //打开一个串口设备 h_com=CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); // 重叠方式 if(h_com==INVALID_HANDLE_VALUE) { MessageBox("不能打开这个串口"); return; } SetupComm(h_com,4096,4096); //1.设置输入输出缓冲 SetCommMask(h_com, EV_RXCHAR); //2.设置事件 //3.超时设置 // 把间隔超时设为最大,把总超时设为0将导致ReadFile立即返回并完成操作 TimeOuts.ReadIntervalTimeout=MAXDWORD; TimeOuts.ReadTotalTimeoutMultiplier=0; TimeOuts.ReadTotalTimeoutConstant=0; /* 设置写超时以指定WriteComm成员函数中的GetOverlappedResult函数的等待时间*/ TimeOuts.WriteTotalTimeoutMultiplier=50; TimeOuts.WriteTotalTimeoutConstant=2000; SetCommTimeouts(h_com, &TimeOuts); //4.配置串口 if(!ConfigConnect()) { MessageBox("配置串口的时候失败"); return; } // m_bConnected=TRUE; //连接标志 //5.打开接收数据线程 //AfxBeginThread(CommProc,this); m_pThread=AfxBeginThread(CommProc, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL); // 创建并挂起线程 if(m_pThread==NULL) { CloseHandle(h_com); } else { m_bConnected=TRUE; m_pThread->ResumeThread(); // 恢复线程运行 } } //发送函数 void CComDlg::OnSend() { // TODO: Add your control notification handler code here COMSTAT ComStat; ULONG nLength=0; UpdateData(true); ULONG szLength = m_send.GetLength(); char *sz = new char[szLength]; if(sz==NULL) return; memcpy(sz,m_send.GetBuffer(szLength),szLength); DWORD dwErrorFlags; ClearCommError(h_com,&dwErrorFlags,&ComStat); BOOL fState=WriteFile(h_com,sz,szLength,&nLength,&m_osWrite); if(!fState) { ULONG my_error=GetLastError(); if(my_error==ERROR_IO_PENDING) { GetOverlappedResult(h_com,&m_osWrite,&nLength,TRUE); } else nLength=0; } delete[] sz; sz=NULL; } const ULONG TheBord[3]={9600,19200,38400}; //配置串口 BOOL CComDlg::ConfigConnect() { DCB dcb; if(!GetCommState(h_com, &dcb)) return FALSE; dcb.fBinary=TRUE; dcb.BaudRate = TheBord[m_bord.GetCurSel()]; // 数据传输速率 dcb.ByteSize = 8; // 每字节位数 dcb.fParity = TRUE; //校验 dcb.Parity=NOPARITY; //为无校验 dcb.StopBits=ONESTOPBIT; //1停止位 // 硬件流控制设置 dcb.fOutxCtsFlow = FALSE; dcb.fRtsControl = TRUE; // XON/XOFF流控制设置 dcb.fInX=dcb.fOutX = TRUE; dcb.XonChar = 0x11; dcb.XoffChar = 0x13; dcb.XonLim = 50; dcb.XoffLim = 50; return SetCommState(h_com, &dcb); } //工作者线程 //用于判断串口是否接收到数据,如果有数据,就发信息给WM_COMMNOTIFY // 工作者线程,负责监视串行口 // UINT CommProc(LPVOID pParam) { OVERLAPPED os; DWORD dwMask, dwTrans; COMSTAT ComStat; DWORD dwErrorFlags; CComDlg *pX1=(CComDlg*)pParam; memset(&os, 0, sizeof(OVERLAPPED)); os.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL); if(os.hEvent==NULL) { AfxMessageBox("Can't create event object!"); return (UINT)-1; } while(pX1->m_bConnected) { ClearCommError(pX1->h_com,&dwErrorFlags,&ComStat); if(ComStat.cbInQue) { // 无限等待WM_COMMNOTIFY消息被处理完 WaitForSingleObject(pX1->m_hPostMsgEvent, INFINITE); //重置事件 ResetEvent(pX1->m_hPostMsgEvent); // 通知!!! PostMessage(pX1->GetSafeHwnd(),WM_COMMNOTIFY, EV_RXCHAR, 0); //pX1->m_hTermWnd continue; } dwMask=0; if(!WaitCommEvent(pX1->h_com, &dwMask, &os)) // 重叠操作 { if(GetLastError()==ERROR_IO_PENDING) // 无限等待重叠操作结果 GetOverlappedResult(pX1->h_com, &os, &dwTrans, TRUE); else { CloseHandle(os.hEvent); return (UINT)-1; } } } CloseHandle(os.hEvent); return 0; } //串口消息函数(自己建立的消息) LRESULT CComDlg::OnCommNotify(WPARAM wParam, LPARAM lParam) { if( (!m_bConnected) || (wParam&EV_RXCHAR)!=EV_RXCHAR) { SetEvent(m_hPostMsgEvent); //允许允许发送下一个信息 return 0L; } //开始接收数据 int nLength; char buf[4096/4]; CString str; nLength=ReadComm(buf,100); //获取数据和长度 if(nLength) { for(int i=0;i<nLength;i++) str+=buf[i]; m_receive.ReplaceSel(str); } SetEvent(m_hPostMsgEvent); //允许发送下一个信息 return 0L; } //读取串口数据,返回长度。 //输入参数:要读的长度 //注意事项:输入的要读的长度如果比实际缓冲里面的数据量大的话,返回的是较小的值 DWORD CComDlg::ReadComm(char *buf, DWORD dwLength) { DWORD length=0; COMSTAT ComStat; DWORD dwErrorFlags; ClearCommError(h_com,&dwErrorFlags,&ComStat); length=min(dwLength, ComStat.cbInQue); //看上面的注意事项 ReadFile(h_com,buf,length,&length,&m_osRead); return length; }