串口通訊將資料位元組分解為單一位元流循序傳輸,結構簡單、連接線少、應用極廣。本文採用 Microsoft Communications Control (MSComm) ActiveX 控件實作,利用 Windows ActiveX 技術簡化串口程式設計,僅需少量代碼即可高效完成任務。適用於 Visual Studio 2010/2012/2013 及 VC++ 6.0。
| 屬性 | 說明 |
|---|---|
CommPort | 設定/取得通訊埠號 |
Settings | 以字串設定鮑率、奇偶校驗、資料位、停止位(如 "9600,n,8,1") |
PortOpen | 設定/取得埠開啟狀態 |
Input | 從接收緩衝區讀取並移除字元 |
Output | 向發送緩衝區寫入字串 |
InputLen | 每次讀取字元數,0 表示讀取全部 |
InBufferCount | 接收緩衝區已接收字元數,歸零可清除緩衝區 |
InputMode | 0=文字模式,1=二進位模式 |
RThreshold/SThreshold | 觸發 OnComm 事件的接收/發送緩衝區字元閾值 |
VC++ 6.0:專案 → 加入至專案 → 元件與控制項 → 已註冊的 ActiveX 控制項 → 選擇 Microsoft Communications Control 6.0 → 插入。將控件加入對話方塊,設定 ID 為 IDC_MSCOMM。
VS2010/2012/2013:操作類似,透過工具箱或專案屬性加入 COM 元件。
IDC_COMBO_SELECT、設定鮑率 IDC_COMBO_BTLSET)IDC_BUTTON_STARTIDC_EDIT_SEND、IDC_EDIT_RECEIVE
| 控件 ID | 變數名稱 | 變數型別 |
|---|---|---|
IDC_EDIT_RECEIVE | m_strReceive | CString |
IDC_EDIT_SEND | m_strSend | CString |
IDC_MSCOMM | m_MSComm | CMSComm |
IDC_COMBO_SELECT | m_nPort | int |

void CMyDlg::OnButtonOpen() {
if (m_MSComm.GetPortOpen()) {
AfxMessageBox(_T("請先關閉串口!"));
return;
}
UpdateData(TRUE);
if (m_nPort == -1) {
AfxMessageBox(_T("請選擇串口!"));
return;
}
m_MSComm.SetCommPort(m_nPort);
m_MSComm.SetInBufferSize(1024);
m_MSComm.SetOutBufferSize(1024);
m_MSComm.SetInputLen(0);
m_MSComm.SetInputMode(1); // 二進位模式
m_MSComm.SetRThreshold(1); // 收到 1 字元觸發事件
m_MSComm.SetPortOpen(TRUE);
if (m_MSComm.GetPortOpen()) {
GetDlgItem(IDC_BUTTON_OPEN)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(TRUE);
} else {
CString strInfo;
strInfo.Format(_T("打開串口 COM%d 失敗!"), m_nPort);
AfxMessageBox(strInfo);
}
}
void CMyDlg::OnButtonSend() {
if (!m_MSComm.GetPortOpen()) {
AfxMessageBox(_T("請先打開串口!"));
return;
}
UpdateData(TRUE);
int nSendLength = m_strSend.GetLength();
CByteArray byteArray;
byteArray.RemoveAll();
byteArray.SetSize(nSendLength);
for (int i = 0; i < nSendLength; i++) {
byteArray.SetAt(i, (BYTE)m_strSend.GetAt(i));
}
m_MSComm.SetOutput(COleVariant(byteArray));
}
void CMyDlg::OnButtonClose() {
if (!m_MSComm.GetPortOpen()) {
AfxMessageBox(_T("請先打開串口!"));
return;
}
m_MSComm.SetPortOpen(FALSE);
GetDlgItem(IDC_BUTTON_OPEN)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(FALSE);
}
void CMyDlg::OnSelchangeBps() {
UpdateData(TRUE);
int nIndex = m_bps.GetCurSel();
switch (nIndex) {
case 0: m_MSComm.SetSettings(_T("19200,n,8,1")); break;
case 1: m_MSComm.SetSettings(_T("14400,n,8,1")); break;
case 2: m_MSComm.SetSettings(_T("9600,n,8,1")); break;
case 3: m_MSComm.SetSettings(_T("4800,n,8,1")); break;
}
UpdateData(FALSE);
}
void CMyDlg::OnOnCommMscomm() {
if (m_MSComm.GetCommEvent() == 2) { // 接收緩衝區有字元
VARIANT variantInput = m_MSComm.GetInput();
COleSafeArray safeArray(variantInput);
long length = safeArray.GetOneDimSize();
BYTE* pData = new BYTE[length];
safeArray.AccessData((void**)&pData);
CString strTmp;
for (long i = 0; i < length; i++) {
BYTE bt = pData[i];
if (m_bDisplayAsChar) // 假設有單選鈕控制顯示模式
strTmp.Format(_T("%c"), bt);
else
strTmp.Format(_T("%02X "), bt);
m_strReceive += strTmp;
}
safeArray.UnaccessData();
delete[] pData;
UpdateData(FALSE);
}
}
編譯生成 EXE,連接串口線後執行:


