VC串口編程帶全部注釋和步驟_第1頁
VC串口編程帶全部注釋和步驟_第2頁
VC串口編程帶全部注釋和步驟_第3頁
VC串口編程帶全部注釋和步驟_第4頁
VC串口編程帶全部注釋和步驟_第5頁
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、用 VC 6.0 實(shí)現(xiàn)串行通信的三種方法和介紹在實(shí)驗(yàn)室和工業(yè)應(yīng)用中,串口是常用的計(jì)算機(jī)與外部串行設(shè)備之間的數(shù)據(jù)傳輸通道,由于串行通信方便易行,所以應(yīng)用廣泛。依據(jù)不同的條件實(shí)現(xiàn)對(duì)串口的靈活編程控制是我們所需要的。 - 在光學(xué)鏡片鍍膜工藝中,用單片機(jī)進(jìn)行多路溫度數(shù)據(jù)采集控制,采集結(jié)果以串行方式進(jìn)入主機(jī),每隔10秒向主機(jī)發(fā)送一次采樣數(shù)據(jù),主機(jī)向單片機(jī)發(fā)送相關(guān)的控制命令,實(shí)現(xiàn)串行數(shù)據(jù)接收、處理、記錄、顯示,實(shí)時(shí)繪制曲線。串行通信程序開發(fā)環(huán)境為 VC 6.0。 Windows下串行通信 - 與以往 DOS 下串行通信程序不同的是, 窗口 不提倡應(yīng)用程序直接控制硬件,而是通過 窗口 操作系統(tǒng)提供的設(shè)備驅(qū)動(dòng)

2、程序來進(jìn)行數(shù)據(jù)傳遞。串行口在 贏32 中是作為文件來進(jìn)行處理的,而不是直接對(duì)端口進(jìn)行操作,對(duì)于串行通信, 贏32 提供了相應(yīng)的文件 I/O 函數(shù)與通信函數(shù),通過了解這些函數(shù)的使用,可以編制出符合不同需要的通信程序。 -與通信設(shè)備相關(guān)的結(jié)構(gòu)有COMMCONFIG、 COMMPROP、COMMTIMEOUTS、COMSTAT、DCB、MODEMDEVCAPS、 MODEMSETTINGS共7個(gè),與通信有關(guān)的Windows API函數(shù)共有26個(gè),詳細(xì)說明可參考 MSDN幫助文件。以下將結(jié)合實(shí)例,給出實(shí)現(xiàn)串行通信的三種方法。 實(shí)現(xiàn)串行通信的三種方法 - 方法一:使用 VC 提供的串行通信控件 MSCo

3、mm -首先,在對(duì)話框中創(chuàng)建通信控件,若Control工具欄中缺少該控件,可通過菜單ProjectAdd to ProjectComponents and Control插入即可,再將該控件從工具箱中拉到對(duì)話框中。此時(shí),你只需要關(guān)心控件提供的對(duì) Windows 通信驅(qū)動(dòng)程序的 API 函數(shù)的接口。換句話說,只需要設(shè)置和監(jiān)視MSComm控件的屬性和事件。 -在ClassWizard中為新創(chuàng)建的通信控件定義成員對(duì)象(CMSComm m_Serial),通過該對(duì)象便可以對(duì)串口屬性進(jìn)行設(shè)置,MSComm 控件共有27 個(gè)屬性,這里只介紹其中幾個(gè)常用屬性: CommPort 設(shè)置并返回通信端口號(hào),缺省為

4、 COM1。 Settings 以字符串的形式設(shè)置并返回波特 率、奇偶校驗(yàn)、數(shù)據(jù)位、停止位。 PortOpen 設(shè)置并返回通信端口的狀態(tài),也可 以打開和關(guān)閉端口。 Input 從接收緩沖區(qū)返回和刪除字符。 Output 向發(fā)送緩沖區(qū)寫一個(gè)字符串。 InputLen 設(shè)置每次Input讀入的字符個(gè)數(shù),缺 省值為0,表明讀取接收緩沖區(qū)中的全 部內(nèi)容。 InBufferCount 返回接收緩沖區(qū)中已接收到的字符 數(shù),將其置0可以清除接收緩沖區(qū)。 InputMode 定義Input屬性獲取數(shù)據(jù)的方式(為 0:文本方式;為1:二進(jìn)制方式)。 -RThreshold 和 SThreshold 屬性,表示在

