一、目标
实现串口通信的上位机。
二、使用步骤
1.打开串口
头文件.h中
public:
//自定义变量
HANDLE m_hCom; //串口句柄
volatile int m_bConnected; //串口连接成功指示
public:
//串口相关函数
BOOL OpenComm(int Num); //打开串口函数
源文件.cpp中
BOOL CSerialPortDlg::OnInitDialog()
{
...
// TODO: 在此添加额外的初始化代码
//设串口组合列表框
TCHAR com[][6] = { "COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9" };
for (int i = 0; i < 9; i++)
m_Combo_Com.AddString(com[i]);
m_Combo_Com.SetCurSel(0);
//设波特率组合列表框
TCHAR baud[][7] = { "300","600","1200","2400","4800","9600","19200","38400","43000","56000","57600","115200","128000","230400" };
for (int i = 0; i < 14; i++)
m_Combo_Baud.AddString(baud[i]);
m_Combo_Baud.SetCurSel(5);
//设校验位组合列表框
TCHAR check[][7] = { "None","Odd","Even" };
for (int i = 0; i < 3; i++)
m_Combo_Check.AddString(check[i]);
m_Combo_Check.SetCurSel(0);
//设数据位组合列表框
TCHAR data[][2] = { "8","7","6" };
for (int i = 0; i < 3; i++)
m_Combo_Data.AddString(data[i]);
m_Combo_Data.SetCurSel(0);
//设停止位组合列表框
TCHAR stop[][2] = { "1","2" };
for (int i = 0; i < 2; i++)
m_Combo_Stop.AddString(stop[i]);
m_Combo_Stop.SetCurSel(0);
//打开串口函数赋初值
OpenComm(0);
}
//打开串口函数。
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("打开串口失败!"); //失败时弹出对话框提醒
m_bConnected = 0; //将串口连接标志设为0
return FALSE; //打开失败后不再继续往下进行,直接返回FALSE
}
m_bConnected = 1; //将串口连接标志设为1
return 0;
}
2.设置串口
头文件.h中
public:
//串口相关函数
BOOL SetCommParameter(); //设置串口参数
源文件.cpp中
//设置串口参数
BOOL CSerialPortDlg::SetCommParameter()
{
DCB dcb; //DCB结构,定义了串口通信设备的控制设置
if (!GetCommState(m_hCom, &dcb))
//读取新创建的 m_hCom串口句柄的 DCB设备控制块结构体,当只需要设置一部分 DCB参数时,可以通过此函数读取现有参数,只改变部分参数即可
return FALSE; //如果读取不成功直接结束
//设置波特率
long baudrate[] = { 300,600,1200,2400,4800,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.显示串口状态
头文件.h中
void DisplayStatus(); //显示串口状态
源文件.cpp中
//显示串口状态
void CSprDlg::DisplayStatus()
{
CWnd* static_status = GetDlgItem(IDC_STATIC_COMSTATU);
CWnd* static_txlen = GetDlgItem(IDC_STATIC_TXLEN);
CWnd* static_rxlen = GetDlgItem(IDC_STATIC_RXLEN);
CString status_str, txlen_str, rxlen_str;
if (m_bConnected)
{
status_str = "STATUS:" + m_Str_Com + " OPENED," + m_Str_Baud + ',' + m_Str_Check + ',' + m_Str_Data + ',' + m_Str_Stop;
SetCommParameter();
}
else
status_str = "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("TX:%ld", m_txlen);
static_txlen->SetWindowText(txlen_str);
rxlen_str.Format("RX:%ld", m_rxlen);
static_rxlen->SetWindowText(rxlen_str);
}
3.关闭串口
头文件.h中
public:
//串口相关函数
void CloseConnection(); //关闭串口
源文件.cpp中
//关闭串口
void CSerialPortDlg::CloseConnection()
{
if (!m_bConnected)
return;
m_bConnected = FALSE;
SetCommMask(m_hCom, 0);
CloseHandle(m_hCom);
}
3.串口设置更改事件
头文件.h中
public:
//列表框函数
afx_msg void OnSelchangeComboCOM(); //更改串口
afx_msg void OnSelchangeComboBaud(); //更改波特率
afx_msg void OnSelchangeComboCheck(); //更改校验位
afx_msg void OnSelchangeComboData(); //更改数据位
afx_msg void OnSelchangeComboStop(); //更改停止位
源文件.cpp中
//更改串口
void CSprDlg::OnCbnSelchangeComboCom()
{
// TODO: 在此添加控件通知处理程序代码
if (m_bConnected)
CloseConnection();
if (m_COMStatu)
{
int i = m_Combo_Com.GetCurSel();
OpenComm(i);
}
DisplayStatus();
}
//更改波特率
void CSprDlg::OnCbnSelchangeComboBaud()
{
// TODO: 在此添加控件通知处理程序代码
int baudindex;
baudindex = m_Combo_Baud.GetCurSel();
if (baudindex != CB_ERR)
{
SetCommParameter();
m_Combo_Baud.GetLBText(baudindex, m_Str_Baud);
}
DisplayStatus();
}
//更改校验位
void CSprDlg::OnCbnSelchangeComboCheck()
{
// TODO: 在此添加控件通知处理程序代码
int checkindex;
checkindex = m_Combo_Check.GetCurSel();
if (checkindex != CB_ERR)
{
SetCommParameter();
m_Combo_Check.GetLBText(checkindex, m_Str_Check);
DisplayStatus();
}
}
//更改数据位
void CSprDlg::OnCbnSelchangeComboData()
{
// TODO: 在此添加控件通知处理程序代码
int dataindex;
dataindex = m_Combo_Data.GetCurSel();
if (dataindex != CB_ERR)
{
SetCommParameter();
m_Combo_Data.GetLBText(dataindex, m_Str_Data);
DisplayStatus();
}
}
//更改停止位
void CSprDlg::OnCbnSelchangeComboStop()
{
// TODO: 在此添加控件通知处理程序代码
int stopindex;
stopindex = m_Combo_Stop.GetCurSel();
if (stopindex != CB_ERR)
{
SetCommParameter();
m_Combo_Stop.GetLBText(stopindex, m_Str_Stop);
DisplayStatus();
}
}
4.打开关闭串口按钮
头文件.h中
public:
//按钮函数
afx_msg void OnButtonCOMstatu(); //串口状态显示
源文件.cpp中
//串口状态显示
void CSprDlg::OnBnClickedButtonOpencom()
{
TODO: 在此添加控件通知处理程序代码
m_COMStatu = !m_COMStatu;
if (!m_COMStatu)
GetDlgItem(IDC_BUTTON_OPENCOM)->SetWindowText("串口打开");
else
GetDlgItem(IDC_BUTTON_OPENCOM)->SetWindowText("串口关闭");
OnCbnSelchangeComboCom();
DisplayStatus();
return;
}
三、完整代码
头文件.h中
//变量=====================================================================================
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 OnBnClickedButtonOpencom(); //串口状态显示
//列表框函数
afx_msg void OnCbnSelchangeComboCom(); //更改串口
afx_msg void OnCbnSelchangeComboBaud(); //更改波特率
afx_msg void OnCbnSelchangeComboCheck(); //更改校验位
afx_msg void OnCbnSelchangeComboData(); //更改数据位
afx_msg void OnCbnSelchangeComboStop(); //更改停止位
};
源文件.cpp中
===========================================初始化对话框===========================================
//初始化对话框
BOOL CSprDlg::OnInitDialog()
{
// TODO: 在此添加额外的初始化代码
//设串口组合列表框
TCHAR com[][6] = { "COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9" };
for (int i = 0; i < 9; i++)
m_Combo_Com.AddString(com[i]);
m_Combo_Com.SetCurSel(0);
//设波特率组合列表框
TCHAR baud[][7] = { "300","600","1200","2400","4800","9600","19200","38400","43000","56000",
"57600","115200","128000","230400" };
for (int i = 0; i < 14; i++)
m_Combo_Baud.AddString(baud[i]);
m_Combo_Baud.SetCurSel(11);
//设校验位组合列表框
TCHAR check[][7] = { "N","O","E" };
for (int i = 0; i < 3; i++)
m_Combo_Check.AddString(check[i]);
m_Combo_Check.SetCurSel(0);
//设数据位组合列表框
TCHAR data[][2] = { "8","7","6" };
for (int i = 0; i < 3; i++)
m_Combo_Data.AddString(data[i]);
m_Combo_Data.SetCurSel(0);
//设停止位组合列表框
TCHAR stop[][2] = { "1","2" };
for (int i = 0; i < 2; i++)
m_Combo_Stop.AddString(stop[i]);
m_Combo_Stop.SetCurSel(0);
OpenComm(0);
return TRUE;
}
==============================================打开串口==============================================
//打开串口
BOOL CSprDlg::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("打开串口失败!"); //失败时弹出对话框提醒
m_bConnected = 0; //将串口连接标志设为0
return FALSE; //打开失败后不再继续往下进行,直接返回FALSE
}
m_bConnected = 1;
return 0;
}
============================================显示串口状态============================================
//显示串口状态
void CSprDlg::DisplayStatus()
{
CWnd* static_status = GetDlgItem(IDC_STATIC_COMSTATU);
CWnd* static_txlen = GetDlgItem(IDC_STATIC_TXLEN);
CWnd* static_rxlen = GetDlgItem(IDC_STATIC_RXLEN);
CString status_str, txlen_str, rxlen_str;
if (m_bConnected)
{
status_str = "STATUS:" + m_Str_Com + " OPENED," + m_Str_Baud + ',' + m_Str_Check + ',' + m_Str_Data + ',' + m_Str_Stop;
SetCommParameter();
}
else
status_str = "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("TX:%ld", m_txlen);
static_txlen->SetWindowText(txlen_str);
rxlen_str.Format("RX:%ld", m_rxlen);
static_rxlen->SetWindowText(rxlen_str);
}
==============================================关闭串口==============================================
//关闭串口
void CSprDlg::CloseConnection()
{
if (!m_bConnected)
return;
m_bConnected = FALSE;
SetCommMask(m_hCom, 0);
CloseHandle(m_hCom);
}
==============================================设置串口参数==============================================
//设置串口参数
BOOL CSprDlg::SetCommParameter()
{
DCB dcb;
if (!GetCommState(m_hCom, &dcb))
return FALSE;
//设置波特率
long baudrate[] = { 300,600,1200,2400,4800,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;
dcb.fBinary = TRUE;
dcb.fParity = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
return(SetCommState(m_hCom, &dcb));
}
==========================================串口开关按钮状态显示==========================================
//串口状态显示
void CSprDlg::OnBnClickedButtonOpencom()
{
TODO: 在此添加控件通知处理程序代码
m_COMStatu = !m_COMStatu;
if (!m_COMStatu)
GetDlgItem(IDC_BUTTON_OPENCOM)->SetWindowText("串口打开");
else
GetDlgItem(IDC_BUTTON_OPENCOM)->SetWindowText("串口关闭");
OnCbnSelchangeComboCom();
DisplayStatus();
return;
}
==============================================更改串口设置==============================================
//更改串口
void CSprDlg::OnCbnSelchangeComboCom()
{
// TODO: 在此添加控件通知处理程序代码
if (m_bConnected)
CloseConnection();
if (m_COMStatu)
{
int i = m_Combo_Com.GetCurSel();
OpenComm(i);
}
DisplayStatus();
}
//更改波特率
void CSprDlg::OnCbnSelchangeComboBaud()
{
// TODO: 在此添加控件通知处理程序代码
int baudindex;
baudindex = m_Combo_Baud.GetCurSel();
if (baudindex != CB_ERR)
{
SetCommParameter();
m_Combo_Baud.GetLBText(baudindex, m_Str_Baud);
}
DisplayStatus();
}
//更改校验位
void CSprDlg::OnCbnSelchangeComboCheck()
{
// TODO: 在此添加控件通知处理程序代码
int checkindex;
checkindex = m_Combo_Check.GetCurSel();
if (checkindex != CB_ERR)
{
SetCommParameter();
m_Combo_Check.GetLBText(checkindex, m_Str_Check);
DisplayStatus();
}
}
//更改数据位
void CSprDlg::OnCbnSelchangeComboData()
{
// TODO: 在此添加控件通知处理程序代码
int dataindex;
dataindex = m_Combo_Data.GetCurSel();
if (dataindex != CB_ERR)
{
SetCommParameter();
m_Combo_Data.GetLBText(dataindex, m_Str_Data);
DisplayStatus();
}
}
//更改停止位
void CSprDlg::OnCbnSelchangeComboStop()
{
// TODO: 在此添加控件通知处理程序代码
int stopindex;
stopindex = m_Combo_Stop.GetCurSel();
if (stopindex != CB_ERR)
{
SetCommParameter();
m_Combo_Stop.GetLBText(stopindex, m_Str_Stop);
DisplayStatus();
}
}