如何使用VC++6.0 MFC制作串口上位机

VC6MFC的串口控件怎么用?编辑框显示串口信息是乱码怎么办?下拉列表没有内容怎么办?

记录上vc6位机制作过程和需要注意的问题

一、为什么使用VC6

VC6虽然是比较老的编程软件,但是他的性能很好,功能齐全,操作简单,可以完成windows系统下很多的功能,比如串口通信,网络通信等等。现在的VS虽然比VC6性能好得多,但是低配电脑基本上很卡,不建议低配电脑使用,我就是。

二、VC6的安装

这里有一个微信上的安装教程

三、MFC的工程建立和编译

1、工程建立

  • 点击文件,新建,输入工程名(注意不可以使用中文),点击MFC AppWizard[exe]后确定。

    建立基本对话框

    之后会提示你工程的相关信息,确认即可。

2、编译

编译运行和常规的方式一样。

如果我们想让电脑里没有安装VC6的人运行我们制作的MFC程序的话,我们需要在工程设置 中,将使用MFC作为共享的DLL改为使用MFC作为静态链接库,这样我们就可以让其他电脑运行MFC的窗口程序,这就是在可执行文件中加入了MFC的运行库。

但根据情况而定,这样会让你的exe增到10MB左右。

打开工程

我们要注意的是打开工程一定要点击 打开工作空间 ,因为点击打开会出现闪退现象!原因未知…

四、窗口控件的使用

1、窗口控件的插入


在工作区的右侧我们可以看到这样的一个工具栏,我妈可以添加需要的空间到窗口上,同样窗口上的多余内容我们可以删掉。

2、具体的控件使用方法

如果你找不到你的窗口界面了,那么请打开左侧栏的ResourceView中的Dialog

按钮

按钮的名称在其右键属性中更改,标题即为显示的名称。

双击按钮,出现对话框,这里是让用户设定按钮时间函数的名称,可以默认为其ID,也可以自行设置为 “On…” 的格式。

命名后自动跳转到了按钮事件函数,如

1
2
3
4
5
void CHostcomputerDlg::OnButton2() 
{
// TODO: Add your control notification handler code here

}

如果窗口上按钮很多,命名无法找到相应函数时可以双击窗口按钮来编辑程序。

按钮事件函数我们可以理解成单片机中的中断函数,程序执行过程中只要按下按钮就会执行这个函数。

静态文本和组框

这两个就很简单了,直接放置到窗口上,右键属性,在标题中修改要显示的内容。

编辑框

编辑框可以作为显示窗口使用,也可作为输入框。

  • 如果横向文字很多,那么可选择水平滚动,以方便查看横向,如果编辑框宽度够用那么就不用改横向的属性。
  • 作为上位机我们显示数据可以是一行一行的显示,这时候就要使用垂直和自动垂直滚动,这样更新的数据就会逐行在这里显示。
  • 我们可以使用类的方式也可以不使用,这里列举输入不用类,输出使用类的方式。
编辑框作为输入

这里我们就要引入一种类 CString,它不是一种数据类型也不是C++中的标准库,在MFC中普遍使用,可以说是非常的方便。

1
2
CString str;
GetDlgItem(IDC_EDIT1)->GetWindowText(str);

这里的IDC_EDIT1是编辑框的ID,此时编辑框中的内容已经存到了str中。

编辑框作为显示
1
2
3
4
m_edit1.SetSel(-1);//使用一次就行,代表可以使用\r\n分行
m_edit1.ReplaceSel("abcdefg");//显示字符串
m_edit1.ReplaceSel(out);//显示变量(char或CString)
m_edit1.ReplaceSel("\r\n");//换行

这里的m_edit1并不是ID,而是类。那么如何建立类向导呢?

  • 窗体任意位置右键
  • 建立类向导
  • Member Variables
  • 点击Add Variable…为IDC_EDIT1这个编辑框建立一个类。
  • 这里类的名称要写成 “m_…” 的形式。更重要的是Category一定要选择Control!!!
  • 点击OK完成。

复选框和单选框

在串口调试助手中我们经常会用定时发送等功能,那么复选框就可以提供选择是否要进行某一操作的功能。

1
2
3
4
if(((CButton*)GetDlgItem(IDC_CHECK1))->GetCheck()==TRUE)
//勾选
else
//未勾选

这里判断的TRUE是复选框勾选的状态。

单选框不建议使用,因为单选框选中后不可取消

组合框