5、 OnComm 事件發(fā)生之前,接收緩沖區(qū)或發(fā)送緩沖區(qū)中可以接收的字符數(shù)。 - 以下是通過設(shè)置控件屬性對(duì)串口進(jìn)行初始化的實(shí)例: BOOLCSampleDlg: PortOpen () BOOLm_Opened; m_Serial.SetCommPort(2);/指定串口號(hào) m_Serial.SetSettings(“4800,N,8,1); /通信參數(shù)設(shè)置 m_Serial.SetInBufferSize(1024);/指定接收緩沖區(qū)大小 m_Serial.SetInBufferCount(0);/清空接收緩沖區(qū) m_Serial.InputMode(1);/設(shè)置數(shù)據(jù)獲取方式 m_Serial.

6、SetInputLen(0);/設(shè)置讀取方式 & nbsp ;& nbsp ; m_Opened=m_Serail.SetPortOpen(1); /打開指定的串口 回來m_Opened; - 空的CSampleDlg:OnComm () & nbsp ; switch(m_Serial.GetCommEvent() 盒子2: /串行口數(shù)據(jù)接收,處理; - 方法二:在單線程中實(shí)現(xiàn)自定義的串口通信類 -控件簡單易用,但由于必須拿到對(duì)話框中使用,在一些需要在線程中實(shí)現(xiàn)通信的應(yīng)用場合,控件的使用顯得捉襟見肘。此時(shí),若能夠按不同需要定制靈活的串口通信類將彌補(bǔ)控件的不足,以下將介紹如何在單線程中建立自定

7、義的通信類。 -該通信類CSimpleComm需手動(dòng)加入頭文件與源文件,其基類為CObject,大致建立步驟如下: -(1) 打開串口,獲取串口資源句柄 -通信程序從CreateFile處指定串口設(shè)備及相關(guān)的操作屬性,再返回一個(gè)句柄,該句柄將被用于后續(xù)的通信操作,并貫穿整個(gè)通信過程。CreateFile() 函數(shù)中有幾個(gè)值得注意的參數(shù)設(shè)置:串口共享方式應(yīng)設(shè)為0,串口為不可共享設(shè)備;創(chuàng)建方式必須為OPEN_EXISTING,即打開已有的串口。對(duì)于dwFlagAndAttribute參數(shù),對(duì)串口有意義的值是FILE_FLAG_OVERLAPPED,該標(biāo)志表明串口采用異步通信模式,可進(jìn)行重疊操作;若

8、值為NULL,則為同步通信方式,在同步方式下,應(yīng)用程序?qū)⑹冀K控制程序流,直到程序結(jié)束,若遭遇通信故障等因素,將導(dǎo)致應(yīng)用程序的永久等待,所以一般多采用異步通信。 -(2)串口設(shè)置 - BOOL & nbsp ; CSimpleComm:打開 () DCB dcb; m_hIDComDev=CreateFile ( “COM2, GENERIC_READ | GENERIC_WRITE,0, 空,打開_現(xiàn)有 ,文件_ATTRIBUTE_NORMAL | 文件_FLAG_OVE & nbsp ;& nbsp ;& nbsp ; RLAPPED ,空);& nbsp ;& nbsp ;& nbsp ;

9、& nbsp ;& nbsp ;& nbsp ; / 打開串口,異步操作 如果( m_hIDComDev =NULL )回來(假); & nbsp ;& nbsp ;& nbsp ; dcb.DCBlength = sizeof ( DCB ); GetCommState( m_hIDComDev, dcb ); /獲得端口默認(rèn)設(shè)置 & nbsp ;& nbsp ; dcb.BaudRate=CBR_4800; & nbsp ;& nbsp ; dcb.ByteSize=8; & nbsp ;& nbsp ; dcb.Parity= NOPARITY ; & nbsp ;& nbsp ; dc

10、b.StopBits=(BYTE) ONESTOPBIT ; -(3)串口讀寫操作 -主要運(yùn)用ReadFile()與WriteFile()API函數(shù),若為異步通信方式,兩函數(shù)中最后一個(gè)參數(shù)為指向OVERLAPPED結(jié)構(gòu)的非空指針,在讀寫函數(shù)返回值為FALSE的情況下,調(diào)用GetLastError()函數(shù),返回值為ERROR_IO_PENDING,表明I/O操作懸掛,即操作轉(zhuǎn)入后臺(tái)繼續(xù)執(zhí)行。此時(shí),可以用WaitForSingleObject()來等待結(jié)束信號(hào)并設(shè)置最長等待時(shí)間。舉例如下: BOOLbReadStatus; bReadStatus = ReadFile ( m_hIDComDev

11、,緩沖區(qū), dwBytesRead, dwBytesRead,m_OverlappedRead ); 如果(! bReadStatus ) 如果( GetLastError () =ERROR_IO_PENDING ) & nbsp ;& nbsp ; WaitForSingleObject(m_OverlappedRead.hEvent,1000); 回來( int ) dwBytesRead ); 回來(0); 回來( int ) dwBytesRead ); -定義全局變量m_Serial作為新建通信類CSimpleComm的對(duì)象,通過調(diào)用類的成員函數(shù)即可實(shí)現(xiàn)所需串行通信功能。與方法一相

