MFC基于API写的串口通信

程序流程:打开串口——>发送数据——>接收数据——>关闭串口

第一步打开串口按钮

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();
};

  • 0
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值