非常实用的一个窗口控件,我们在制作上位机时,会提供给用户可选的串口号等等。

组合框添加内容

我们想要在程序运行开始后让组合框中出现下拉列表,就要在MFC初始化时将组合框的初始化添加进去。

第一步还是要建类,我们命名为m_cbCom
之后我们在程序中找到BOOL CHostcomputerDlg::OnInitDialog()这个函数,在程序开头附近,这是MFC控件初始化的函数。

在此函数末尾// TODO: Add extra initialization here下,return TRUE;前,添加初始化代码。

1
2
3
4
5
6
7
8
9
10
11
m_cbCom.InsertString(0,"-请选择-");
m_cbCom.InsertString(1,"COM 1");
m_cbCom.InsertString(2,"COM 2");
m_cbCom.InsertString(3,"COM 3");
m_cbCom.InsertString(4,"COM 4");
m_cbCom.InsertString(5,"COM 5");
m_cbCom.InsertString(6,"COM 6");
m_cbCom.InsertString(7,"COM 7");
m_cbCom.InsertString(8,"COM 8");
m_cbCom.InsertString(9,"COM 9");
m_cbCom.InsertString(10,"COM 10");

这里的序号要从0开始,双引号中是显示的内容。

获取用户选择的序号
1
2
int com;
com=m_cbCom.GetCurSel();

这里获取的是用户选择的项的序号。

组合框没有下拉菜单的问题

鼠标放在组合框下拉箭头上,可以看到鼠标编程了上下指向的箭头,单击,则可以将组合框下拉菜单的高度改变。这是初学者经常遭遇的一个难题。再次点击切换回横向拉伸组合框。

滑块

想要实时显示滑块值,个人使用的是定时器每隔100ms获取一次滑块位置并在其后加一个编辑框,显示数值的方法。

滑块初始化

滑块的使用也需要建立类。
和上面的其他控件一样,我们在初始化函数下加入代码。

1
2
m_timslider.SetRange(10,1000);
m_timslider.SetTicFreq(10);

这里的SetRange代表的是滑块的范围是10-1000,最小为10,最大为1000,SetTicFreq代表滑块移动的最小单位为10。

滑块值获取
1
2
int slider;
slider=m_timslider.GetPos();

定时器

添加定时器函数

定时器控件不同于窗口中的其他控件,我们需要在类向导中添加。

点击Add FunctionEdit Code,即可修改添加到程序中的定时器函数。如:

1
2
3
4
5
6
void CHostcomputerDlg::OnTimer(UINT nIDEvent) 
{
// TODO: Add your message handler code here and/or call default

CDialog::OnTimer(nIDEvent);
}
定时器初始化

同样在初始化函数中,添加

1
SetTimer(1,50,NULL);

这里定义了定时器1,50ms中断一次。和芯片不同,我们的电脑可以模拟出很多个定时器,你可以定义2,3,4….

定时器关闭

例如关闭定时器1:

1
KillTimer(1);
定时器中断

这里列举两个定时器的中断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void CSwjDlg::OnTimer(UINT nIDEvent) 
{
// TODO: Add your message handler code here and/or call default
switch(nIDEvent)
{
case 1://定时器1中断
m_edit1.ReplaceSel("abcdefg");
m_edit1.ReplaceSel("\r\n");//换行
break;

case 2://定时器2中断
com=m_cbCom.GetCurSel();//获取滑块位置
break;
}
CDialog::OnTimer(nIDEvent);
}

进度条


建立m_Progress类

1
2
3
4
5
m_Progress.SetRange(0,100);//设置进度条的数值范围
m_Progress.SetStep(10);//设置单步长度如10
m_Progress.StepIt();//走一步
m_Progress.SetPos(50);//设置进度条在自定义的位置如50
n=m_Progress.GetPos();//获取当前位置

串口控件

添加串口控件

窗体右键 插入ActiveX控件

在窗口上会出现一个小电话图标,这就是串口控件。这个图片在运行程序时是看不到的。
之后建立m_ctrlComm类。

串口的打开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
m_ctrlComm.SetCommPort(com);//com为串口号
if (m_ctrlComm.GetPortOpen())//如果串口已经打开
{
m_ctrlComm.SetPortOpen(FALSE);//不再重复打开
}
if(!m_ctrlComm.GetPortOpen())//串口没有打开
{
m_ctrlComm.SetPortOpen(TRUE);//打开串口
SetDlgItemText(IDC_EDIT1,"串口已打开");
}
m_ctrlComm.SetInputMode(1);
m_ctrlComm.SetSettings("4800,n,8,1");//波特率
m_ctrlComm.SetRThreshold(1);
m_ctrlComm.SetInputLen(0);
m_ctrlComm.GetInput();
串口发送