12、比,方法二賦予串行通信程序設(shè)計(jì)較大的靈活性,端口的讀寫可選擇較簡單的查詢式,或通過設(shè)置與外設(shè)數(shù)據(jù)發(fā)送時(shí)間間隔TimeCycle相同的定時(shí)器:SetTimer(1,TimeCycle,NULL),進(jìn)行定時(shí)讀取或發(fā)送。 CSampleView: OnTimer ( UINT nIDEvent ) charInputData 30; & nbsp ;& nbsp ;& nbsp ;& nbsp ;& nbsp ;& nbsp ; m_Serial.ReadData(InputData,30); / 數(shù)據(jù)處理 -若對(duì)端口數(shù)據(jù)的響應(yīng)時(shí)間要求較嚴(yán)格,可采用事件驅(qū)動(dòng) I/O讀寫,Windows定義了9種串口

13、通信事件,較常用的有: EV_RXCHAR: 接收到一個(gè)字節(jié),并放入輸入 緩沖區(qū)。 EV_TXEMPTY: 輸出緩沖區(qū)中的最后一個(gè)字 符發(fā)送出去。 EV_RXFLAG: 接收到事件字符(DCB結(jié)構(gòu)中 EvtChar成員),放入輸入緩沖區(qū)。 -在用SetCommMask()指定了有用的事件后,應(yīng)用程序可調(diào)用WaitCommEvent()來等待事件的發(fā)生。SetCommMask(hComm,0)可使WaitCommEvent() 中止。 - 方法三:多線程下實(shí)現(xiàn)串行通信 - -線程的基本概念可詳見VC參考書目,Windows內(nèi)部的搶先調(diào)度程序在活動(dòng)的線程之間分配CPU時(shí)間,Win 32 區(qū)分兩種不

14、同類型的線程,一種是用戶界面線程UI(User Interface Thread),它包含消息循環(huán)或消息泵,用于處理接收到的消息;另一種是工作線程(Work Thread),它沒有消息循環(huán),用于執(zhí)行后臺(tái)任務(wù)。用于監(jiān)視串口事件的線程即為工作線程。 -多線程通信類的編寫在端口的配置,連接部分與單線程通信類相同,在端口配置完畢后,最重要的是根據(jù)實(shí)際情況,建立多線程之間的同步對(duì)象,如信號(hào)燈、臨界區(qū)、事件等,相關(guān)細(xì)節(jié)可參考VC 中的同步類。 -一切就緒后即可啟動(dòng)工作線程: CWinThrea CommThread = AfxBeginThread(CommWatchThread, / 線程函數(shù)名 (LP

15、VOID) m_pTTYInfo, / 傳遞的參數(shù) THREAD_優(yōu)先權(quán)_ABOVE_NORMAL, / 設(shè)置線程優(yōu)先級(jí) (UINT) 0,/最大堆棧大小 (DWORD) CREATE_SUSPENDED, /創(chuàng)建標(biāo)志 (LPSECURITY_ATTRIBUTES) NULL);/安全性標(biāo)志 - 同時(shí),在串口事件監(jiān)視線程中: if(WaitCommEvent(pTTYInfoidComDev, dwEvtMask,NULL) if(dwEvtMask pTTYInfodwEvtMask ) = pTTYInfodwEvtMask) WaitForSingleObject(pTTYInfohPo

16、stEvent,0xFFFFFFFF); ResetEvent(pTTYInfohPostEvent); / 置同步事件對(duì)象為非信號(hào)態(tài) : PostMessage ( CSampleView , ID_COM1_DATA ,0,0); / 發(fā)送通知消息 -用PostMessage()向指定窗口的消息隊(duì)列發(fā)送通知消息,相應(yīng)地,需要在該窗口建立消息與成員函數(shù)間的映射,用ON_MESSAGE將消息與成員函數(shù)名關(guān)聯(lián)。 BEGIN_MESSAGE_MAP ( CSampleView , CView ) / AFX_MSG_MAP ( CSampleView ) ON_MESSAGE ( ID_COM1_

17、DATA , OnProcessCom1Data ) ON_MESSAGE ( ID_COM2_DATA , OnProcessCom2Data ) / AFX_MSG_MAP END_MESSAGE_MAP () -然后在各成員函數(shù)中完成對(duì)各串口數(shù)據(jù)的接收處理,但必須保證在下一次監(jiān)測到有數(shù)據(jù)到來之前,能夠完成所有的中間處理工作,否則將造成數(shù)據(jù)的捕捉錯(cuò)誤。 -多線程的實(shí)現(xiàn)可以使得各端口獨(dú)立,準(zhǔn)確地實(shí)現(xiàn)串行通信,使串口通信具有更廣泛的靈活性與嚴(yán)格性,且充分利用了CPU時(shí)間。但在具體的實(shí)時(shí)監(jiān)控系統(tǒng)中如何協(xié)調(diào)多個(gè)線程,線程之間以何種方式實(shí)現(xiàn)同步也是在多線程串行通信程序?qū)崿F(xiàn)的難點(diǎn)。 - 以 VC 6.

