程序流程:打开串口——>发送数据——>接收数据——>关闭串口
第一步打开串口按钮
void CSerialAssistantDlg::OnBnClickedButtonOpenSerial()
{
// TODO: 在此添加控件通知处理程序代码
CString CButtonOpenText;// 定义字符串,用于存储获取的编辑框文本
GetDlgItemText(IDC_BUTTON_OPEN_SERIAL, CButtonOpenText); //获取给发送编辑框的文本
//关闭串口
if (CButtonOpenText == _T("关闭串口"))//当按钮为关闭串口的时候,点击按钮关闭串口并更改控件文本为打开串口
{
CButtonOpenText = _T("打开串口");/*//改变按钮名称为打开串口*/
UpdateData(true); //刷新数据,UpdateData(TRUE) == 将控件的值赋值给成员变量
m_CButtonOpenSerial.SetWindowText(CButtonOpenText); //m_CButtonOpenSerial打开串口按钮的关联变量,/改变按钮名称为打开串口*/
CancelSynchronousIo(this->m_CButtonOpenSerial); //取消指定线程发出的同步 I / O 操作的标记。
DWORD dwError = GetLastError();//获取错误信息
CloseHandle(m_hHandle);//关闭串口
m_hHandle = INVALID_HANDLE_VALUE;
return;
}
m_CComboBoxSerial.GetLBText(m_CComboBoxSerial.GetCurSel(), m_ComboItemSerialText);//m_ComboItemSerialText自定义CString类型变量,用于存放串口下拉列表框选中的项的控件文本
m_hHandle = CreateFile(m_ComboItemSerialText, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);//打开串口
m_hHandle:自定义的HANDLE类型的变量,用于存放打开串口返回的句柄
if (m_hHandle == (HANDLE)INVALID_FILE_SIZE)
{
MessageBox(TEXT("端口打开失败")); // 报告端口打开失败
return;
}
else if (m_hHandle != INVALID_HANDLE_VALUE)
{
// 设置端口参数
//设置波特率
m_CComboBoxBaudRate.GetLBText(m_CComboBoxBaudRate.GetCurSel(), m_ComboItemBaudRateText); //串口下拉列表框选中的项的控件文本
myDCB.BaudRate = (DWORD) &m_ComboItemBaudRateText;//myDCB:自定义的DCB结构的对象,详细信息可查看DCB结构
myDCB.fParity = true; // 奇偶校验 TRUE=使用,FALSE=不使用
//设置校验位
myDCB.Parity = m_CComboBoxBaudRate.GetCurSel(); // 校验方式:0-无 1-奇 2-偶 3-标志 4-空格
int nFindNumShuJuWei = m_CComboBoxDataBit.GetCurSel();
switch (nFindNumShuJuWei)
{
case 0:
myDCB.ByteSize = 4; // 数据位数
break;
case 1:
myDCB.ByteSize = 5; // 数据位数
break;
case 2:
myDCB.ByteSize = 6; // 数据位数
break;
case 3:
myDCB.ByteSize = 7; // 数据位数
break;
case 4:
myDCB.ByteSize = 8; // 数据位数
break;
default: MessageBox(NULL, TEXT("未选择数位数"));
break;
}
int nFindNumTinZhiWei = m_CComboBoxStopBit.GetCurSel();
switch (nFindNumTinZhiWei)
{
case 0:
myDCB.StopBits = 1; // 停止位数:0-1位 1-1.5位 2-2位
break;
case 1:
myDCB.StopBits = 1.5; // 停止位数:0-1位 1-1.5位 2-2位
break;
case 2:
myDCB.StopBits = 2; // 停止位数:0-1位 1-1.5位 2-2位
break;
default: MessageBox(NULL, TEXT("未选择停止位数"));
break;
}
UpdateData(FALSE);
}
SetCommState(m_hHandle, &myDCB);//设置串口配置
PurgeComm(m_hHandle, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
if (CButtonOpenText == _T("打开串口"))//打开串口成功后,改变按钮名称为关闭串口
{
CButtonOpenText = _T("关闭串口");
UpdateData(true); //将控件的状态传给其关联的变量
m_CButtonOpenSerial.SetWindowText(CButtonOpenText); //改变按钮名称为关闭串口
//OnEnChangeEditReceive();
m_CEditReceive.SetTimer(1, 100, NULL);
m_hHandleMainWindow = AfxGetMainWnd()->m_hWnd;//获取主窗口句柄并存放于HANDLE类型的自定义变量m_hHandleMainWindow
m_handleMyThread = CreateThread(NULL, 0, receive,&m_hHandleMainWindow,0, NULL);//创建线程,用于循环唤醒接收数据函数(可用定时器代替)
}
else
{
// 设置失败
MessageBox(NULL, TEXT("设置出现错误,导致端口打开失败")); // 报告端口打开失败
return;
}
}
2、手动发送数据
// TODO: 在此添加控件通知处理程序代码
m_CEditSend.GetWindowText(m_SendText);//获取控件文本
LPDWORD writeaddr = 0;
DWORD dwBytesWrite = 100;
char strTEXT[1024] = { 0 };
for (int i = 0; i < m_SendText.GetLength(); i++)
{
strTEXT[i] = (char)m_SendText.GetAt(i);
}
//发送数据
WriteFile(m_hHandle, strTEXT, m_SendText.GetLength() + 3, &dwBytesWrite, NULL);
// MessageBox(m_SendText);//测试代码,结果:文本获取没有问题,发送出去时会出现问题,中文字符无法发出显示
}
3、接收数据(具体实现路线:点击打开串口按钮后,创建线程,执行回调函数,循环给主窗口的自定义函数发送消息,调用自定义函数)
线程的回调函数
DWORD WINAPI receive(LPVOID pParam)//名称可以更改,但是其他参数建议不修改,如需传输多个数据,可定义一个结构体,直接传结构体变量
{
HWND m_hHandle = *(HWND*)pParam;
while (1)
{
int i = SendMessage(m_hHandle, UM_MSG_CUSTOM_RECEIVE, NULL, NULL);
//UM_MSG_CUSTOM_RECEIVE为自定义消息
//m_hHandle为传入的主窗口句柄
Sleep(2000);
}
return 0;
}
4、自定义消息(具体的详细教程,可自行查找,这个不难)
第一步:
Dlg.cpp文件的开头,加入以下代码,
#define UM_MSG_CUSTOM_RECEIVE (WM_USER+1000)
第二步:在Dlg.h头文件,加入以下代码,声明自定义的函数
afx_msg LRESULT OnEnChangeEditCustomReception(WPARAM WParam, LPARAM LParam);
第三步:将你的函数跟消息关联起来(代码如下)
ON_MESSAGE(UM_MSG_CUSTOM_RECEIVE, OnEnChangeEditCustomReception)
第四步:实现你的自定义函数
LRESULT CSerialAssistantDlg::OnEnChangeEditCustomReception(WPARAM WParam, LPARAM LParam)
{
BOOL bResult = 0;
DWORD dwError = 0;
DWORD BytesRead = 0;
char strRX[1024] = { 0 };
COMSTAT ComStat;
ClearCommError(m_hHandle, &dwError, &ComStat);//清空缓冲区
if (ComStat.cbInQue > 0)//判断缓冲区是否有数据
{
bResult = ReadFile(m_hHandle, strRX, ComStat.cbInQue, &BytesRead, NULL);//读取缓存区
if (bResult)
{
m_strRXData += strRX;
m_strRXData += "\r\n";
UpdateData(FALSE);
}
m_CEditReceive.SetWindowTextW(m_strRXData);//m_CEditReceive显示编辑框的关联变量
}
return 1;
}
各变量的定义如下:(如果对代码的变量有不理解的可参考以下代码,辅助理解)
class CSerialAssistantDlg : public CDialogEx
{
// 构造
public:
CSerialAssistantDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_SERIALASSISTANT_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()
private:
CString m_ComboItemSerialText;//串口下拉列表框选择的项
CString m_ComboItemBaudRateText;//波特率下拉列表框选择的项
CString m_ComboItemCheckBitsText;//校验位下拉列表框选择的项
CString m_ComboItemDataBitText;//数据位下拉列表框选择的项
CString m_ComboItemStopBitText;//停止位下拉列表框选择的项
HANDLE m_hHandle; //串口句柄
HANDLE m_hHandleMainWindow; //主窗口句柄
DCB myDCB;//配置串口的结构体
CString m_SendText; //手动发送要发出的文本
HANDLE m_handleMyThread;
CString m_strRXData;
CString m_ReceiveText;
public:
afx_msg void OnBnClickedButtonOpenSerial();
// 串口下拉列表框关联变量
CComboBox m_CComboBoxSerial;
// 波特率下拉列表框关联变量
CComboBox m_CComboBoxBaudRate;
// 校验位下拉列表框关联变量
CComboBox m_CComboBoxCheckBits;
// 数据位下拉列表框关联变量
CComboBox m_CComboBoxDataBit;
// 停止位下拉列表框关联变量
CComboBox m_CComboBoxStopBit;
// 打开串口按钮关联变量
CButton m_CButtonOpenSerial;
// 手动发送按钮关联变量
CButton m_CButtonSend;
afx_msg void OnBnClickedButtonSend();
// 发送数据编辑框关联变量
CEdit m_CEditSend;
afx_msg void OnEnChangeEditReceive();
afx_msg LRESULT OnEnChangeEditCustomReception(WPARAM WParam, LPARAM LParam);
// 数据接收编辑款关联变量
CEdit m_CEditReceive;
afx_msg void OnBnClickedButtonClear();
afx_msg void OnBnClickedButtonClearSend();
afx_msg void OnBnClickedMfclink2();
afx_msg void OnBnClickedMfclinkMail();
};