参考文档:http://wenku.baidu.com/link?url=MLGQojaxyHnEgngEAXG8oPnISuM9SVaDzNTvg0oTSrrJkMXIR_6MR3cO_Vnh-grkUekLw2CSnQlE2ni5P-CzCCyI36fnNFFl_BkbEbMomP_ MSComm在VS2010中的实现过程
注:在vs2010中MSComm类中一些函数被改变了,例如setcommport()被改成了put_commport(),getinput()改为了get_input(),以此类推。
串口编程流程
1、串口初始化。
在MSCommDlg.cpp中的OnInitDialog()中,加入串口初始化代码。
代码如下:
1: // CMSCommDlg 消息处理程序
2:
3: BOOL CMSCommDlg::OnInitDialog()
4: {
5: CDialogEx::OnInitDialog();
6:
7: // 将“关于...”菜单项添加到系统菜单中。
8:
9: // IDM_ABOUTBOX 必须在系统命令范围内。
10: ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
11: ASSERT(IDM_ABOUTBOX < 0xF000);
12:
13: CMenu* pSysMenu = GetSystemMenu(FALSE);
14: if (pSysMenu != NULL)
15: {
16: BOOL bNameValid;
17: CString strAboutMenu;
18: bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
19: ASSERT(bNameValid);
20: if (!strAboutMenu.IsEmpty())
21: {
22: pSysMenu->AppendMenu(MF_SEPARATOR);
23: pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
24: }
25: }
26:
27: // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
28: // 执行此操作
29: SetIcon(m_hIcon, TRUE); // 设置大图标
30: SetIcon(m_hIcon, FALSE); // 设置小图标
31:
32: // TODO: 在此添加额外的初始化代码
33: m_Comm.put_CommPort(2);//选择串口2
34: m_Comm.put_InputMode(1);//输入模式为二进制模式
35: m_Comm.put_InBufferSize(1024);//输入缓冲区大小
36: m_Comm.put_OutBufferSize(512);//输出缓冲区大小
37: //设置波特率9600,无奇偶校验,8位数据位,1位停止位
38: m_Comm.put_Settings(_T("9600,n,8,1"));
39: if(!m_Comm.get_PortOpen())
40: {
41: m_Comm.put_PortOpen(TRUE);//打开串口
42: }
43: //每接收一个字符或多个字符就会触发OnComm事件
44: m_Comm.put_RThreshold(1);//每当接收缓冲区有1个字符则接收串口数据
45: //清空缓存区内容
46: m_Comm.put_InputLen(0);// 设置当前缓冲区长度为0
47: m_Comm.get_Input(); // 预读缓冲区以清除残留数据(从接收缓冲区中读取数据)
48:
49: return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
50: }
2、为MSComm类添加事件处理函数OnCommMscomm1();用于处理接收到的数据。
注:在此介绍一个小知识。文本框如何和字符串相关联。
DDX_Control 与 DDX_Text 区别
1)DDX_Text()的作用可以理解为把字符串变量与控件的文本(WindowText)关联起来。
2)DDX_Control()的作用可以理解为把变量和控件本身相关联,此变量就是一个控件类型的变量。
3)DoDataExchange(pDX)的作业可以理解为处理所有变量与其相关联控件,两者进行数据交换的函数。
1: void CView::DoDataExchange(CDataExchange* pDX)
2: {
3: CFormView::DoDataExchange(pDX);
4: DDX_Text(pDX, IDC_ID_VALUE, m_strID); //1
5: DDX_Control(pDX, IDC_ID_VALUE, m_editID); //2
6: }
针对1: 通过updateData(TRUE)取得控件上的值传给m_strID,此时说明可以进行修改。修改完之后,通过ApdateData(FALSE),将变量的值传回控件,然后进行界面显示。
针对2: 通过m_editID.GetWindText(str),取得值,处理后,通过m_editID.SetWindText(str)传回控件界面显示。
下面再举一个小实例来进行说明:
给编辑框加成员变量m_strA
在响应插入操作的消息里如下写
UpdateData(TRUE);
m_strA += _T("b"); //此处只能是一个常量,变量行不通,需要利用DDX_Text()或者下面的函数进行处理。
UpdateData(FALSE);
等同于:
CString str;
((CEdit*)GetDlgItem(IDC_EDIT)->GetWindowText(str);
str+="b";
((CEdit*)GetDlgItem(IDC_EDIT)->SetWindowText(str);
主要程序如下:
1: void CMSCommDlg::OnCommMscomm1()
2: {
3: // TODO: 在此处添加消息处理程序代码
4: VARIANT variant_inp;//VARIANT型变量,用于接收串口数据
5: COleSafeArray safearray_inp;//安全数组,用于接收串口数据
6: LONG len,k;
7: BYTE rxdata[2048];//接收数据缓冲区
8: CString strTemp;
9: if(m_Comm.get_CommEvent() == 2)//事件值为2表示有接收到的数据到来
10: {
11: variant_inp = m_Comm.get_Input();
12: safearray_inp = variant_inp;//将VARIANT类型变量转换为COleSafeArray类型变量(我们可以理解为一个容器,有数据有长度尺寸等。)
13: len = safearray_inp.GetOneDimSize();//获取有效数据的长度
14: for(k = 0; k < len; k++)
15: {
16: safearray_inp.GetElement(&k,rxdata+k);//将COleSafeArray类型变量,拆解为字符数组。
17: }
18: for(k = 0; k < len; k++) //将字符数组转换为字符串类型变量
19: {
20: BYTE bt = *(char *)(rxdata + k);
21: strTemp.Format(_T("%c"),bt);
22: m_strEditRXData += (strTemp);
23: }
24: }
25: //自动换行的实现
26: CString temp = _T(" ");//显示完成后要自动换行
27: //_T就是TEXT,vs2010里面为了兼容vc6.0而设计的转换(兼容)函数。
28: m_strEditRXData += temp;
29: UpdateData(FALSE); //显示接收编辑框中的内容
30: }
3、发送数据。通过put_output()函数,向发送缓冲区写入数据即可。
为对话框类添加onbuttonsend函数,然后编辑。核心代码如下:
1: void CMSCommDlg::OnBnClickedButton1Send()
2: {
3: // TODO: 在此添加控件通知处理程序代码
4: UpdateData(TRUE); //读取发送编辑框中的文本内容
5: //对发送的数据进行强制类型转换,由CString 字符串数据转换为VARIANT 类型。
6: m_Comm.put_Output(COleVariant(m_strEditTXData));//发送数据,可以将字符串变为VARIANT型数据类型
7: //以下两句代码可以不要。以下两句为一个整体,用其一肯定没有用处。
8: //用下面两句就不用手动清空了。呵呵,可以自动清空发送缓冲区数据。
9: //首先清空发送的字符串变量,然后将此变量的值返回给控件。使控件为空。从而达到清空的目的。
10: m_strEditTXData.Empty();//发送后清空输入框
11: UpdateData(FALSE); //更新编辑框内容
12: }
4、结果演示:
以下是整个代码:(供读者朋友们参考)
MSCommDlg.cpp文件:
1:
2: // MSCommDlg.cpp : 实现文件
3: //
4:
5: #include "stdafx.h"
6: #include "MSComm.h"
7: #include "MSCommDlg.h"
8: #include "afxdialogex.h"
9: #include "Resource.h"
10:
11: #ifdef _DEBUG
12: #define new DEBUG_NEW
13: #endif
14:
15:
16: // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
17:
18: class CAboutDlg : public CDialogEx
19: {
20: public:
21: CAboutDlg();
22:
23: // 对话框数据
24: enum { IDD = IDD_ABOUTBOX };
25:
26: protected:
27: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
28:
29: // 实现
30: protected:
31: DECLARE_MESSAGE_MAP()
32: };
33:
34: CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
35: {
36: }
37:
38: void CAboutDlg::DoDataExchange(CDataExchange* pDX)
39: {
40: CDialogEx::DoDataExchange(pDX);
41: }
42:
43: BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
44: END_MESSAGE_MAP()
45:
46:
47: // CMSCommDlg 对话框
48:
49:
50:
51:
52: CMSCommDlg::CMSCommDlg(CWnd* pParent /*=NULL*/)
53: : CDialogEx(CMSCommDlg::IDD, pParent)
54: {
55: m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
56: m_strEditRXData = _T(""); //也可以自己自动在对话框上右击,添加变量生成。
57: m_strEditTXData = _T("");
58: }
59:
60: void CMSCommDlg::DoDataExchange(CDataExchange* pDX)
61: {
62: CDialogEx::DoDataExchange(pDX);
63: DDX_Control(pDX, IDC_MSCOMM1, m_Comm);
64: // DDX_Control(pDX, IDC_EDIT1, m_strEditRXData);
65: DDX_Text(pDX,IDC_EDIT1,m_strEditRXData);
66: DDX_Text(pDX,IDC_EDIT2,m_strEditTXData);
67: }
68:
69: BEGIN_MESSAGE_MAP(CMSCommDlg, CDialogEx)
70: ON_WM_SYSCOMMAND()
71: ON_WM_PAINT()
72: ON_WM_QUERYDRAGICON()
73: ON_BN_CLICKED(IDC_BUTTON1_SEND, &CMSCommDlg::OnBnClickedButton1Send)
74: END_MESSAGE_MAP()
75:
76:
77: // CMSCommDlg 消息处理程序
78:
79: BOOL CMSCommDlg::OnInitDialog()
80: {
81: CDialogEx::OnInitDialog();
82:
83: // 将“关于...”菜单项添加到系统菜单中。
84:
85: // IDM_ABOUTBOX 必须在系统命令范围内。
86: ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
87: ASSERT(IDM_ABOUTBOX < 0xF000);
88:
89: CMenu* pSysMenu = GetSystemMenu(FALSE);
90: if (pSysMenu != NULL)
91: {
92: BOOL bNameValid;
93: CString strAboutMenu;
94: bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
95: ASSERT(bNameValid);
96: if (!strAboutMenu.IsEmpty())
97: {
98: pSysMenu->AppendMenu(MF_SEPARATOR);
99: pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
100: }
101: }
102:
103: // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
104: // 执行此操作
105: SetIcon(m_hIcon, TRUE); // 设置大图标
106: SetIcon(m_hIcon, FALSE); // 设置小图标
107:
108: // TODO: 在此添加额外的初始化代码
109: m_Comm.put_CommPort(2);//选择串口2
110: m_Comm.put_InputMode(1);//输入模式为二进制模式
111: m_Comm.put_InBufferSize(1024);//输入缓冲区大小
112: m_Comm.put_OutBufferSize(512);//输出缓冲区大小
113: //设置波特率9600,无奇偶校验,8位数据位,1位停止位
114: m_Comm.put_Settings(_T("9600,n,8,1"));
115: if(!m_Comm.get_PortOpen())
116: {
117: m_Comm.put_PortOpen(TRUE);//打开串口
118: }
119: //每接收一个字符或多个字符就会触发OnComm事件
120: m_Comm.put_RThreshold(1);//每当接收缓冲区有1个字符则接收串口数据
121: //清空缓存区内容
122: m_Comm.put_InputLen(0);// 设置当前缓冲区长度为0
123: m_Comm.get_Input(); // 预读缓冲区以清除残留数据(从接收缓冲区中读取数据)
124:
125: return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
126: }
127:
128: void CMSCommDlg::OnSysCommand(UINT nID, LPARAM lParam)
129: {
130: if ((nID & 0xFFF0) == IDM_ABOUTBOX)
131: {
132: CAboutDlg dlgAbout;
133: dlgAbout.DoModal();
134: }
135: else
136: {
137: CDialogEx::OnSysCommand(nID, lParam);
138: }
139: }
140:
141: // 如果向对话框添加最小化按钮,则需要下面的代码
142: // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
143: // 这将由框架自动完成。
144:
145: void CMSCommDlg::OnPaint()
146: {
147: if (IsIconic())
148: {
149: CPaintDC dc(this); // 用于绘制的设备上下文
150:
151: SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
152:
153: // 使图标在工作区矩形中居中
154: int cxIcon = GetSystemMetrics(SM_CXICON);
155: int cyIcon = GetSystemMetrics(SM_CYICON);
156: CRect rect;
157: GetClientRect(&rect);
158: int x = (rect.Width() - cxIcon + 1) / 2;
159: int y = (rect.Height() - cyIcon + 1) / 2;
160:
161: // 绘制图标
162: dc.DrawIcon(x, y, m_hIcon);
163: }
164: else
165: {
166: CDialogEx::OnPaint();
167: }
168: }
169:
170: //当用户拖动最小化窗口时系统调用此函数取得光标
171: //显示。
172: HCURSOR CMSCommDlg::OnQueryDragIcon()
173: {
174: return static_cast<HCURSOR>(m_hIcon);
175: }
176:
177: BEGIN_EVENTSINK_MAP(CMSCommDlg, CDialogEx)
178: ON_EVENT(CMSCommDlg, IDC_MSCOMM1, 1, CMSCommDlg::OnCommMscomm1, VTS_NONE)
179: END_EVENTSINK_MAP()
180:
181:
182: void CMSCommDlg::OnCommMscomm1()
183: {
184: // TODO: 在此处添加消息处理程序代码
185: VARIANT variant_inp;//VARIANT型变量,用于接收串口数据
186: COleSafeArray safearray_inp;//安全数组,用于接收串口数据
187: LONG len,k;
188: BYTE rxdata[2048];//接收数据缓冲区
189: CString strTemp;
190: if(m_Comm.get_CommEvent() == 2)//事件值为2表示有接收到的数据到来
191: {
192: variant_inp = m_Comm.get_Input();
193: safearray_inp = variant_inp;//将VARIANT类型变量转换为COleSafeArray类型变量(我们可以理解为一个容器,有数据有长度尺寸等。)
194: len = safearray_inp.GetOneDimSize();//获取有效数据的长度
195: for(k = 0; k < len; k++)
196: {
197: safearray_inp.GetElement(&k,rxdata+k);//将COleSafeArray类型变量,拆解为字符数组。
198: }
199: for(k = 0; k < len; k++) //将字符数组转换为字符串类型变量
200: {
201: BYTE bt = *(char *)(rxdata + k);
202: strTemp.Format(_T("%c"),bt);
203: m_strEditRXData += (strTemp);
204: }
205: }
206: //自动换行的实现
207: CString temp = _T(" ");//显示完成后要自动换行
208: //_T就是TEXT,vs2010里面为了兼容vc6.0而设计的转换(兼容)函数。
209: m_strEditRXData += temp;
210: UpdateData(FALSE); //显示接收编辑框中的内容
211: }
212:
213:
214: void CMSCommDlg::OnBnClickedButton1Send()
215: {
216: // TODO: 在此添加控件通知处理程序代码
217: UpdateData(TRUE); //读取发送编辑框中的文本内容
218: //对发送的数据进行强制类型转换,由CString 字符串数据转换为VARIANT 类型。
219: m_Comm.put_Output(COleVariant(m_strEditTXData));//发送数据,可以将字符串变为VARIANT型数据类型
220: //以下两句代码可以不要。以下两句为一个整体,用其一肯定没有用处。
221: //用下面两句就不用手动清空了。呵呵,可以自动清空发送缓冲区数据。
222: //首先清空发送的字符串变量,然后将此变量的值返回给控件。使控件为空。从而达到清空的目的。
223: m_strEditTXData.Empty();//发送后清空输入框
224: UpdateData(FALSE); //更新编辑框内容
225: }
MSCommDlg.h 文件:
1:
2: // MSCommDlg.h : 头文件
3: //
4:
5: #pragma once
6: #include "mscomm1.h"
7: #include "afxwin.h"
8:
9:
10: // CMSCommDlg 对话框
11: class CMSCommDlg : public CDialogEx
12: {
13: // 构造
14: public:
15: CMSCommDlg(CWnd* pParent = NULL); // 标准构造函数
16:
17: // 对话框数据
18: enum { IDD = IDD_MSCOMM_DIALOG };
19:
20: protected:
21: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
22:
23:
24: // 实现
25: protected:
26: HICON m_hIcon;
27:
28: // 生成的消息映射函数
29: virtual BOOL OnInitDialog();
30: afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
31: afx_msg void OnPaint();
32: afx_msg HCURSOR OnQueryDragIcon();
33: DECLARE_MESSAGE_MAP()
34: public:
35: DECLARE_EVENTSINK_MAP()
36: void OnCommMscomm1();
37: afx_msg void OnBnClickedButton1Send();
38: CMscomm1 m_Comm;
39: CString m_strEditRXData; //可以通过为对话框添加变量建立此变量,也可以直接敲代码建立此成员变量。
40: CString m_strEditTXData; //假如是通过直接敲代码建立的成员变量,需要在.cpp文件里面手动初始化。然后,在和需要联系的
41: // CEdit m_strEditRXData; // 控件建立联系。.cpp里面有很详细。
42: };