18、0 為工具,實(shí)現(xiàn)串行通信的三種方法各有利弊VC+ 簡單而強(qiáng)大 的多線程串口編程工具 CserialPort類一個(gè)串口類, 已作了一個(gè)基于對(duì)話框的同時(shí)檢測4個(gè)串口示例的程序,在這兒主要介紹如何將這個(gè)類應(yīng)用到VC中基于文檔的程序中。為了加深對(duì)串口數(shù)據(jù)處理的了解,我們利用這個(gè)類解決如下問題: 問題: 串口2(COM2)每隔1秒向串口1(COM1)發(fā)送的NEMA格式的報(bào)文:串頭為$,串尾為,中間為一個(gè)xxxx的整數(shù)( 比如2345,不足4位則前面以0代替代),最后是hh校驗(yàn),規(guī)定hh為xxxx四個(gè)數(shù)的半BYTE校驗(yàn)和,最后加上回車與換行。整個(gè)數(shù)據(jù)包為$xxxx*hh。 串口1收到上述報(bào)文后,校驗(yàn)正確后

19、,將發(fā)來的數(shù)據(jù)顯示在視窗中,并記下發(fā)來的正確幀數(shù)和錯(cuò)誤幀數(shù),若正確,還向串口2發(fā)送Y,串口2收到Y(jié)后將收到的Y的計(jì)數(shù)顯示在視窗中。 測試方法: 將三線制串口線聯(lián)接上同一臺(tái)計(jì)算機(jī)的兩個(gè)串口,編好程序后就可測試。如果沒有兩個(gè)串口的微機(jī),自己改改程序。 好了,你可以先下載源程序: scporttest.zip(大?。?9KB,VC6,WIN9X/2000,SerialPort.h SerialPort.cpp是兩個(gè)類文件) 編程步驟: 1. 建立程序: 建立一個(gè)基于單文檔的MFC應(yīng)用程序SCPortTest,所有步驟保持缺省狀態(tài)。 2. 添加類文件: 將SerialPort.h SerialPort

20、.cpp兩個(gè)類文件復(fù)制到工程文件夾中,用Project-Add to Project-Files命令將上述兩個(gè)文件加入工程。并在SCPortTestView.h中將頭文件SerialPort.h說明:#include SerialPort.h。 3. 人工增加串口消息響應(yīng)函數(shù):OnCommunication(WPARAM ch, LPARAM port) 首先在SCPortTestView.h中添加串口字符接收消息WM_COMM_RXCHAR(串口接收緩沖區(qū)內(nèi)有一個(gè)字符)的響應(yīng)函數(shù)聲明: / AFX_MSG ( CSCPortTestView ) afx_msg長的 OnCommunicati

21、on ( WPARAM ch , LPARAM端口 ); / AFX_MSG 然后在SCPortTestView.cpp文件中進(jìn)行WM_COMM_RXCHAR消息映射: BEGIN_MESSAGE_MAP ( CSCPortTestView , CView ) / AFX_MSG_MAP ( CSCPortTestView ) ON_MESSAGE ( WM_COMM_RXCHAR , OnCommunication ) / AFX_MSG_MAP END_MESSAGE_MAP () 接著在SCPortTestView.cpp中加入函數(shù)的實(shí)現(xiàn): 長的 CSCPortTestView:OnCo

