文章目录
- [1 功能展示](#1 功能展示)
- [2 实现步骤](#2 实现步骤)
-
- [2.1 添加控件 及 控件变量](#2.1 添加控件 及 控件变量)
- [2.2 添加按钮及静态文本框](#2.2 添加按钮及静态文本框)
- [2.3 声明其他变量 及 函数](#2.3 声明其他变量 及 函数)
- [3 函数实现](#3 函数实现)
-
- [3.1 初始刷函数](#3.1 初始刷函数)
- [3.2 设置串口参数](#3.2 设置串口参数)
- [3.3 打开串口函数](#3.3 打开串口函数)
- [3.4 显示串口状态](#3.4 显示串口状态)
- [3.5 关闭串口](#3.5 关闭串口)
- [3.6 更改串口、波特率、校验位、数据位、停止位](#3.6 更改串口、波特率、校验位、数据位、停止位)
- [3.7 串口状态显示](#3.7 串口状态显示)
- [4 串口参数 与预设不完全一致](#4 串口参数 与预设不完全一致)
- [5 完整代码](#5 完整代码)
-
- [5.1 ...Dlg.h文件](#5.1 ...Dlg.h文件)
- [4.2 ...Dlg.cpp文件](#4.2 ...Dlg.cpp文件)
- [6 小改进](#6 小改进)
- [6 完整MFC项目项下载](#6 完整MFC项目项下载)
1 功能展示
实现串口助手:
2 实现步骤
2.1 添加控件 及 控件变量
在工具栏中 拖拽5个 Combobox 控件,和5个 Static Text控件,
排好序,并如下命名;
给5个 Combobox 控件,分别添加以下控件变量 和 值变量 (通过右键控件,弹出的窗口添加)
cpp
//控件 列表框变量
m_Combo_Com; //列表框:串口
m_Combo_Baud; //列表框:波特率
m_Combo_Check; //列表框:校验位
m_Combo_Data; //列表框:数据位
m_Combo_Stop; //列表框:停止位
//值 字符变量
m_Str_Com; //字符变量:串口
m_Str_Baud; //字符变量:波特率
m_Str_Check; //字符变量:校验位
m_Str_Data; //字符变量:数据位
m_Str_Stop; //字符变量:停止位
...Dlg.h文件中 会多出10行;
...Dlg.cpp文件中 会多出以下代码

2.2 添加按钮及静态文本框
添加4个 Static Text控件,和一个 Button 按钮
其ID命名如下
cpp
IDC_COMSTATUS_STATIC
IDC_PORTisOPEN_STATIC
IDC_TXLEN_STATIC
IDC_RXLEN_STATIC
IDC_OPENCOM_BUTTON
定义两个变量
cpp
public:
//自定义变量
long m_rxlen; //接收数据个数
long m_txlen; //发送数据个数
2.3 声明其他变量 及 函数
Dlg.h文件中 所有用户生成或添加的 变量及函数
cpp
public:
//自定义变量
HANDLE m_hCom; //串口句柄
volatile int m_bConnected; //串口连接成功指示
BOOL m_COMStatu; //串口状态指示
long m_rxlen; //接收数据个数
long m_txlen; //发送数据个数
//列表框变量
CComboBox m_Combo_Com; //列表框:串口
CComboBox m_Combo_Baud; //列表框:波特率
CComboBox m_Combo_Check; //列表框:校验位
CComboBox m_Combo_Data; //列表框:数据位
CComboBox m_Combo_Stop; //列表框:停止位
//字符变量
CString m_Str_Com; //字符变量:串口
CString m_Str_Baud; //字符变量:波特率
CString m_Str_Check; //字符变量:校验位
CString m_Str_Data; //字符变量:数据位
CString m_Str_Stop; //字符变量:停止位
//函数=====================================================================================
public:
//串口相关函数
BOOL OpenComm(int Num); //打开串口
BOOL SetCommParameter(); //设置串口参数
void DisplayStatus(); //显示串口状态
void CloseConnection(); //关闭串口
//按钮函数
afx_msg void OnBnClickedOpencomButton(); //串口状态显示
//列表框函数
afx_msg void OnCbnSelchangeComboCom(); //更改串口
afx_msg void OnCbnSelchangeComboBaud(); //更改波特率
afx_msg void OnCbnSelchangeComboCheck(); //更改校验位
afx_msg void OnCbnSelchangeComboData(); //更改数据位
afx_msg void OnCbnSelchangeComboStop(); //更改停止位
3 函数实现
3.1 初始刷函数
在OnInitDialog()函数中添加
cpp
// TODO: 在此添加额外的初始化代码
//========================================== = 初始化对话框========================================== =
//设串口组合列表框
TCHAR com[][6] = {_T("COM1"),_T("COM2"),_T("COM3"),_T("COM4"),_T("COM5"),_T("COM6"),_T("COM7"),_T("COM8"),_T("COM9") };
for (int i = 0; i < 9; i++)
m_Combo_Com.AddString(com[i]);
m_Combo_Com.SetCurSel(0);//默认显示第1个串口号
//设波特率组合列表框
TCHAR baud[][7] = {_T("9600"),_T("19200"),_T("38400"),_T("43000"),_T("56000"),_T("57600"),_T("115200"),_T("128000"),_T("230400") };
for (int i = 0; i < 9; i++)
m_Combo_Baud.AddString(baud[i]);
m_Combo_Baud.SetCurSel(2);//默认显示第3个波特率
//设校验位组合列表框
TCHAR check[][7] = {_T("None"),_T("Odd"),_T("Even") };
for (int i = 0; i < 3; i++)
m_Combo_Check.AddString(check[i]);
m_Combo_Check.SetCurSel(0);//默认显示无校验
//设数据位组合列表框
TCHAR data[][2] = {_T("8"),_T("7"),_T("6") };
for (int i = 0; i < 3; i++)
m_Combo_Data.AddString(data[i]);
m_Combo_Data.SetCurSel(0);
//设停止位组合列表框
TCHAR stop[][2] = { _T("1"),_T("2") };
for (int i = 0; i < 2; i++)
m_Combo_Stop.AddString(stop[i]);
m_Combo_Stop.SetCurSel(0);
//打开串口函数赋初值
OpenComm(0);
3.2 设置串口参数
cpp
/==============================================设置串口参数==============================================
//设置串口参数
BOOL CSerialPortDlg::SetCommParameter()
{
DCB dcb; //DCB结构,定义了串口通信设备的控制设置
if (!GetCommState(m_hCom, &dcb))
//读取新创建的 m_hCom串口句柄的 DCB设备控制块结构体,当只需要设置一部分 DCB参数时,可以通过此函数读取现有参数,只改变部分参数即可
return FALSE; //如果读取不成功直接结束
//设置波特率
long baudrate[] = {9600,19200,38400,43000,56000,57600,115200,128000,230400 };
int baudindex = m_Combo_Baud.GetCurSel();
m_Combo_Baud.GetLBText(baudindex, m_Str_Baud);
dcb.BaudRate = baudrate[baudindex];//读取并设置波特率参数
//设置数据位
int databit[] = { 8,7,6 };
int dataindex = m_Combo_Data.GetCurSel();
m_Combo_Data.GetLBText(dataindex, m_Str_Data);
dcb.ByteSize = databit[dataindex];
//设置校验位
int checkindex = m_Combo_Check.GetCurSel();
m_Combo_Check.GetLBText(checkindex, m_Str_Check);
switch (checkindex)
{
case 0: dcb.Parity = NOPARITY; break;
case 1: dcb.Parity = ODDPARITY; break;
case 2: dcb.Parity = EVENPARITY; break;
default:;
}
//设置停止位
int stopindex = m_Combo_Stop.GetCurSel();
m_Combo_Stop.GetLBText(stopindex, m_Str_Stop);
switch (stopindex)
{
case 0: dcb.StopBits = ONESTOPBIT; break;
case 1: dcb.StopBits = TWOSTOPBITS; break;
default:;
}
//流控制
dcb.fInX = FALSE;
dcb.fOutX = FALSE;
dcb.fNull = FALSE; //为TRUE时,接收时自动去掉空(0值)字节
dcb.fBinary = TRUE; //指定是否允许二进制模式。Win32 API不支持非二进制模式传输,应设置为true
dcb.fParity = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
return(SetCommState(m_hCom, &dcb)); //应用设置
}
3.3 打开串口函数
cpp
/==============================================打开串口==============================================
//打开串口函数
BOOL CSerialPortDlg::OpenComm(int Num)
{
m_Combo_Com.GetLBText(Num, m_Str_Com);
//获取串口Combo下拉框中对应于Num位置的串口名称,比如Num=0时,m_SeriouStr 为"COM1"
m_hCom = CreateFile(m_Str_Com, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
//将串口作为一个文件来看,用CreateFile()函数打开串口,返回结果存储在m_hCom中
if (m_hCom == INVALID_HANDLE_VALUE)//如果返回INVALID_HANDLE_VALUE表示打开串口失败,
{
AfxMessageBox(_T("打开串口失败!")); //失败时弹出对话框提醒
m_bConnected = 0; //将串口连接标志设为0
return FALSE; //打开失败后不再继续往下进行,直接返回FALSE
}
m_bConnected = 1; //将串口连接标志设为1
return 0;
}
3.4 显示串口状态
cpp
//============================================显示串口状态============================================
//显示串口状态
void CSerialPortDlg::DisplayStatus()
{
CWnd* static_status = GetDlgItem(IDC_COMSTATUS_STATIC);
CWnd* static_txlen = GetDlgItem(IDC_TXLEN_STATIC);
CWnd* static_rxlen = GetDlgItem(IDC_RXLEN_STATIC);
CString status_str, txlen_str, rxlen_str;
if (m_bConnected)
{
status_str = _T("STATUS:") + m_Str_Com + " OPENED," + m_Str_Baud + ',' + m_Str_Check + ',' + m_Str_Data + ',' + m_Str_Stop;
SetCommParameter();
}
else
status_str = _T("STATUS:") + m_Str_Com + " CLOSED," + m_Str_Baud + ',' + m_Str_Check + ',' + m_Str_Data + ',' + m_Str_Stop;
static_status->SetWindowText(status_str);
txlen_str.Format(_T("TX: % ld"), m_txlen);
static_txlen->SetWindowText(txlen_str);
rxlen_str.Format(_T("RX:%ld"), m_rxlen);
static_rxlen->SetWindowText(rxlen_str);
}
3.5 关闭串口
cpp
//==============================================关闭串口==============================================
//关闭串口
void CSerialPortDlg::CloseConnection()
{
if (!m_bConnected)
return;
m_bConnected = FALSE;
SetCommMask(m_hCom, 0);
CloseHandle(m_hCom);
}
3.6 更改串口、波特率、校验位、数据位、停止位
cpp
//==============================================更改串口设置==============================================
//更改串口
void CSerialPortDlg::OnCbnSelchangeComboCom()
{
// TODO: 在此添加控件通知处理程序代码
if (m_bConnected)
CloseConnection();
if (m_COMStatu)
{
int i = m_Combo_Com.GetCurSel();
OpenComm(i);
}
DisplayStatus();
}
//更改波特率
void CSerialPortDlg::OnCbnSelchangeComboBaud()
{
// TODO: 在此添加控件通知处理程序代码
int baudindex;
baudindex = m_Combo_Baud.GetCurSel();
if (baudindex != CB_ERR)
{
SetCommParameter();
//把索引号为baudindex的数据放到m_Str_Baud变量中,传给m_Combo_Baud控件
m_Combo_Baud.GetLBText(baudindex, m_Str_Baud);
}
DisplayStatus();
}
//更改校验位
void CSerialPortDlg::OnCbnSelchangeComboCheck()
{
// TODO: 在此添加控件通知处理程序代码
int checkindex;
checkindex = m_Combo_Check.GetCurSel();
if (checkindex != CB_ERR)
{
SetCommParameter();
m_Combo_Check.GetLBText(checkindex, m_Str_Check);
DisplayStatus();
}
}
//更改数据位
void CSerialPortDlg::OnCbnSelchangeComboData()
{
// TODO: 在此添加控件通知处理程序代码
int dataindex;
dataindex = m_Combo_Data.GetCurSel();
if (dataindex != CB_ERR)
{
SetCommParameter();
m_Combo_Data.GetLBText(dataindex, m_Str_Data);
DisplayStatus();
}
}
//更改停止位
void CSerialPortDlg::OnCbnSelchangeComboStop()
{
// TODO: 在此添加控件通知处理程序代码
int stopindex;
stopindex = m_Combo_Stop.GetCurSel();
if (stopindex != CB_ERR)
{
SetCommParameter();
m_Combo_Stop.GetLBText(stopindex, m_Str_Stop);
DisplayStatus();
}
}
增加了此功能后,就可以随意选择下路框的参数了
3.7 串口状态显示
cpp
//==========================================串口开关按钮状态显示==========================================
//串口状态显示
void CSerialPortDlg::OnBnClickedOpencomButton()
{
// TODO: 在此添加控件通知处理程序代码
m_COMStatu = !m_COMStatu;
if (!m_COMStatu)
GetDlgItem(IDC_PORTisOPEN_STATIC)->SetWindowText(_T("串口状态:串口已关闭"));
else
GetDlgItem(IDC_PORTisOPEN_STATIC)->SetWindowText(_T("串口状态:串口已打开"));
OnCbnSelchangeComboCom();
DisplayStatus();
return;
}
4 串口参数 与预设不完全一致
我们预期是:串口号COM1,波特率38400,校验None,数据8,停止位1;
但实际效果:波特率19200、校验Even、数据6
,显示的不对。
解决办法:
【52】MFC入门到精通------(CComboBox)下拉框选项顺序与初始化不一致,默认显示项也不一致
5 完整代码
5.1 ...Dlg.h文件
cpp
// SerialPortDlg.h: 头文件
//
#pragma once
// CSerialPortDlg 对话框
class CSerialPortDlg : public CDialogEx
{
// 构造
public:
CSerialPortDlg(CWnd* pParent = nullptr); // 标准构造函数
//变量=====================================================================================
public:
//自定义变量
HANDLE m_hCom; //串口句柄
volatile int m_bConnected; //串口连接成功指示
BOOL m_COMStatu; //串口状态指示
long m_rxlen; //接收数据个数
long m_txlen; //发送数据个数
//列表框变量
CComboBox m_Combo_Com; //列表框:串口
CComboBox m_Combo_Baud; //列表框:波特率
CComboBox m_Combo_Check; //列表框:校验位
CComboBox m_Combo_Data; //列表框:数据位
CComboBox m_Combo_Stop; //列表框:停止位
//字符变量
CString m_Str_Com; //字符变量:串口
CString m_Str_Baud; //字符变量:波特率
CString m_Str_Check; //字符变量:校验位
CString m_Str_Data; //字符变量:数据位
CString m_Str_Stop; //字符变量:停止位
//函数=====================================================================================
public:
//串口相关函数
BOOL OpenComm(int Num); //打开串口
BOOL SetCommParameter(); //设置串口参数
void DisplayStatus(); //显示串口状态
void CloseConnection(); //关闭串口
//按钮函数
afx_msg void OnBnClickedOpencomButton(); //串口状态显示
//列表框函数
afx_msg void OnCbnSelchangeComboCom(); //更改串口
afx_msg void OnCbnSelchangeComboBaud(); //更改波特率
afx_msg void OnCbnSelchangeComboCheck(); //更改校验位
afx_msg void OnCbnSelchangeComboData(); //更改数据位
afx_msg void OnCbnSelchangeComboStop(); //更改停止位
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_SERIALPORT_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
};
4.2 ...Dlg.cpp文件
cpp
// SerialPortDlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "SerialPort.h"
#include "SerialPortDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序"关于"菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CSerialPortDlg 对话框
CSerialPortDlg::CSerialPortDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_SERIALPORT_DIALOG, pParent)
, m_Str_Com(_T(""))
, m_Str_Baud(_T(""))
, m_Str_Check(_T(""))
, m_Str_Data(_T(""))
, m_Str_Stop(_T(""))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CSerialPortDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_COMBO1, m_Combo_Com);
DDX_Control(pDX, IDC_COMBO2, m_Combo_Baud);
DDX_Control(pDX, IDC_COMBO3, m_Combo_Check);
DDX_Control(pDX, IDC_COMBO4, m_Combo_Data);
DDX_Control(pDX, IDC_COMBO5, m_Combo_Stop);
DDX_CBString(pDX, IDC_COMBO1, m_Str_Com);
DDX_CBString(pDX, IDC_COMBO2, m_Str_Baud);
DDX_CBString(pDX, IDC_COMBO3, m_Str_Check);
DDX_CBString(pDX, IDC_COMBO4, m_Str_Data);
DDX_CBString(pDX, IDC_COMBO5, m_Str_Stop);
}
BEGIN_MESSAGE_MAP(CSerialPortDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_OPENCOM_BUTTON, &CSerialPortDlg::OnBnClickedOpencomButton)
END_MESSAGE_MAP()
// CSerialPortDlg 消息处理程序
BOOL CSerialPortDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将"关于..."菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
//========================================== = 初始化对话框========================================== =
//设串口组合列表框
TCHAR com[][6] = {_T("COM1"),_T("COM2"),_T("COM3"),_T("COM4"),_T("COM5"),_T("COM6"),_T("COM7"),_T("COM8"),_T("COM9") };
for (int i = 0; i < 9; i++)
m_Combo_Com.AddString(com[i]);
m_Combo_Com.SetCurSel(0);//默认显示第1个串口号
//设波特率组合列表框
TCHAR baud[][7] = {_T("9600"),_T("19200"),_T("38400"),_T("43000"),_T("56000"),_T("57600"),_T("115200"),_T("128000"),_T("230400") };
for (int i = 0; i < 9; i++)
m_Combo_Baud.AddString(baud[i]);
m_Combo_Baud.SetCurSel(2);//默认显示第3个波特率
//设校验位组合列表框
TCHAR check[][7] = {_T("None"),_T("Odd"),_T("Even") };
for (int i = 0; i < 3; i++)
m_Combo_Check.AddString(check[i]);
m_Combo_Check.SetCurSel(0);//默认显示无校验
//设数据位组合列表框
TCHAR data[][2] = {_T("8"),_T("7"),_T("6") };
for (int i = 0; i < 3; i++)
m_Combo_Data.AddString(data[i]);
m_Combo_Data.SetCurSel(0);
//设停止位组合列表框
TCHAR stop[][2] = { _T("1"),_T("2") };
for (int i = 0; i < 2; i++)
m_Combo_Stop.AddString(stop[i]);
m_Combo_Stop.SetCurSel(0);
//打开串口函数赋初值
OpenComm(0);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CSerialPortDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CSerialPortDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CSerialPortDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
//==============================================设置串口参数==============================================
//设置串口参数
BOOL CSerialPortDlg::SetCommParameter()
{
DCB dcb; //DCB结构,定义了串口通信设备的控制设置
if (!GetCommState(m_hCom, &dcb))
//读取新创建的 m_hCom串口句柄的 DCB设备控制块结构体,当只需要设置一部分 DCB参数时,可以通过此函数读取现有参数,只改变部分参数即可
return FALSE; //如果读取不成功直接结束
//设置波特率
long baudrate[] = {9600,19200,38400,43000,56000,57600,115200,128000,230400 };
int baudindex = m_Combo_Baud.GetCurSel();
m_Combo_Baud.GetLBText(baudindex, m_Str_Baud);
dcb.BaudRate = baudrate[baudindex];//读取并设置波特率参数
//设置数据位
int databit[] = { 8,7,6 };
int dataindex = m_Combo_Data.GetCurSel();
m_Combo_Data.GetLBText(dataindex, m_Str_Data);
dcb.ByteSize = databit[dataindex];
//设置校验位
int checkindex = m_Combo_Check.GetCurSel();
m_Combo_Check.GetLBText(checkindex, m_Str_Check);
switch (checkindex)
{
case 0: dcb.Parity = NOPARITY; break;
case 1: dcb.Parity = ODDPARITY; break;
case 2: dcb.Parity = EVENPARITY; break;
default:;
}
//设置停止位
int stopindex = m_Combo_Stop.GetCurSel();
m_Combo_Stop.GetLBText(stopindex, m_Str_Stop);
switch (stopindex)
{
case 0: dcb.StopBits = ONESTOPBIT; break;
case 1: dcb.StopBits = TWOSTOPBITS; break;
default:;
}
//流控制
dcb.fInX = FALSE;
dcb.fOutX = FALSE;
dcb.fNull = FALSE; //为TRUE时,接收时自动去掉空(0值)字节
dcb.fBinary = TRUE; //指定是否允许二进制模式。Win32 API不支持非二进制模式传输,应设置为true
dcb.fParity = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
return(SetCommState(m_hCom, &dcb)); //应用设置
}
//==============================================打开串口==============================================
//打开串口函数
BOOL CSerialPortDlg::OpenComm(int Num)
{
m_Combo_Com.GetLBText(Num, m_Str_Com);
//获取串口Combo下拉框中对应于Num位置的串口名称,比如Num=0时,m_SeriouStr 为"COM1"
m_hCom = CreateFile(m_Str_Com, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
//将串口作为一个文件来看,用CreateFile()函数打开串口,返回结果存储在m_hCom中
if (m_hCom == INVALID_HANDLE_VALUE)//如果返回INVALID_HANDLE_VALUE表示打开串口失败,
{
AfxMessageBox(_T("打开串口失败!")); //失败时弹出对话框提醒
m_bConnected = 0; //将串口连接标志设为0
return FALSE; //打开失败后不再继续往下进行,直接返回FALSE
}
m_bConnected = 1; //将串口连接标志设为1
return 0;
}
//============================================显示串口状态============================================
//显示串口状态
void CSerialPortDlg::DisplayStatus()
{
CWnd* static_status = GetDlgItem(IDC_COMSTATUS_STATIC);
CWnd* static_txlen = GetDlgItem(IDC_TXLEN_STATIC);
CWnd* static_rxlen = GetDlgItem(IDC_RXLEN_STATIC);
CString status_str, txlen_str, rxlen_str;
if (m_bConnected)
{
status_str = _T("STATUS:") + m_Str_Com + " OPENED," + m_Str_Baud + ',' + m_Str_Check + ',' + m_Str_Data + ',' + m_Str_Stop;
SetCommParameter();
}
else
status_str = _T("STATUS:") + m_Str_Com + " CLOSED," + m_Str_Baud + ',' + m_Str_Check + ',' + m_Str_Data + ',' + m_Str_Stop;
static_status->SetWindowText(status_str);
txlen_str.Format(_T("TX: % ld"), m_txlen);
static_txlen->SetWindowText(txlen_str);
rxlen_str.Format(_T("RX:%ld"), m_rxlen);
static_rxlen->SetWindowText(rxlen_str);
}
//==============================================关闭串口==============================================
//关闭串口
void CSerialPortDlg::CloseConnection()
{
if (!m_bConnected)
return;
m_bConnected = FALSE;
SetCommMask(m_hCom, 0);
CloseHandle(m_hCom);
}
//==============================================更改串口设置==============================================
//更改串口
void CSerialPortDlg::OnCbnSelchangeComboCom()
{
// TODO: 在此添加控件通知处理程序代码
if (m_bConnected)
CloseConnection();
if (m_COMStatu)
{
int i = m_Combo_Com.GetCurSel();
OpenComm(i);
}
DisplayStatus();
}
//更改波特率
void CSerialPortDlg::OnCbnSelchangeComboBaud()
{
// TODO: 在此添加控件通知处理程序代码
int baudindex;
baudindex = m_Combo_Baud.GetCurSel();
if (baudindex != CB_ERR)
{
SetCommParameter();
//把索引号为baudindex的数据放到m_Str_Baud变量中,传给m_Combo_Baud控件
m_Combo_Baud.GetLBText(baudindex, m_Str_Baud);
}
DisplayStatus();
}
//更改校验位
void CSerialPortDlg::OnCbnSelchangeComboCheck()
{
// TODO: 在此添加控件通知处理程序代码
int checkindex;
checkindex = m_Combo_Check.GetCurSel();
if (checkindex != CB_ERR)
{
SetCommParameter();
m_Combo_Check.GetLBText(checkindex, m_Str_Check);
DisplayStatus();
}
}
//更改数据位
void CSerialPortDlg::OnCbnSelchangeComboData()
{
// TODO: 在此添加控件通知处理程序代码
int dataindex;
dataindex = m_Combo_Data.GetCurSel();
if (dataindex != CB_ERR)
{
SetCommParameter();
m_Combo_Data.GetLBText(dataindex, m_Str_Data);
DisplayStatus();
}
}
//更改停止位
void CSerialPortDlg::OnCbnSelchangeComboStop()
{
// TODO: 在此添加控件通知处理程序代码
int stopindex;
stopindex = m_Combo_Stop.GetCurSel();
if (stopindex != CB_ERR)
{
SetCommParameter();
m_Combo_Stop.GetLBText(stopindex, m_Str_Stop);
DisplayStatus();
}
}
//==========================================串口开关按钮状态显示==========================================
//串口状态显示
void CSerialPortDlg::OnBnClickedOpencomButton()
{
// TODO: 在此添加控件通知处理程序代码
m_COMStatu = !m_COMStatu;
if (!m_COMStatu)
GetDlgItem(IDC_PORTisOPEN_STATIC)->SetWindowText(_T("串口状态:串口已关闭"));
else
GetDlgItem(IDC_PORTisOPEN_STATIC)->SetWindowText(_T("串口状态:串口已打开"));
OnCbnSelchangeComboCom();
DisplayStatus();
return;
}
6 小改进
可以将 OnInitDialog() 函数中 串口初始化 部分进行 独立函数 封装
cpp
//初始化串口
BOOL CSerialPortDlg::InitComm()
{
//设串口组合列表框
TCHAR com[][6] = { _T("COM1"),_T("COM2"),_T("COM3"),_T("COM4"),_T("COM5"),_T("COM6"),_T("COM7"),_T("COM8"),_T("COM9") };
for (int i = 0; i < 9; i++)
m_Combo_Com.AddString(com[i]);
m_Combo_Com.SetCurSel(0);//默认显示第1个串口号
//设波特率组合列表框
TCHAR baud[][7] = { _T("9600"),_T("19200"),_T("38400"),_T("43000"),_T("56000"),_T("57600"),_T("115200"),_T("128000"),_T("230400") };
for (int i = 0; i < 9; i++)
m_Combo_Baud.AddString(baud[i]);
m_Combo_Baud.SetCurSel(2);//默认显示第3个波特率
//设校验位组合列表框
TCHAR check[][7] = { _T("None"),_T("Odd"),_T("Even") };
for (int i = 0; i < 3; i++)
m_Combo_Check.AddString(check[i]);
m_Combo_Check.SetCurSel(0);//默认显示无校验
//设数据位组合列表框
TCHAR data[][2] = { _T("8"),_T("7"),_T("6") };
for (int i = 0; i < 3; i++)
m_Combo_Data.AddString(data[i]);
m_Combo_Data.SetCurSel(0);
//设停止位组合列表框
TCHAR stop[][2] = { _T("1"),_T("2") };
for (int i = 0; i < 2; i++)
m_Combo_Stop.AddString(stop[i]);
m_Combo_Stop.SetCurSel(0);
return true;
}