||
下面分享制作一款能够同时通过串口控制下位机以及能够显示参数曲线的上位机,首先来看串口通信
MFC的串口编程一般有两种方法,一个是使用ActiveX控件,例如mscomm串口控件,还有一个是用SerialPort类或者一些其他的串口类,这两个的区别是使用SerialPort类不需要注册控件,在其他没有安装控件的电脑上也能够用。但是这个有个致命的缺点那就是在发送数据的时候不能同时接收数据,在发送数据的时候不能同时接收数据,所以对于需要频繁接收发发送的项目不适合采用SerialPort类编写。Mscomm串口还有一个优点那就是可以设定接收到多少个字符进响应函数,但mscomm也有个致命缺点,那就是设定多少字节进响应函数,并不会一定就刚好接收到这多么数据就进入消息中,一定会是大于等于。这个特点对串口示波器的编程并不利。Mscomm还有一个缺点那就是发送数据的时候只要数据中有停止位(0),那么后面的数据就不会传输了,而SerialPort类可以设定传输多少字节数据,不过Mscomm这个缺点通过格式转换还是可以解决的,就是麻烦点。下面对这两种方法都进行讲解。
采用VC6.0编写,如图新建MFC程序,工程名字为lb,选择基本对话框,然后点击完成。
在打开的对话框上拖入上述控件,然后修改控件标题,将列表框控件ID改为IDC_COMBO,添加成员变量如下图所示,两个编辑框成员变量分别改为m_strSendData,m_strEditReceiveMsg,打开串口按钮ID改为IDC_Open,最后如下图所示:
1·先用SerialPort类制作串口软件。拷贝类文件serialport.h和serialport.cpp复制到工程所在的文件夹下,然后点击VC6.0菜单Project->Add to Project->Files…,选择serialport.h和serialport.cpp点击OK,就把类文件加入了当前工程。注意如果是用win7则需要安装一个FileTool插件,这个是专门用来为VC6添加与打开文件的。
2·在FileView中打开lbDlg.h,将头文件说明,即加入#include
"SerialPort.h",这样就加入了CSerialPort类。通过CSerialPort类完成串口操作。
3·在主对话框头文件“lbDlg.h”public中定义CserialPort类对象:
CSerialPort
m_SerialPort; //CSerailPort类对象
BOOL m_bSerialPortOpened; //标志串口是否打开
4·添加消息响应(添加3处地方)
4.1在lbDlg.h中添加串口字符接收消息
afx_msg
LONG OnComm(WPARAM ch,LPARAM port); //只需添加这一行
如下图所示:
4.2 在lbDlg.cpp文件中进行WM_COMM_RXCHAR消息映射:
ON_MESSAGE(WM_COMM_RXCHAR, OnComm) //只需添加这一行
如下图所示:
4.3添加接收数据的消息处理函数,在lbDlg.cpp中完整的添加如下函数(注:不是命名为lb的请自己修改类):
LONG CLbDlg::OnComm(WPARAM ch, LPARAM port)
{
m_strEditReceiveMsg
+= ch;
UpdateData(FALSE); //将接收到的字符显示在接收编辑框中
return
0;
}如下图所示:
为扫描端口按钮添加单击响应函数,双击扫描端口按钮弹出如下:
添加函数如下:
if(!ScanPort())
{
MessageBox(_T("未找到可用端口"),_T("提示"));
}
如下图所示:
在类视图右击CLBDlg添加成员函数int类型函数ScanPort,如下图所示:
添加如下函数:
//程序启动时获取全部可用串口
HANDLE
hCom;
int i,num,k;
CString str;
BOOL flag;
((CComboBox
*)GetDlgItem(IDC_COMBO))->ResetContent();//消除现有所有内容
flag = FALSE;
num = 0;
for (i = 1;i <= 16;i++)
{//此程序支持16个串口
str.Format("\\\\.\\COM%d",i);
hCom = CreateFile(str, 0, 0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
if(INVALID_HANDLE_VALUE !=
hCom )
{//能打开该串口,则添加该串口
CloseHandle(hCom);//关闭线程
str = str.Mid(4);//取字符串的第五个字符
((CComboBox
*)GetDlgItem(IDC_COMBO))->AddString(str);
if (flag == FALSE)
{
flag =
TRUE;
num = i;
}
}
}
i = ((CComboBox
*)GetDlgItem(IDC_COMBO))->GetCount();//取得目前已经有的行数
if (i == 0)
{//若找不到可用串口则禁用“打开串口”功能
// ((CComboBox
*)GetDlgItem(IDC_COMBO))->EnableWindow(FALSE);//设置为不可用
((CButton *)GetDlgItem(IDC_Open))->EnableWindow(FALSE);
return 0;
}
else
{
k = ((CComboBox
*)GetDlgItem((IDC_COMBO)))->GetCount();//取得目前已经有的行数
((CComboBox
*)GetDlgItem(IDC_COMBO))->SetCurSel(k - 1);//选中当前行
((CButton
*)GetDlgItem(IDC_Open))->EnableWindow(TRUE);
return 1;
}
如下图所示(注:图只是截取了一部分):
为“打开串口”按钮添加函数OnOpen如下:
CString txt,error,data;
int i;
GetDlgItem(IDC_Open)->GetWindowText(txt);
i = ((CComboBox
*)GetDlgItem(IDC_COMBO))->GetCurSel();
((CComboBox
*)GetDlgItem(IDC_COMBO))->GetLBText(i,data);
if (txt == "打开串口")
{
data = data.Mid(3);
i = atoi(data);
if(m_SerialPort.InitPort(this,i,115200,'N',8,1,EV_RXFLAG|EV_RXCHAR,512))
{
m_SerialPort.StartMonitoring();
m_bSerialPortOpened=TRUE;
//
AfxMessageBox("打开串口");
}
GetDlgItem(IDC_Open)->SetWindowText("关闭串口");
((CComboBox
*)GetDlgItem(IDC_COMBO))->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);//不可用
}
else
{
m_SerialPort.ClosePort();
m_bSerialPortOpened=FALSE;
GetDlgItem(IDC_Open)->SetWindowText("打开串口");
((CComboBox
*)GetDlgItem(IDC_COMBO))->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);//可用
}
如下图所示(注:图只是截取了一部分):
为发送按钮添加响应函数OnBnSend如下:
if(!m_bSerialPortOpened) return;
UpdateData(TRUE);
m_SerialPort.WriteToPort((LPSTR)(LPCTSTR)m_strSendData);
如下图所示:
好啦,现在可以编译运行了,可以试着打开两个软件,用VSPD 6.9建两个端口。扫描端口点击打开串口后,在编辑框中输入东西,在另个软件中就能看到了,这里没有对数据的接收做处理,不能过多的接收数据。注:此程序默认的波特率为115200如果要更改可以在打开串口程序中更改。详细程序见“SerialPort串口”程序源代码下载地址:https://download.eeworld.com.cn/detail/lb8820265/556641