在工業控制中,工控機(一般都基於 Windows 平臺)經常需要與智能儀表通過串口
進行通信.串口通信方便易行,應用廣泛.
半雙工的,只能由作爲主節點的工控 PC 機依次輪詢網絡上的各智能控制單元子節點.
每次通信都是由 PC 機通過串口向智能控制單元發佈命令,智能控制單元在接收到正
確的命令後作出應答.
方法程序簡單,但欠靈活.其二是調用 Windows的 API 函數,這種方法可以清楚地掌握
串口通信的機制,並且自由靈活.下面只介紹 API 串口通信部分.
方式).同步操作時,API 函數會阻塞直到操作完成以後才能返回(在多線程方式中,
雖然不會阻塞主線程,但是仍然會阻塞監聽線程);而重疊操作方式,API 函數會立即
返回,操作在後臺進行,避免線程的阻塞.
無論哪種操作方式,一般都通過四個步驟來完成:
(1)打開串口
(2)配置串口
(3)讀寫串口
(4)關閉串口
一 打開串口
Win32 系統把文件的概念進行了擴展.無論是文件、通信設備、命名管道、郵件
槽、磁盤、還是控制檯,都是用 API 函數 CreateFile來打開或創建的.該函數的原型
爲:
HANDLE CreateFile( LPCTSTR lpFileName,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);
• lpFileName:將要打開的串口邏輯名,如“COM1”;
• dwDesiredAccess: 指定串口訪問的類型,可以是讀取、寫入或二者並列;
• dwShareMode:指定共享屬性,由於串口不能共享,該參數必須置爲 0;
• lpSecurityAttributes:引用安全性屬性結構,缺省值爲 NULL;
• dwCreationDistribution:創建標誌,對串口操作該參數必須置爲
OPEN_EXISTING;
• dwFlagsAndAttributes:屬性描述,用於指定該串口是否進行異步操作,該值
爲 FILE_FLAG_OVERLAPPED,表示使用異步的 I/O;該值爲 0,表示同步 I/O 操
作;
• hTemplateFile:對串口而言該參數必須置爲 NULL;
同步 I/O 方式打開串口的示例:
HANDLE hCom;//全局變量,串口句柄
hCom=CreateFile("COM1",// 串口名稱
if(hCom==(HANDLE)-1)
{
MessageBox("打開 COM 失敗!");
return FALSE;
}
return TRUE;
重疊 I/O 打開串口的示例:
HANDLE hCom;//全局變量,串口句柄
hCom =CreateFile("COM1",//串口名稱
if(hCom==INVALID_HANDLE_VALUE)
{
MessageBox("打開 COM 失敗!");
return FALSE;
}
return TRUE;
二 配置串口
在打開通訊設備句柄後,常需要對串口進行一些初始化配置工作.這需要通過一個
DCB 結構來進行.DCB 結構包含了諸如波特率、數據位數、奇偶校驗和停止位數等信
息.在查詢或配置串口的屬性時,都要用 DCB 結構來作爲緩衝區.
置.要修改串口的配置,應該先修改 DCB 結構,然後再調用 SetCommState 函數設置串
口.
typedef struct _DCB{
DWORD BaudRate;
//CBR_110,CBR_300,CBR_600,CBR_1200,CBR_2400,CBR_4800,CBR_9600,CBR_19200,
//CBR_38400,
//CBR_56000,CBR_57600,CBR_115200,CBR_128000,CBR_256000,CBR_14400
DWORD fParity;// 指定奇偶校驗使能.若此成員爲 1,允許奇偶校驗檢查
BYTE ByteSize;// 通信字節位數,4—8
BYTE Parity;//指定奇偶校驗方法.此成員可以有下列值:
//EVENPARITY 偶校驗 NOPARITY 無校驗
//MARKPARITY 標記校驗 ODDPARITY 奇校驗
BYTE StopBits;// 指定停止位的位數.此成員可以有下列值:
//ONESTOPBIT 1 位停止位 TWOSTOPBITS 2 位停止位
//ONE5STOPBITS 1.5 位停止位
在 winbase.h 文件中定義了以上用到的常量.如下所示:
#define NOPARITY 0
#define ODDPARITY 1
#define EVENPARITY 2
#define ONESTOPBIT 0
#define ONE5STOPBITS 1
#define TWOSTOPBITS 2
#define CBR_110 110
#define CBR_300 300
#define CBR_600 600
#define CBR_1200 1200
#define CBR_2400 2400
#define CBR_4800 4800
#define CBR_9600 9600
#define CBR_14400 14400
#define CBR_19200 19200
#define CBR_38400 38400
#define CBR_56000 56000
#define CBR_57600 57600
#define CBR_115200 115200
#define CBR_128000 128000
#define CBR_256000 256000
GetCommState 函數可以獲得 COM 口的設備控制塊,從而獲得相關參數:
BOOL GetCommState(
SetCommState 函數設置 COM 口的設備控制塊:
BOOL SetCommState(
除了在 BCD 中的設置外,程序一般還需要設置 I/O
緩衝區的大小和超時.
Windows用 I/O 緩衝區來暫存串口輸入和輸出的數據.如果通信的速率較高,則應該設置較大的緩衝區.
調用 SetupComm 函數可以設置串行口的輸入和輸出緩衝區的大小.
BOOL SetupComm(
定的時間內沒有讀入或發送指定數量的字符,ReadFile 或 WriteFile 的操作仍然會
結束.
調用 SetCommTimeouts 可以用某一個 COMMTIMEOUTS 結構的內容來設置超時.
的最大時延.總超時是指讀寫操作總共花費的最大時間.寫操作只支持總超時,而讀
操作兩種超時均支持.用 COMMTIMEOUTS 結構可以規定讀寫操作的超時.
typedef struct _COMMTIMEOUTS {
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
COMMTIMEOUTS 結構的成員都以毫秒爲單位.總超時的計算公式是:
總超時=時間係數×要求讀/寫的字符數+時間常量
例如:要讀入 10 個字符,那麼讀操作的總超時的計算公式爲:
讀總超時=ReadTotalTimeoutMultiplier×10+ReadTotalTimeoutConstant
各種超時.
0,那麼就不使用讀間隔超時.如果 ReadTotalTimeoutMultiplier 和 ReadTotalTimeoutConstant 都爲
0,
則不使用讀總超時.如果讀間隔超時被設置成MAXDWORD 並且讀時間係數和讀時間常量都爲 0,
那麼在讀一次輸入緩衝區的內容後讀操作就立即返回,而不管是否讀入了要求的字符.
回,但超時仍然是起作用的.在這種情況下,超時規定的是操作的完成時間,而不是
ReadFile 和 WriteFile 的返回時間.
配置串口的示例:
SetupComm(hCom,1024,1024);//輸入緩衝區和輸出緩衝區的大小都是 1024
COMMTIMEOUTS TimeOuts;
//設定讀超時
TimeOuts.ReadIntervalTimeout=1000;
TimeOuts.ReadTotalTimeoutMultiplier=500;
TimeOuts.ReadTotalTimeoutConstant=5000;
//設定寫超時
TimeOuts.WriteTotalTimeoutMultiplier=500;
TimeOuts.WriteTotalTimeoutConstant=2000;
SetCommTimeouts(hCom,&TimeOuts);//設置超時
DCB dcb;
GetCommState(hCom,&dcb);
dcb.BaudRate=9600;//波特率爲 9600
dcb.ByteSize=8;//每個字節有 8 位
dcb.Parity=NOPARITY;//無奇偶校驗位
dcb.StopBits=TWOSTOPBITS;//兩個停止位
SetCommState(hCom,&dcb);
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
在讀寫串口之前,還要用 PurgeComm()函數清空緩衝區,該函數原型:
BOOL PurgeComm(
參數 dwFlags 指定要完成的操作,可以是下列值的組合:
PURGE_TXABORT 中斷所有寫操作並立即返回,即使寫操作還沒有完成.
PURGE_RXABORT 中斷所有讀操作並立即返回,即使讀操作還沒有完成.
PURGE_TXCLEAR 清除輸出緩衝區
PURGE_RXCLEAR 清除輸入緩衝區
三 讀寫串口
使用 ReadFile 和 WriteFile 讀寫串口,下面是兩個函數的聲明:
BOOL ReadFile(
BOOL WriteFile(
在用 ReadFile 和 WriteFile 讀寫串口時,既可以同步執行,也可以重疊執行.在同
步執行時,函數直到操作完成後才返回.這意味着同步執行時線程會被阻塞,從而導
致效率下降.在重疊執行時,即使操作還未完成,這兩個函數也會立即返回,費時的
I/O 操作在後臺進行.
CreateFile 創建句柄時指定了 FILE_FLAG_OVERLAPPED 標誌,那麼調用 ReadFile 和
WriteFile 對該句柄進行的操作就應該是重疊的;如果未指定重疊標誌,則讀寫操作
應該是同步的.ReadFile 和 WriteFile 函數的同步或者異步應該和 CreateFile 函數
相一致.
WriteFile 函數不但要把指定數量的字符拷入到輸出緩衝區,而且要等這些字符從
串行口送出去後纔算完成操作.
返回 FALSE時,不一定就是操作失敗,線程應該調用 GetLastError函數分析返回的結
果.例如,在重疊操作時如果操作還未完成函數就返回,那麼函數就返回 FALSE,而且
GetLastError 函數返回 ERROR_IO_PENDING.這說明重疊操作還未完成.
下面是同步方式讀寫串口的示例:
//同步讀串口
char str[100];
DWORD wCount;//讀取的字節數
BOOL bReadStat;
bReadStat=ReadFile(hCom,str,100,&wCount,NULL);
if(!bReadStat)
{
MessageBox("讀串口失敗!");
return FALSE;
}
return TRUE;
//同步寫串口
char lpOutBuffer[100];
DWORD dwBytesWrite=100;
COMSTAT ComStat;
DWORD dwErrorFlags;
BOOL bWriteStat;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL);
if(!bWriteStat)
{
MessageBox("寫串口失敗!");
}
PurgeComm(hCom, PURGE_TXABORT|
PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
在重疊操作時,操作還未完成函數就返回.
重疊 I/O 非常靈活,它也可以實現阻塞(例如我們可以設置一定要讀取到一個數據
才能進行到下一步操作).有兩種方法可以等待操作完成:一種方法是用象
WaitForSingleObject 這樣的等待函數來等待 OVERLAPPED 結構的 hEvent 成員;另一
種方法是調用 GetOverlappedResult 函數等待,後面將演示說明.
下面先簡單介紹一下 OVERLAPPED 結構和 GetOverlappedResult 函數:
OVERLAPPED 結構
OVERLAPPED 結構包含了重疊 I/O 的一些信息,定義如下:
typedef struct _OVERLAPPED {
} OVERLAPPED;
在使用 ReadFile 和 WriteFile重疊操作時,線程需要創建OVERLAPPED 結構以供這
兩個函數使用.線程通過 OVERLAPPED 結構獲得當前的操作狀態,該結構最重要的成
員是 hEvent.hEvent 是讀寫事件.當串口使用異步通訊時,函數返回時操作可能還沒
有完成,程序可以通過檢查該事件得知是否讀寫完畢.
疊操作完成後,該成員變量會自動被置爲有信號狀態.
GetOverlappedResult 函數
BOOL GetOverlappedResult(
該函數返回重疊操作的結果,用來判斷異步操作是否完成,它是通過判斷
OVERLAPPED 結構中的 hEvent 是否被置位來實現的.
異步讀串口的示例:
char lpInBuffer[1024];
DWORD dwBytesRead=1024;
COMSTAT ComStat;
DWORD dwErrorFlags;
OVERLAPPED m_osRead;
memset(&m_osRead,0,sizeof(OVERLAPPED));
m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
ClearCommError(hCom,&dwErrorFlags,&ComStat);
dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
if(!dwBytesRead)
return FALSE;
BOOL bReadStatus;
bReadStatus=ReadFile(hCom,lpInBuffer,dwBytesRead,&dwBytesRead,&m_osRead);
if(!bReadStatus)//如果 ReadFile 函數返回 FALSE
{
if(GetLastError()==ERROR_IO_PENDING) {
//GetLastError() 函數返回ERROR_IO_PENDING,表明串口正在進行讀操作
WaitForSingleObject(m_osRead.hEvent,2000);
PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
return dwBytesRead;
}
return 0;
}
PurgeComm(hCom,PURGE_TXABORT|
return dwBytesRead;
對以上代碼再作簡要說明:在使用 ReadFile 函數進行讀操作前,應先使用
ClearCommError 函數清除錯誤.ClearCommError 函數的原型如下:
BOOL ClearCommError(
該函數獲得通信錯誤並報告串口的當前狀態,同時,該函數清除串口的錯誤標誌以
便繼續輸入、輸出操作.
COMSTAT 結構包含串口的信息,結構定義如下:
typedef struct _COMSTAT{//cst
} COMSTAT, *LPCOMSTAT;
這裏只用到了 cbInQue 成員變量,該成員變量的值代表輸入緩衝區的字節數.
這段代碼用 WaitForSingleObject 函數來等待 OVERLAPPED 結構的 hEvent 成員.
下面是調用 GetOverlappedResult 函數等待的異步讀串口示例:
char lpInBuffer[1024];
DWORD dwBytesRead=1024;
BOOL bReadStatus;
DWORD dwErrorFlags;
COMSTAT ComStat;
OVERLAPPED m_osRead;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
if(!ComStat.cbInQue)
{
return 0;
}
dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
bReadStatus=ReadFile(hCom, lpInBuffer,dwBytesRead,
if(!bReadStatus)//如果 ReadFile 函數返回 FALSE
{
if(GetLastError()==ERROR_IO_PENDING)
{
GetOverlappedResult(hCom,&m_osRead,&dwBytesRead,TRUE);
return dwBytesRead;
}
return 0;
}
return dwBytesRead;
異步寫串口的示例:
char buffer[1024];
DWORD dwBytesWritten=1024;
DWORD dwErrorFlags;
COMSTAT ComStat;
OVERLAPPED m_osWrite;
BOOL bWriteStat;
bWriteStat=WriteFile(hCom,buffer,dwBytesWritten,
if(!bWriteStat)
{
if(GetLastError()==ERROR_IO_PENDING)
{
WaitForSingleObject(m_osWrite.hEvent,1000);
return dwBytesWritten;
}
return 0;
}
return dwBytesWritten;
四 關閉串口
利用 API 函數關閉串口非常簡單,只需使用 CreateFile 函數返回的句柄作爲參數
調用 CloseHandle 即可:
BOOL CloseHandle(
);
爲了更好地理解串口編程,下面分別編寫兩個實例,這兩個實例都實現了工控機與
百特顯示儀表通過 RS485 接口進行的串口通信.其中第一個實例採用同步串口操作,
第二個實例採用異步串口操作.
實例 1
打開 VC++6.0,新建基於對話框的工程 RS485Comm,在主對話框窗口
IDD_RS485COMM_DIALOG 上添加兩個按鈕,ID 分別爲 IDC_SEND 和 IDC_RECEIVE,標題
分別爲”發送”和”接收”;添加一個靜態文本框 IDC_DISP,用於顯示串口接收到
的內容.
①在 RS485CommDlg.cpp 文件中添加全局變量:
HANDLE hCom;//全局變量,串口句柄
②在 RS485CommDlg.cpp 文件中的 OnInitDialog()函數添加如下代碼:
// TODO: Add extra initialization here
hCom=CreateFile("COM1",// 串口名稱
if(hCom==(HANDLE)-1)
{
MessageBox("打開 COM 失敗!");
return FALSE;
}
SetupComm(hCom,100,100);//輸入緩衝區和輸出緩衝區的大小都是 1024
COMMTIMEOUTS TimeOuts;
//設定讀超時
TimeOuts.ReadIntervalTimeout=MAXDWORD;
TimeOuts.ReadTotalTimeoutMultiplier=0;
TimeOuts.ReadTotalTimeoutConstant=0;
//在讀一次輸入緩衝區的內容後讀操作就立即返回,
//而不管是否讀入了要求的字符.
//設定寫超時
TimeOuts.WriteTotalTimeoutMultiplier=100;
TimeOuts.WriteTotalTimeoutConstant=500;
SetCommTimeouts(hCom,&TimeOuts);//設置超時
DCB dcb;
GetCommState(hCom,&dcb);
dcb.BaudRate=9600;//波特率爲 9600
dcb.ByteSize=8;//每個字節有 8 位
dcb.Parity=NOPARITY;//無奇偶校驗位
dcb.StopBits=TWOSTOPBITS;//兩個停止位
SetCommState(hCom,&dcb);
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
③分別雙擊 IDC_SEND 按鈕和 IDC_RECEIVE 按鈕,添加兩個按鈕的響應函數:
void CRS485CommDlg::OnSend()//發送數據
{
//TODO: Add your control notification handler code here
//在此需要簡單介紹百特公司 XMA5000 的通訊協議:
//該儀表 RS485 通訊採用主機廣播方式通訊.
//串行半雙工,幀 11 位,1 個起始位(0),8 個數據位,2 個停止位(1)
//如:讀儀表顯示的瞬時值,主機發送:DC1 AAA BB ETX
//其中:DC1 是標準 ASCII 碼的一個控制符號,碼值爲 11H(十進制的 17)
//在 XMA5000 的通訊協議中,DC1 表示讀瞬時值
//AAA 是從機地址碼,也就是 XMA5000 顯示儀表的通訊地址
//BB 爲通道號,讀瞬時值時該值爲 01
//ETX 也是標準ASCII 碼的一個控制符號,碼值爲 03H
//在 XMA5000 的通訊協議中,ETX 表示主機結束符
char lpOutBuffer[7];
memset(lpOutBuffer,'\0',7);//前 7 個字節先清零
lpOutBuffer[0]= '\x11';// 發送緩衝區的第 1 個字節爲 DC1
lpOutBuffer[1]= '0';//第 2 個字節爲字符 0(30H)
lpOutBuffer[2]='0';//第 3 個字節爲字符 0(30H)
lpOutBuffer[3]='1';// 第 4 個字節爲字符 1(31H)
lpOutBuffer[4]='0';//第 5 個字節爲字符 0(30H)
lpOutBuffer[5]='1';//第 6 個字節爲字符 1(31H)
lpOutBuffer[6]='\x03';//第 7 個字節爲字符 ETX
//從該段代碼可以看出,儀表的通訊地址爲 001
DWORD dwBytesWrite=7;
COMSTAT ComStat;
DWORD dwErrorFlags;
BOOL bWriteStat;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL);
if(!bWriteStat)
{
MessageBox("寫串口失敗!");
}
}
void CRS485CommDlg::OnReceive() //接收數據
{
// TODO: Add your control notification handler code here
char str[100];
memset(str,'\0',100);
DWORD wCount=100;//讀取的字節數
BOOL bReadStat;
bReadStat=ReadFile(hCom,str,wCount,&wCount,NULL);
if(!bReadStat)
{
}
PurgeComm(hCom,PURGE_TXABORT|
m_disp=str;
UpdateData(FALSE);
}
可以觀察返回的字符串,其中有和儀表顯示值相同的部分,可以進行相應的字符串操
作取出儀表的顯示值.
④打開 ClassWizard,爲靜態文本框IDC_DISP 添加 CString 類型變量 m_disp,同時添
加 WM_CLOSE 的相應函數:
void CRS485CommDlg::OnClose()
{
//TODO: Add your message handler code here and/or call default
CloseHandle(hCom);//程序退出時關閉串口
CDialog::OnClose();
}
實例 2
打開 VC++6.0,新建基於對話框的工程 RS485Comm,在主對話框窗口
IDD_RS485COMM_DIALOG 上添加兩個按鈕,ID 分別爲 IDC_SEND 和 IDC_RECEIVE,標題
分別爲”發送”和”接收”;添加一個靜態文本框 IDC_DISP,用於顯示串口接收到
的內容.
①在 RS485CommDlg.cpp 文件中添加全局變量:
HANDLE hCom;//全局變量,串口句柄
②在 RS485CommDlg.cpp 文件中的 OnInitDialog()函數添加如下代碼:
hCom=CreateFile("COM1",// 串口名稱
if(hCom==(HANDLE)-1)
{
MessageBox("打開 COM 失敗!");
return FALSE;
}
SetupComm(hCom,100,100);//輸入緩衝區和輸出緩衝區的大小都是 100
COMMTIMEOUTS TimeOuts;
//設定讀超時
TimeOuts.ReadIntervalTimeout=MAXDWORD;
TimeOuts.ReadTotalTimeoutMultiplier=0;
TimeOuts.ReadTotalTimeoutConstant=0;
//在讀一次輸入緩衝區的內容後讀操作就立即返回,
//而不管是否讀入了要求的字符.
//設定寫超時
TimeOuts.WriteTotalTimeoutMultiplier=100;
TimeOuts.WriteTotalTimeoutConstant=500;
SetCommTimeouts(hCom,&TimeOuts);//設置超時
DCB dcb;
GetCommState(hCom,&dcb);
dcb.BaudRate=9600;//波特率爲 9600
dcb.ByteSize=8;//每個字節有 8 位
dcb.Parity=NOPARITY;//無奇偶校驗位
dcb.StopBits=TWOSTOPBITS;//兩個停止位
SetCommState(hCom,&dcb);
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
③分別雙擊 IDC_SEND 按鈕和 IDC_RECEIVE 按鈕,添加兩個按鈕的響應函數:
void CRS485CommDlg::OnSend()//發送數據
{
// TODO: Add your control notification handler code here
OVERLAPPED m_osWrite;
memset(&m_osWrite,0,sizeof(OVERLAPPED));
m_osWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
char lpOutBuffer[7];
memset(lpOutBuffer,'\0',7);
lpOutBuffer[0]='\x11'';
lpOutBuffer[1]='0';
lpOutBuffer[2]='0';
lpOutBuffer[3]='1';
lpOutBuffer[4]='0';
lpOutBuffer[5]='1';
lpOutBuffer[6]='\x03';
DWORD dwBytesWrite=7;
COMSTAT ComStat;
DWORD dwErrorFlags;
BOOL bWriteStat;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
bWriteStat=WriteFile(hCom,lpOutBuffer,
if(!bWriteStat)
{
if(GetLastError()==ERROR_IO_PENDING)
{
WaitForSingleObject(m_osWrite.hEvent,1000);
}
}
}
void CRS485CommDlg::OnReceive() //接收數據
{
// TODO: Add your control notification handler code here
OVERLAPPED m_osRead;
memset(&m_osRead,0,sizeof(OVERLAPPED));
m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
COMSTAT ComStat;
DWORD dwErrorFlags;
char str[100];
memset(str,'\0',100);
DWORD dwBytesRead=100;//讀取的字節數
BOOL bReadStat;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
bReadStat=ReadFile(hCom,str,
if(!bReadStat)
{
if(GetLastError()==ERROR_IO_PENDING)
//GetLastError() 函數返回ERROR_IO_PENDING,表明串口正在進行讀操作
{
WaitForSingleObject(m_osRead.hEvent,2000);
//使用 WaitForSingleObject 函數等待,直到讀操作完成或延時已達到 2 秒鐘
//當串口讀操作進行完畢後,m_osRead 的 hEvent 事件會變爲有信號
}
}
PurgeComm(hCom,PURGE_TXABORT|
m_disp=str;
UpdateData(FALSE);
}
④打開 ClassWizard,爲靜態文本框IDC_DISP 添加 CString 類型變量 m_disp,同時添
加 WM_CLOSE 的相應函數:
void CRS485CommDlg::OnClose()
{
//TODO: Add your message handler code here and/or call default
CDialog::OnClose();
}