22、mmunication ( WPARAM ch , LPARAM端口 ) . 注意:由于這個(gè)串口類加入工程后,沒有自動(dòng)的消息映射機(jī)制,因此上述步驟均需要手工添加。 4 初始化串口 在視創(chuàng)建時(shí)初始化串口,首先利用ClassWizardr按下圖生成OnInitialUpdate()函數(shù)。 接著在SerialPort.h文件中說明我們?cè)诔绦蛑幸玫降娜肿兞浚?保存兩個(gè)串口接收數(shù)據(jù): char m_chChecksum;/用于COM1的校驗(yàn)和計(jì)算 CString m_strRXhhCOM1;/用于存放COM1接收的半BYTE校驗(yàn)字節(jié)hh CString m_strRXDataCOM1;/COM1接收

23、數(shù)據(jù) CString m_strRXDataCOM2;/COM2接收數(shù)據(jù) UINT m_nRXErrorCOM1;/COM1接收數(shù)據(jù)錯(cuò)誤幀數(shù) UINT m_nRXErrorCOM2;/COM2接收數(shù)據(jù)錯(cuò)誤幀數(shù) UINT m_nRXCounterCOM1;/COM1接收數(shù)據(jù)錯(cuò)誤幀數(shù) UINT m_nRXCounterCOM2;/COM2接收數(shù)據(jù)錯(cuò)誤幀數(shù)CString 再在SerialPort.h文件中說明串口類對(duì)象:CSerailPort m_ComPort2;(public)。 因?yàn)橐跏蓟?個(gè)串口,所以這里用了數(shù)組。 下面是初始化串口1和串口2: 空的 CSCPortTestView:OnI

24、nitialUpdate () CView:OnInitialUpdate (); / TODO :添加你的這里的專業(yè)化的代碼并且/或呼叫底班 m_chChecksum=0;/校驗(yàn)和置0 m_nRXErrorCOM1=0;/COM1接收數(shù)據(jù)錯(cuò)誤幀數(shù)置0 m_nRXErrorCOM2=0;/COM2接收數(shù)據(jù)錯(cuò)誤幀數(shù)置0 m_nRXCounterCOM1=0;/COM1接收數(shù)據(jù)錯(cuò)誤幀數(shù)置0 m_nRXCounterCOM2=0;/COM2接收數(shù)據(jù)錯(cuò)誤幀數(shù)置0 m_strRXhhCOM1.Empty();/清空半BYTE校驗(yàn)hh存儲(chǔ)變量 適合于 ( int i=0;我2;i+) 如果 (m_ComP

25、orti.InitPort(this,i+1,9600,N,8,1,EV_RXFLAG | EV_RXCHAR ,512) /portnr=1(2),baud=960,parity=N,databits=8,stopsbits=1, / dwCommEvents=EV_RXCHAR | EV_RXFLAG ,nBufferSize=512 m_ComPorti.StartMonitoring();/啟動(dòng)串口監(jiān)視線程 if(i=1) SetTimer(1,1000,NULL);/設(shè)置定時(shí)器,1秒后發(fā)送數(shù)據(jù) 另外 CString str; str.Format(COM%d 沒有發(fā)現(xiàn),或被其它設(shè)備占

26、用,i+1); AfxMessageBox ( str ); 5 利用ClassWizard按下圖生成CSCPortTestView 的時(shí)間消息WM_TIMER響應(yīng)函數(shù): 空的 CSCPortTestView:OnTimer ( UINT nIDEvent ) / TODO :添加你的這里的消息處理器代碼并且/或呼叫默認(rèn) int randdata=rand()%9000;/產(chǎn)生9000以內(nèi)的隨機(jī)數(shù) CString strSendData; strSendData.Format(%04d,randdata); SendString(strSendData, 2);/串口2發(fā)送數(shù)據(jù); CView:

27、OnTimer ( nIDEvent ); 上面用到的SendString()需按如下方式生成: 在ClassView中單擊鼠標(biāo)右鍵,在環(huán)境菜單中選擇Add Member Function: 空的 CSCPortTestView:SendString ( CString & str , int端口 ) char checksum=0, cr=CR , lf=LF; char c1,c2; 適合于 ( int i=0;i4)&0x0f ); 如果(c110)c1+=“0;另外的c1+=一-10; 如果(c2TextOut(10,50,strtemp);/顯示接收到的數(shù)據(jù) ReleaseDC ( pDC ); if(port=1) /COM1接收到數(shù)據(jù) m_strRXDataCOM1+=( char ) ch; 切換( ch ) 大小寫“$”: m_chChecksum=0;/開始計(jì)算CheckSum flag=0; 打破; 大小寫“*”: flag=2; c2=m_chChecksum&0x0f;c1=( m_chChecksum4)&0x0f ); 如果(c110)c1+=“0;另外的c1

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論