1.打开VS2019,点击“创建新项目”
2.在模版搜索栏中输入MFC,如果你的VS2019装有C++ MFC组件,会显示下图界面,点击MFC应用,再点击下一步。
3.输入项目名称及存储路径,点击创建
4.在应用程序类型中选择基于对话框,点击完成
初始界面如下:
5.点击“工具”菜单,再点击“选择工具箱项”
6.在弹出对话框中,点击“com组件”,然后在下面列表中选择“Microsoft Communications Control…”,然后点击“确定”
7.将工具箱里的“Microsoft Communications Control…”拖到设计的对话框里,如下:
c:\\Windows\\SysWOW64\\comctl32.ocx 再点确定,注册。注意我的系统是Win7 64位。
10.在弹出对话框中,点击MFC,选中右边列表框中的ActiveX控件中的MFC类,点击添加
11.在弹出对话框中,可用类型库栏,选中Microsoft Comm Control 6.0….选中右下列表框中的IMSComm,在点击》,点击确定。
12.打开项目资源管理器,可看到,已添加了与串口通信有关的文件。
13.按Ctrl+F5试运行一下,看是否存在错误,结果如下,没有错误。
14.对话框界面设计,由于是演示程序,界面设计得比较简单。
15.位串口设置中的五个CComboBox及发送接收区的编辑框添加关联变量,编辑框还额外关联CString变量分别为:strEditRevc,strEditInput。
16.在DemoCSCommDlg的头文件中包含CMSComm.h并在头文件中定义CMSComm变量
mctr_SComm
17. 将mctr_SComm关联到对话框中的Microsoft Communications Control控件
18.串口设置中的CComboBox控件初始化,为实现CComboBox的初始化数据按输入顺序排列,需将CComboBox控件属性表中的排序设为False,为便于查看初始化数据加入,在CDemoCSCommDlg::OnInitDialog()中进行。
//初始化端口CComboBox控件
mctr_Combobox_Port.AddString(_T("COM1"));
mctr_Combobox_Port.AddString(_T("COM2"));
mctr_Combobox_Port.AddString(_T("COM3"));
mctr_Combobox_Port.AddString(_T("COM4"));
mctr_Combobox_Port.AddString(_T("COM5"));
mctr_Combobox_Port.AddString(_T("COM6"));
mctr_Combobox_Port.AddString(_T("COM7"));
mctr_Combobox_Port.AddString(_T("COM8"));
mctr_Combobox_Port.AddString(_T("COM9"));
mctr_Combobox_Port.AddString(_T("COM10"));
mctr_Combobox_Port.SetCurSel(0);
//初始化波特率CComboBox控件
mctr_Combobox_Baudrate.AddString(_T("1200"));
mctr_Combobox_Baudrate.AddString(_T("2400"));
mctr_Combobox_Baudrate.AddString(_T("4800"));
mctr_Combobox_Baudrate.AddString(_T("9600"));
mctr_Combobox_Baudrate.AddString(_T("12800"));
mctr_Combobox_Baudrate.AddString(_T("14400"));
mctr_Combobox_Baudrate.AddString(_T("19200"));
mctr_Combobox_Baudrate.AddString(_T("25600"));
mctr_Combobox_Baudrate.AddString(_T("28800"));
mctr_Combobox_Baudrate.AddString(_T("38400"));
mctr_Combobox_Baudrate.AddString(_T("56000"));
mctr_Combobox_Baudrate.SetCurSel(3);
//初始化校验位CComboBox控件
mctr_Combobox_Parity.AddString(_T("E"));
mctr_Combobox_Parity.AddString(_T("M"));
mctr_Combobox_Parity.AddString(_T("N"));
mctr_Combobox_Parity.AddString(_T("O"));
mctr_Combobox_Parity.AddString(_T("S"));
mctr_Combobox_Parity.SetCurSel(2);
//初始化数据位CComboBox控件
mctr_Combobox_Data.AddString(_T("4"));
mctr_Combobox_Data.AddString(_T("5"));
mctr_Combobox_Data.AddString(_T("6"));
mctr_Combobox_Data.AddString(_T("7"));
mctr_Combobox_Data.AddString(_T("8"));
mctr_Combobox_Data.SetCurSel(4);
//初始化停止位CComboBox控件
mctr_Combobox_StopBit.AddString(_T("1"));
mctr_Combobox_StopBit.AddString(_T("1.5"));
mctr_Combobox_StopBit.AddString(_T("2"));
mctr_Combobox_StopBit.SetCurSel(0);
20.在串口未打开时,关闭串口按钮应该是不可操作,因此也需要,在初始化中设置。
//初始化关闭串口按钮
CButton* pButton;
pButton = (CButton*)GetDlgItem(IDC_BUTTON_CLOSE_COMM);
pButton->EnableWindow(0);
21.在"DemoCSCommDlg.h"中定义两个BOOL变量bOpen,bRecv用以标记串口打开状态及是否接收数据。并在构造函数中初始化这两个变量,在 CDemoCSCommDlg::OnPaint()中添加码
// CSComm open/close flag
bool bOpen;
// SComm receive data enable/disable flag
bool bRecv;
//变量初始化:
CDemoCSCommDlg::CDemoCSCommDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_DEMOCSCOMM_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
bOpen = 0;
bRecv = 1;
}
//在CDemoCSCommDlg::OnPaint()中添加以下代码:
{
CButton* pButton;
if (bOpen)
{
pButton = (CButton*)GetDlgItem(IDC_BUTTON_OPEN_COMM);
pButton->EnableWindow(0);
pButton = (CButton*)GetDlgItem(IDC_BUTTON_CLOSE_COMM);
pButton->EnableWindow(1);
pButton = (CButton*)GetDlgItem(IDC_BUTTON_OPEN_SEND);
pButton->EnableWindow(1);
}
else
{
pButton = (CButton*)GetDlgItem(IDC_BUTTON_OPEN_COMM);
pButton->EnableWindow(1);
pButton = (CButton*)GetDlgItem(IDC_BUTTON_CLOSE_COMM);
pButton->EnableWindow(0);
pButton = (CButton*)GetDlgItem(IDC_BUTTON_OPEN_SEND);
pButton->EnableWindow(0);
}
if (bRecv)
{
pButton = (CButton*)GetDlgItem(IDC_BUTTON_STOP_RECV);
pButton->SetWindowTextW(_T("停止接收"));
}
else
{
pButton = (CButton*)GetDlgItem(IDC_BUTTON_STOP_RECV);
pButton->SetWindowTextW(_T("接收数据"));
}
22.在"DemoCSCommDlg.h"中定义串口初始化函数
23. 在“DemoCSCommDlg.cpp”中实现,源码如下:
void CDemoCSCommDlg::InitScomm(short mscommPort, CString mSetsettings)
{
// TODO: 在此处添加实现代码.
mctr_SComm.put_CommPort(mscommPort);//选择nCom口
mctr_SComm.put_InputMode(1);//以文本方式获取输入数据
mctr_SComm.put_InBufferSize(1024);//输入缓冲区大小为1024byte
mctr_SComm.put_OutBufferSize(1024);//输出缓冲区大小为1024byte
mctr_SComm.put_Settings(mSetsettings);//设置串口参数
}
24.鼠标移动到CSComm控件上按右键,为其添加事件处理程序
在此函数中添加如下代码,实现数据接收。
void CDemoCSCommDlg::OnCommMscomm1()
{
VARIANT variant_inp;
COleSafeArray safearray_inp;
CString strtemp;
CByteArray byteArr;
short nEvent = mctr_SComm.get_CommEvent();
if (nEvent == 2 && bRecv == TRUE)
{
variant_inp = mctr_SComm.get_Input();//读缓input冲区
safearray_inp = variant_inp;//variant数据转换成colesafearray型变量
safearray_inp.GetByteArray(byteArr);
byteArr.FreeExtra();
int len = byteArr.GetSize();
for (int i = 0; i < len; i++)
{
BYTE bt = byteArr[i];
strtemp.Format(L"%c", bt);
strEditRevc += strtemp;
}
mctr_Edit_Revc.SetWindowTextW(strEditRevc);
}
}
25. 对话框上的所有按钮添加事件处理程序及实现代码:
afx_msg void OnBnClickedButtonOpenComm();
afx_msg void OnBnClickedButtonSend();
afx_msg void OnBnClickedButtonCloseComm();
afx_msg void OnBnClickedButtonClear();
afx_msg void OnBnClickedButtonStopRecv();
//打开串口
void CDemoCSCommDlg::OnBnClickedButtonOpenComm()
{
// TODO: 在此添加控件通知处理程序代码
short sPort = mctr_Combobox_Port.GetCurSel() + 1;
CString str, str1;
str.Empty();
mctr_Combobox_Baudrate.GetLBText(mctr_Combobox_Baudrate.GetCurSel(), str1);
str += str1;
mctr_Combobox_Parity.GetLBText(mctr_Combobox_Parity.GetCurSel(), str1);
str += str1;
mctr_Combobox_Data.GetLBText(mctr_Combobox_Data.GetCurSel(), str1);
str += str1;
mctr_Combobox_StopBit.GetLBText(mctr_Combobox_StopBit.GetCurSel(), str1);
str += str1;
str = "9600,n,8,1";
InitScomm(sPort, str);
if (!mctr_SComm.get_PortOpen())
try
{
mctr_SComm.put_PortOpen(1);//打开串口
}
catch (CException* e)
{
MessageBox(_T("打开串口失败"));
e->ReportError();
e->Delete();
}
if (mctr_SComm.get_PortOpen())
{
MessageBox(L"打开串口成功");
mctr_SComm.put_RThreshold(1);//每当串口接收缓冲区有多余或等于1个字符时将引发一个接收数据的oncomm事件
mctr_SComm.put_InputLen(0);//设置当前接收区数据长度为0,即一次读取全部数据
mctr_SComm.get_Input();//预读缓冲区以清空残留数据
//读写超时设置
volatile HANDLE m_hCom;
COMMTIMEOUTS m_TimeOuts;
m_hCom = (HANDLE)mctr_SComm.get_CommPort();
m_TimeOuts.ReadIntervalTimeout = MAXDWORD;
m_TimeOuts.ReadTotalTimeoutMultiplier = 0;
m_TimeOuts.ReadTotalTimeoutConstant = 0;
m_TimeOuts.WriteTotalTimeoutMultiplier = 50;
m_TimeOuts.WriteTotalTimeoutConstant = 2000;
SetCommTimeouts(m_hCom, &m_TimeOuts);
//对话框界面更新
bOpen = 1;
CButton* pButton;
pButton = (CButton*)GetDlgItem(IDC_BUTTON_OPEN_COMM);
pButton->EnableWindow(0);
pButton = (CButton*)GetDlgItem(IDC_BUTTON_SEND);
pButton->EnableWindow(1);
pButton = (CButton*)GetDlgItem(IDC_BUTTON_CLOSE_COMM);
pButton->EnableWindow(1);
}
else
{
MessageBox(L"打开串口失败");
}
}
//发送数据
void CDemoCSCommDlg::OnBnClickedButtonSend()
{
// TODO: 在此添加控件通知处理程序代码
CString strSendData;
COleVariant coleData;
UpdateData();
mctr_Edit_Input.GetWindowText(strSendData);
coleData = (COleVariant)strSendData;
mctr_SComm.put_Output((VARIANT)coleData);
}
//关闭串口
void CDemoCSCommDlg::OnBnClickedButtonCloseComm()
{
mctr_SComm.put_PortOpen(0);
bOpen = 0;
CButton* pButton;
pButton = (CButton*)GetDlgItem(IDC_BUTTON_OPEN_COMM);
pButton->EnableWindow(1);
pButton = (CButton*)GetDlgItem(IDC_BUTTON_SEND);
pButton->EnableWindow(0);
pButton = (CButton*)GetDlgItem(IDC_BUTTON_CLOSE_COMM);
pButton->EnableWindow(0);
}
//清空接收区
void CDemoCSCommDlg::OnBnClickedButtonClear()
{
strEditRevc.Empty();
mctr_Edit_Revc.SetWindowTextW(strEditRevc);
}
//接收数据/停止接收
void CDemoCSCommDlg::OnBnClickedButtonStopRecv()
{
CButton* pButton;
pButton = (CButton*)GetDlgItem(IDC_BUTTON_STOP_RECV);
if (bRecv)
{
bRecv = FALSE;
pButton->SetWindowTextW(L"接收数据");
}
else
{
bRecv =TRUE;
pButton->SetWindowTextW(L"停止接收");
}
}
25.实测,由于电脑没有9Pin串口,先用CH340(USB转串口)模块,将TxD与RxD用跳帽短接,进行发送与接收测试。