當(dāng)前位置:機(jī)電之家首頁(yè) >> PLC技術(shù)>> PLC基礎(chǔ) >> PLC通信 >> 用VC 6.0實(shí)現(xiàn)串行通信的三種方法
用VC 6.0實(shí)現(xiàn)串行通信的三種方法

---- 摘要: 本文介紹了在bbbbbbs平臺(tái)下串行通信的實(shí)現(xiàn)機(jī)制,討論了根據(jù)不同的條件用Visual C++ 設(shè)計(jì)串行通信程序的三種方法,并結(jié)合實(shí)際,實(shí)現(xiàn)對(duì)溫度數(shù)據(jù)的接收監(jiā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ī),每隔10S向主機(jī)發(fā)送一次采樣數(shù)據(jù),主機(jī)向單片機(jī)發(fā)送相關(guān)的控制命令,實(shí)現(xiàn)串行數(shù)據(jù)接收,處理,記錄,顯示,實(shí)時(shí)繪制曲線。串行通信程序開(kāi)發(fā)環(huán)境為 VC++ 6.0。

---- bbbbbbs下串行通信

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

---- 實(shí)現(xiàn)串行通信的三種方法

---- 方法一:使用VC++提供的串行通信控件MSComm 首先,在對(duì)話框中創(chuàng)建通信控件,若Control工具欄中缺少該控件,可通過(guò)菜單Project --> Add to Project --> Components and Control插入即可,再將該控件從工具箱中拉到對(duì)話框中。此時(shí),你只需要關(guān)心控件提供的對(duì) bbbbbbs 通訊驅(qū)動(dòng)程序的 API 函數(shù)的接口。換句話說(shuō),只需要設(shè)置和監(jiān)視MSComm控件的屬性和事件。

---- 在ClassWizard中為新創(chuàng)建的通信控件定義成員對(duì)象(CMSComm m_Serial),通過(guò)該對(duì)象便可以對(duì)串口屬性進(jìn)行設(shè)置,MSComm 控件共有27個(gè)屬性,這里只介紹其中幾個(gè)常用屬性:

---- CommPort 設(shè)置并返回通訊端口號(hào),缺省為COM1。

---- Settings 以字符串的形式設(shè)置并返回波特率、奇偶校驗(yàn)、數(shù)據(jù)位、停止位。

---- PortOpen 設(shè)置并返回通訊端口的狀態(tài),也可以打開(kāi)和關(guān)閉端口。

---- bbbbb 從接收緩沖區(qū)返回和刪除字符。

---- Output 向發(fā)送緩沖區(qū)寫(xiě)一個(gè)字符串。

---- bbbbbLen 設(shè)置每次bbbbb讀入的字符個(gè)數(shù),缺省值為0,表明讀取接收緩沖 區(qū)中的全部?jī)?nèi)容。

---- InBufferCount 返回接收緩沖區(qū)中已接收到的字符數(shù),將其置0可以清除接收緩 沖區(qū)。

---- bbbbbMode 定義bbbbb屬性獲取數(shù)據(jù)的方式(為0:文本方式;為1:二進(jìn)制方式)。

---- RThreshold 和 SThreshold 屬性,表示在 OnComm 事件發(fā)生之前,接收緩沖區(qū)或發(fā)送緩沖區(qū)中可以接收的字符數(shù)。

---- 以下是通過(guò)設(shè)置控件屬性對(duì)串口進(jìn)行初始化的實(shí)例:

BOOL CSampleDlg:: PortOpen()
{
BOOL m_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.bbbbbMode(1); // 設(shè)置數(shù)據(jù)獲取方式
m_Serial.SetbbbbbLen(0); // 設(shè)置讀取方式
m_Opened=m_Serail.SetPortOpen(1); // 打開(kāi)指定的串口
return m_Opened;
}

---- 打開(kāi)所需串口后,需要考慮串口通信的時(shí)機(jī)。在接收或發(fā)送數(shù)據(jù)過(guò)程中,可能需要監(jiān)視并響應(yīng)一些事件和錯(cuò)誤,所以事件驅(qū)動(dòng)是處理串行端口交互作用的一種非常有效的方法。使用 OnComm 事件和 CommEvent 屬性捕捉并檢查通訊事件和錯(cuò)誤的值。發(fā)生通訊事件或錯(cuò)誤時(shí),將觸發(fā) OnComm 事件,CommEvent 屬性的值將被改變,應(yīng)用程序檢查 CommEvent 屬性值并作出相應(yīng)的反應(yīng)。在程序中用ClassWizard為CMSComm控件添加OnComm消息處理函數(shù):

void CSampleDlg::OnComm()
{
......
switch(m_Serial.GetCommEvent())
{
case 2:
// 串行口數(shù)據(jù)接收,處理;
}
}

---- 方法二:在單線程中實(shí)現(xiàn)自定義的串口通信類(lèi)

---- 控件簡(jiǎn)單易用,但由于必須拿到對(duì)話框中使用,在一些需要在線程中實(shí)現(xiàn)通信的應(yīng)用場(chǎng)合,控件的使用顯得捉襟見(jiàn)肘。此時(shí),若能夠按不同需要定制靈活的串口通信類(lèi)將彌補(bǔ)控件的不足,以下將介紹如何在單線程中建立自定義的通信類(lèi)。

---- 該通信類(lèi)CSimpleComm需手動(dòng)加入頭文件與源文件,其基類(lèi)為Cbbbbbb,大致建立步驟如下:

---- (1) 打開(kāi)串口,獲取串口資源句柄

[NextPage]

---- 通信程序從CreateFile處指定串口設(shè)備及相關(guān)的操作屬性。再返回一個(gè)句柄,該句柄將被用于后續(xù)的通信操作,并貫穿整個(gè)通信過(guò)程。CreateFile()函數(shù)中有幾個(gè)值得注意的參數(shù)設(shè)置:串口共享方式應(yīng)設(shè)為0,串口為不可共享設(shè)備;創(chuàng)建方式必須為OPEN_EXISTING,即打開(kāi)已有的串口。對(duì)于dwFlagAndAttribute參數(shù),對(duì)串口有意義的值是FILE_FLAG_OVERLAPPED,該標(biāo)志表明串口采用異步通信模式,可進(jìn)行重疊操作;若值為NULL,則為同步通信方式,在同步方式下,應(yīng)用程序?qū)⑹冀K控制程序流,直到程序結(jié)束,若遭遇通信故障等因素,將導(dǎo)致應(yīng)用程序的永久等待,所以一般多采用異步通信。

---- (2)串口設(shè)置

---- 串口打開(kāi)后,其屬性被設(shè)置為默認(rèn)值,根據(jù)具體需要,通過(guò)調(diào)用GetCommState(hComm,&dcb)讀取當(dāng)前串口設(shè)備控制塊DCB(Device Control Block)設(shè)置,修改后通過(guò)SetCommState(hComm,&dcb)將其寫(xiě)入。再需注意異步讀寫(xiě)的超時(shí)控制設(shè)置, 通過(guò)COMMTIMEOUTS結(jié)構(gòu)設(shè)置超時(shí),調(diào)用SetCommTimeouts(hComm,&timeouts)將結(jié)果寫(xiě)入。以下是溫度監(jiān)控程序中串口初始化成員函數(shù):

BOOL CSimpleComm::Open( )
{
DCB dcb;

m_hIDComDev=CreateFile( "COM2",
GENERIC_READ | GENERIC_WRITE,
0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_
NORMAL|FILE_FLAG_OVE RLAPPED, NULL );
// 打開(kāi)串口,異步操作
if( m_hIDComDev == NULL ) return( FALSE );

dcb.DCBlength = sizeof( DCB );
GetCommState( m_hIDComDev, &dcb ); // 獲得端口默認(rèn)設(shè)置
dcb.BaudRate=CBR_4800;
dcb.ByteSize=8;
dcb.Parity= NOPARITY;
dcb.StopBits=(BYTE) ONESTOPBIT;
...... }

---- (3)串口讀寫(xiě)操作

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

BOOL bReadStatus;
bReadStatus = ReadFile( m_hIDComDev, buffer,
dwBytesRead, &dwBytesRead, &m_OverlappedRead );
if(!bReadStatus)
{
if(GetLastError()==ERROR_IO_PENDING)
{
WaitForSinglebbbbbb(m_OverlappedRead.hEvent,1000);
return ((int)dwBytesRead);
}
return(0);
}
return ((int)dwBytesRead);

---- 定義全局變量m_Serial作為新建通信類(lèi)CSimpleComm的對(duì)象,通過(guò)調(diào)用類(lèi)的成員函數(shù)即可實(shí)現(xiàn)所需串行通信功能。與方法一相比,方法二賦予串行通信程序設(shè)計(jì)較大的靈活性,端口的讀寫(xiě)可選擇較簡(jiǎn)單的查詢式,或通過(guò)設(shè)置與外設(shè)數(shù)據(jù)發(fā)送時(shí)間間隔TimeCycle相同的定時(shí)器:SetTimer(1,TimeCycle,NULL),進(jìn)行定時(shí)讀取或發(fā)送。

[NextPage]

CSampleView:: OnTimer(UINT nIDEvent)
{
char bbbbbData[30];
m_Serial.ReadData(bbbbbData,30);
// 數(shù)據(jù)處理
}
---- 若對(duì)端口數(shù)據(jù)的響應(yīng)時(shí)間要求較嚴(yán)格,可采用事件驅(qū)動(dòng)I/O讀寫(xiě),bbbbbbs定義了9種串口通信事件,較常用的有:

---- EV_RXCHAR: 接收到一個(gè)字節(jié),并放入輸入緩沖區(qū)。

---- EV_TXEMPTY: 輸出緩沖區(qū)中的最后一個(gè)字符發(fā)送出去。

---- EV_RXFLAG: 接收到事件字符(DCB結(jié)構(gòu)中EvtChar成員),放入輸入緩沖區(qū)。

---- 在用SetCommMask()指定了有用的事件后,應(yīng)用程序可調(diào)用WaitCommEvent()來(lái)等待事件的發(fā)生。SetCommMask(hComm,0)可使WaitCommEvent()中止。

---- 方法三 多線程下實(shí)現(xiàn)串行通信

---- 方法一,二適用于單線程通信。在很多工業(yè)控制系統(tǒng)中,常通過(guò)擴(kuò)展串口連接多個(gè)外設(shè),各外設(shè)發(fā)送數(shù)據(jù)的重復(fù)頻率不同,要求后臺(tái)實(shí)時(shí)無(wú)差錯(cuò)捕捉,采集,處理,記錄各端口數(shù)據(jù),這就需要在自定義的串行通信類(lèi)中創(chuàng)建端口監(jiān)視線程,以便在指定的事件發(fā)生時(shí)向相關(guān)的窗口發(fā)送通知消息。

---- 線程的基本概念可詳見(jiàn)VC++參考書(shū)目,bbbbbbs內(nèi)部的搶先調(diào)度程序在活動(dòng)的線程之間分配CPU時(shí)間,Win 32 區(qū)分兩種不同類(lèi)型的線程,一種是用戶界面線程UI(User Interface Thread),它包含消息循環(huán)或消息泵,用于處理接收到的消息;另一種是工作線程(Work Thread),它沒(méi)有消息循環(huán),用于執(zhí)行后臺(tái)任務(wù)。用于監(jiān)視串口事件的線程即為工作線程。

---- 多線程通信類(lèi)的編寫(xiě)在端口的配置,連接部分與單線程通信類(lèi)相同,在端口配置完畢后,最重要的是根據(jù)實(shí)際情況,建立多線程之間的同步對(duì)象,如信號(hào)燈,臨界區(qū),事件等,相關(guān)細(xì)節(jié)可參考VC++ 中的同步類(lèi)。

---- 一切就緒后即可啟動(dòng)工作線程:

CWinThrea *CommThread = AfxBegin
Thread(CommWatchThread, // 線程函數(shù)名
(LPVOID) m_pTTYInfo, // 傳遞的參數(shù)
THREAD_PRIORITY_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(pTTYInfo->idComDev,&dwEvtMask,NULL))
{
if((dwEvtMask & pTTYInfo->dwEvtMask )== pTTYInfo->dwEvtMask)
{
WaitForSinglebbbbbb(pTTYInfo->hPostEvent,0xFFFFFFFF);
ResetEvent(pTTYInfo->hPostEvent); // 置同步事件對(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)

[NextPage]
ON_MESSAGE(ID_COM1_DATA, OnProcessCom1Data)
ON_MESSAGE(ID_COM2_DATA, OnProcessCom2Data)
.....
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

---- 然后在各成員函數(shù)中完成對(duì)各串口數(shù)據(jù)的接收處理,但必須保證在下一次監(jiān)測(cè)到有數(shù)據(jù)到來(lái)之前,能夠完成所有的中間處理工作。否則將造成數(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)。

轉(zhuǎn)自《VCHelp.com》



作者:未知 點(diǎn)擊:760次 [打印] [關(guān)閉] [返回頂部]
本文標(biāo)簽:用VC 6.0實(shí)現(xiàn)串行通信的三種方法
* 由于無(wú)法獲得聯(lián)系方式等原因,本網(wǎng)使用的文字及圖片的作品報(bào)酬未能及時(shí)支付,在此深表歉意,請(qǐng)《用VC 6.0實(shí)現(xiàn)串行通信的三種方法》相關(guān)權(quán)利人與機(jī)電之家網(wǎng)取得聯(lián)系。
電子樣本

SN系列樣冊(cè)
:鞏經(jīng)理
:13915946763
:南京塞姆泵業(yè)有限公司
個(gè)人求購(gòu)

楊異乾 【求購(gòu)】  電涌保護(hù)器  2025-11-28
趙焱 【求購(gòu)】  電氣溫控閥  2025-11-28
張揚(yáng)瓊 【求購(gòu)】  ABB火檢...  2025-11-27
張雪根 【求購(gòu)】  固體除垢劑  2025-11-26
趙經(jīng)理 【求購(gòu)】  變壓器  2025-11-26
羅經(jīng)理 【求購(gòu)】  巡邏車(chē)跟蹤...  2025-11-26
趙經(jīng)理 【求購(gòu)】  柴油發(fā)電機(jī)  2025-11-26
沈雙 【求購(gòu)】  柴油過(guò)濾紙  2025-11-26
VIP公司推薦