【51】MFC入门到精通——MFC串口助手(一)---初级版(初始化、串口设置、修改参数、打开/关闭、状态显示),附源码

文章目录

  • [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;
}

6 完整MFC项目项下载

MFC串口助手初级版实现(初始化、串口设置、修改参数、打开/关闭、状态显示)---代码注释非常详细

相关推荐
The Chosen One98512 分钟前
C++的“链”珠妙笔:list的编程艺术
开发语言·数据结构·c++·list
Code Warrior1 小时前
【每日算法】专题十七_多源 BFS
数据结构·c++·算法·宽度优先
帅_shuai_2 小时前
C++ 分配内存释放内存
c++
刚入坑的新人编程4 小时前
暑期算法训练.5
数据结构·c++·算法
Jassy1594 小时前
C++二叉搜索树
数据结构·c++·学习
chilavert3185 小时前
技术演进中的开发沉思-38 MFC系列:关于打印
c++·mfc
wait a minutes7 小时前
【c++】200*200 01灰度矩阵求所有的连通区域坐标集合
c++·矩阵·深度优先
chilavert3187 小时前
技术演进中的开发沉思-41 MFC系列:定制 AppWizard
数据库·c++·windows·mfc
泽02028 小时前
C++11之右值引用与移动语义(提高效率)重要
java·jvm·c++