Format函数我们要经常使用在串口发送数据的处理上。
格式:

[CString].Format(“%s或%c或%d”,[char]或[int])

普通字符串

个人建议使用CString发送,因为这样非常稳定。

1
2
3
4
5
CString send;
char a[]={"abcd"}
send.Format("%s",a);
m_ctrlComm.SetOutput(COleVariant("abcd"));//字符串
m_ctrlComm.SetOutput(COleVariant(send));//发送变量
发送整型数
1
2
3
4
CString send;
int a=123;
send.Format("%d",a);
m_ctrlComm.SetOutput(COleVariant(send));//发送变量
串口接收

双击小电话,可以进入串口函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int data[]={0};

void CSTM32_HIDDlg::OnOnCommMscomm()
{
// TODO: Add your control notification handler code here
VARIANT vReceive;
int len;
byte sBuf;
char rec[5];//根据接收数据长度定义既可
if(m_ctrlComm.GetCommEvent()==2)
{

len=m_ctrlComm.GetInBufferCount();
m_ctrlComm.SetInputLen(len);
vReceive=m_ctrlComm.GetInput();
byte* buf=new byte[len];
memcpy(buf,(byte*)vReceive.parray->pvData,len);
for(int i=0;i<len;i++)
{
sBuf=*(buf+i);
data[i]=sBuf;
rec[i]=sBuf;
}
delete buf;
}
}

这里的rec是储存接收信息的变量。
注意:下位机一定要发送十六进制数据,普通的字符串会出现乱码。
例:可在串口函数中判断rec第一位数据

1
2
if(rec[0]==0x01)
m_edit.ReplaceSel("接收到0x01\r\n");

MFC其他技巧

1.弹出另一个窗口和关闭

点击插入,窗体,名称可以自定义,点击确定。

在主窗体添加新窗体的头文件,可以去新窗体程序中查看,其头文件为名称.h

加入新窗体名称为help,可以在主窗体的按钮中添加:

1
2
3
help dlg;   // 对话框类对象

dlg.DoModal();

关闭新窗体可以在新窗体中操作:

1
EndDialog(0);

即可关闭所在窗体。

2.定时关闭新窗体

添加定时器控件,之后在新窗体的
void open::DoDataExchange(CDataExchange* pDX)
函数尾部添加定时器初始化。
在定时器中断中添加关闭指令。

3.播放音乐

一般播放wav格式的音乐,我们可以音频转码成wav再播放

本地文件中的音乐
1
2
3
4
#include "windows.h"
#include "mmsystem.h" //头文件

PlaySound(完整路径和后缀, AfxGetInstanceHandle(), SND_RESOURCE | SND_ASYNC);
编译到程序资源的音乐

这种方式可以让音乐代码加入到程序中,无需外部文件。
插入,资源,引入,选择文件类型为wav波形文件,选择相应文件即可将wav加入到资源中。
左侧资源窗中可以看到wav的名称为IDR_WAVE1或其他名称。

1
2
3
4
#include "windows.h"
#include "mmsystem.h" //头文件

PlaySound((LPCTSTR)IDR_WAVE1, AfxGetInstanceHandle(), SND_RESOURCE | SND_ASYNC);
单次播放,循环播放,停止播放
1
2
3
4
5
PlaySound((LPCTSTR)IDR_WAVE1, AfxGetInstanceHandle(), SND_RESOURCE | SND_ASYNC| SND_LOOP);
//加入SND_LOOP为循环播放,否则为单次

PlaySound(NULL,NULL,SND_FILENAME | SND_ASYNC | SND_LOOP);
//停止所有音乐播放
4.显示图片
添加资源

建议使用bmp图片,如果加入图片失败请尝试将像素减少。
无法编辑属于可以正常显示的情况。
插入,资源,引入选择文件类型为所有文件,点击bmp格式的图片即可添加。
左侧资源窗体上可见其名称。

添加图片控件

控件栏上的图像控件,在窗体上框出希望的大小。
右键属性。
类型:位图
图像:图像ID

5.更换程序图标

在工程文件夹下,找到res下的ico文件,将想替换的图标替换其即可。

五、END

编译好的可执行文件在工程文件Debug下哦!(。・`ω´・)