倚竹听雨 发表于 2018-6-1 13:25:20

MFC串口通信的一些小问题

小白一枚,最近用MFC写了一个串口通信,但是存在一个bug,当我发送一个正常的完整的数据时,程序不会有问题。但是当我先发送一个不完整的数据,再发送完整的数据,他就无法接收到数据了,估摸着是缓存变量没有清空的原因,但是不知道怎么处理这个问题。清0操作不起左右,有大神帮我一下吗
发送的数据格式是这样的>+123456+223456+323456+423456+523456+623456+723456+823456
附件上传失败,把代码贴出来

// SerialConnectionDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "SerialConnection.h"
#include "SerialConnectionDlg.h"
#include "afxdialogex.h"
#include <string.h>
using namespace std;



#ifdef _DEBUG
#define new DEBUG_NEW
#endif



INPKG pkg;
CTRLPKG ctrlpkg;
/* CRC高位字节值表*/
/* CRC高位字节值表*/
UCHAR CrcHi[] = {
       
};

/* CRC低位字节值表*/
UCHAR CrcLo[] = {
       
};


CSerialPort m_SerialPort;
BOOL m_bPortOpen;

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
        CAboutDlg();

// 对话框数据
        enum { IDD = IDD_ABOUTBOX };

        protected:
        virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
        DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
        CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CSerialConnectionDlg 对话框



CSerialConnectionDlg::CSerialConnectionDlg(CWnd* pParent /*=NULL*/)
        : CDialogEx(CSerialConnectionDlg::IDD, pParent)
        , m_Edit_Receive(_T(""))
        , m_Edit_Send(_T(""))
        , m_ncombo1(_T(""))
        , m_ncombo2(_T(""))
        , m_ncombo3(_T(""))
        , m_1(_T(""))
        , m_2(_T(""))
        , m_3(_T(""))
        , m_4(_T(""))
        , m_5(_T(""))
        , m_6(_T(""))
        , m_7(_T(""))
        , m_8(_T(""))
{
        m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CSerialConnectionDlg::DoDataExchange(CDataExchange* pDX)
{
        CDialogEx::DoDataExchange(pDX);
        DDX_Text(pDX, IDC_EDIT_Rev, m_Edit_Receive);
        DDX_Text(pDX, IDC_EDIT_Rep, m_Edit_Send);
        DDX_Control(pDX, IDC_COMBO1, m_combo1);
        DDX_Control(pDX, IDC_COMBO2, m_combo2);
        DDX_CBString(pDX, IDC_COMBO1, m_ncombo1);
        DDX_CBString(pDX, IDC_COMBO2, m_ncombo2);
        DDX_Control(pDX, IDC_COMBO3, m_combo3);
        DDX_Control(pDX, IDC_COMBO4, m_combo4);
        DDX_Control(pDX, IDC_COMBO5, m_combo5);
        DDX_CBString(pDX, IDC_COMBO3, m_ncombo3);
        DDX_Text(pDX, IDC_EDIT_show1, m_1);
        DDX_Text(pDX, IDC_EDIT_show2, m_2);
        DDX_Text(pDX, IDC_EDIT_show3, m_3);
        DDX_Text(pDX, IDC_EDIT_show4, m_4);
        DDX_Text(pDX, IDC_EDIT_show5, m_5);
        DDX_Text(pDX, IDC_EDIT_show6, m_6);
        DDX_Text(pDX, IDC_EDIT_show7, m_7);
        DDX_Text(pDX, IDC_EDIT_show8, m_8);
}

BEGIN_MESSAGE_MAP(CSerialConnectionDlg, CDialogEx)
        ON_WM_SYSCOMMAND()
        ON_WM_PAINT()
        ON_WM_QUERYDRAGICON()

        ON_MESSAGE(WM_COMM_RXCHAR,OnComm)

        //ON_BN_CLICKED(IDC_BUTTON_OPEN,&CSerialConnectionDlg)

        ON_BN_CLICKED(IDC_BUTTON_OPEN, &CSerialConnectionDlg::OnBnClickedButtonOpen)
        ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CSerialConnectionDlg::OnBnClickedButtonClose)
        ON_BN_CLICKED(IDC_BUTTON_SEND, &CSerialConnectionDlg::OnBnClickedButtonSend)
        ON_BN_CLICKED(IDC_BUTTON_CLEAN, &CSerialConnectionDlg::OnBnClickedButtonClean)
//        ON_EN_CHANGE(IDC_EDIT_Rev, &CSerialConnectionDlg::OnEnChangeEditRev)
//ON_EN_CHANGE(IDC_EDIT_Rev, &CSerialConnectionDlg::OnEnChangeEditRev)
ON_WM_TIMER()
ON_BN_CLICKED(IDC_BUTTON1, &CSerialConnectionDlg::OnBnClickedButton1)
ON_EN_CHANGE(IDC_EDIT_Rev, &CSerialConnectionDlg::OnEnChangeEditRev)
ON_EN_CHANGE(IDC_EDIT_show3, &CSerialConnectionDlg::OnEnChangeEditshow3)
END_MESSAGE_MAP()


// CSerialConnectionDlg 消息处理程序

BOOL CSerialConnectionDlg::OnInitDialog()
{
        CDialogEx::OnInitDialog();

        // 将“关于...”菜单项添加到系统菜单中。

        // IDM_ABOUTBOX 必须在系统命令范围内。
        ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
        ASSERT(IDM_ABOUTBOX < 0xF000);

        CMenu* pSysMenu = GetSystemMenu(FALSE);
        if (pSysMenu != NULL)
        {
                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:在此添加额外的初始化代码
        //初始化端口
        m_combo1.AddString(_T("COM1"));
        m_combo1.AddString(_T("COM2"));
        m_combo1.AddString(_T("COM3"));
        m_combo1.AddString(_T("COM4"));
        m_combo1.AddString(_T("COM5"));
        m_combo1.AddString(_T("COM6"));
        m_combo1.AddString(_T("COM7"));
        m_combo1.AddString(_T("COM8"));
        m_combo1.AddString(_T("COM9"));
        m_combo1.AddString(_T("COM10"));
        m_combo1.SetCurSel(1);
        //初始化波特率
        m_combo2.AddString(_T("1200"));
        m_combo2.AddString(_T("2400"));
        m_combo2.AddString(_T("4800"));
        m_combo2.AddString(_T("9600"));
        m_combo2.AddString(_T("19200"));
        m_combo2.AddString(_T("38400"));
        m_combo2.AddString(_T("57600"));
        m_combo2.SetCurSel(3);
        //初始化校验位
        m_combo3.AddString(_T("NONE"));
        m_combo3.AddString(_T("EVEN"));
        m_combo3.AddString(_T("ODD"));
        m_combo3.SetCurSel(0);
        //初始化数据位
        m_combo4.AddString(_T("7"));
        m_combo4.AddString(_T("8"));
        m_combo4.SetCurSel(1);
        //初始化停止位
        m_combo5.AddString(_T("1"));
        m_combo5.AddString(_T("2"));
        m_combo5.SetCurSel(0);
       
        GetDlgItem(IDC_BUTTON_OPEN)->EnableWindow(TRUE);//把窗口中的 打开串口 设置为可操作状态
        GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(FALSE);//把窗口中的 退出 设置为不可操作状态

        SetTimer(1, 1000, NULL);
        return TRUE;// 除非将焦点设置到控件,否则返回 TRUE
}


//添加的在对话框cpp文件中加入函数OnComm()的实现
LRESULT CSerialConnectionDlg::OnComm(WPARAM ch, LPARAM port){
        CStringArray road;
        recvBuf = ch;
        s.Format("%s", recvBuf);
        a += s;
        s = "";
        CString aa;
        char fbuff = { 0 };
        memcpy(fbuff, a, 58);

        if (fbuff == '>'&&fbuff == '\r'&&recvIndex == 58){ //开始符号一直+结束符一致+长度一致
                fbuff = 0x00;   
                for (int i = 1; i < recvIndex-1; i++){//跳过> 减去'\r'
                       
                        if (fbuff == '+'){
                                aa += " ";               
                        }
                        else{
                                aa += fbuff;
                        }
                }
                if (recvIndex == 58){//
                        recvIndex = 0;
                        a = "";
                }
                m_Edit_Receive = aa;
                CString temp = aa;
                int s0 = temp.ReverseFind(' ');
                road.Add(temp.Mid(s0 + 1));

                while (s0 > 0)
                {
                        temp = temp.Mid(0, s0);
                        s0 = temp.ReverseFind(' ');
                        road.Add(temp.Mid(s0 + 1));
                }
                m_8 = road.GetAt(0);
                m_7 = road.GetAt(1);
                m_6 = road.GetAt(2);
                m_5 = road.GetAt(3);
                m_4 = road.GetAt(4);
                m_3 = road.GetAt(5);
                m_2 = road.GetAt(6);
                m_1 = road.GetAt(7);       
        }
       
       UpdateData(FALSE);
        return 0;
}


       



       




void CSerialConnectionDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
        if ((nID & 0xFFF0) == IDM_ABOUTBOX)
        {
                CAboutDlg dlgAbout;
                dlgAbout.DoModal();
        }
        else
        {
                CDialogEx::OnSysCommand(nID, lParam);
        }
}


// 如果向对话框添加最小化按钮,则需要下面的代码
//来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//这将由框架自动完成。

void CSerialConnectionDlg::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 CSerialConnectionDlg::OnQueryDragIcon()
{
        return static_cast<HCURSOR>(m_hIcon);
}


//打开串口操作
void CSerialConnectionDlg::OnBnClickedButtonOpen()
{
        // TODO:在此添加控件通知处理程序代码
        int SelPort, SelBaudRate, SelDataBits, SelStopBits;
        char SelParity;
        SelPort = m_combo1.GetCurSel() + 1;
        SelStopBits = m_combo5.GetCurSel() + 1;
        SelDataBits = m_combo4.GetCurSel() + 7;
        UpdateData(TRUE);
       
        SelBaudRate = _ttoi(m_ncombo2);//字符型转整型atoi和_ttoi
        SelParity = m_ncombo3.GetAt(0);//获得数据位:GetAt返回的是字符串的第一个字符值
        if (m_SerialPort.InitPort(this,SelPort,SelBaudRate,SelParity,SelDataBits,SelStopBits)){
                m_SerialPort.StartMonitoring();//启动串口通信检测函数
                m_bPortOpen = TRUE;//指示串口已经打开
                UpdateData(FALSE);
                AfxMessageBox(_T("端口已打开"));
                //SetTimer(1, 1000, NULL);
        }
        else
        {
                AfxMessageBox(_T("端口被占用"));
                //GetDlgItem(IDC_BUTTON_OPEN)->EnableWindow(TRUE);
        }
        GetDlgItem(IDC_BUTTON_OPEN)->EnableWindow(FALSE);
        GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(TRUE);

       
}


void CSerialConnectionDlg::OnBnClickedButtonClose()
{
        // TODO:在此添加控件通知处理程序代码
        m_bPortOpen = FALSE;
        GetDlgItem(IDC_BUTTON_OPEN)->EnableWindow(!m_bPortOpen);//使能打开串口按钮
       
        //CSerialConnectionDlg::OnClose();
        m_SerialPort.ClosePort();
        AfxMessageBox(_T("端口已关闭"));
        //KillTimer(1);
}


void CSerialConnectionDlg::OnBnClickedButtonSend()
{
        // TODO:在此添加控件通知处理程序代码
        if (!m_bPortOpen){//检测串口是否打开
               
                AfxMessageBox("串口未打开");
                return ;
        }
        else//打开执行以下
        {
                UpdateData(TRUE);// 读入编辑框的数据(把编辑框中字符写入变量)
               
        /*        unsigned char a = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00 };
                USHORT crc = crc16(a, 6);
                a = crc >> 8;
                a = crc & 0xff;*/
               
                unsigned char a = {0x23,0x30,0x37,0x0d};

                m_SerialPort.WriteBin2Port(a, 4);
                //m_SerialPort.WriteToPort(m_Edit_Send.GetBuffer(0));//调用函数发送数据*********************************************************************************
               
                //SetTimer(1, 1000, NULL);
                //m_SerialPort.WriteToPort();
        }
}


void CSerialConnectionDlg::OnBnClickedButtonClean()
{
        // TODO:在此添加控件通知处理程序代码
        SetDlgItemText(IDC_EDIT_Rev, NULL);//清空接收框消息
        SetDlgItemText(IDC_EDIT_show1, NULL);
        SetDlgItemText(IDC_EDIT_show2, NULL);
        SetDlgItemText(IDC_EDIT_show3, NULL);
        SetDlgItemText(IDC_EDIT_show4, NULL);
        SetDlgItemText(IDC_EDIT_show5, NULL);
        SetDlgItemText(IDC_EDIT_show6, NULL);
        SetDlgItemText(IDC_EDIT_show7, NULL);
        SetDlgItemText(IDC_EDIT_show8, NULL);
        UpdateData(TRUE);
}

//CRC校验

USHORT CSerialConnectionDlg::crc16(UCHAR *updata, UINT len)
{
        UCHAR uchCRCHi = 0xff;
        UCHAR uchCRCLo = 0xff;
        UINTuindex;
        while (len--)
        {
                uindex = uchCRCHi^*updata++;
                uchCRCHi = uchCRCLo^CrcHi;
                uchCRCLo = CrcLo;
        }
        return (uchCRCHi << 8 | uchCRCLo);
}


void CSerialConnectionDlg::OnTimer(UINT_PTR nIDEvent)
{
        // TODO:在此添加消息处理程序代码和/或调用默认值
          
                switch (nIDEvent)
                {
                case 1:
                {
                        if (send == 1)
                        {
                                send = 0;
                                recvIndex = 0;//清空数据长度
                                unsigned char a = { 0x23, 0x30, 0x37, 0x0d };

                                m_SerialPort.WriteBin2Port(a, 4);
                                /******************MODBUS发送**************************/
                                /*unsigned char a = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00 };
                                USHORT crc = crc16(a, 6);
                                a = crc >> 8;
                                a = crc & 0xff;
                                m_SerialPort.WriteBin2Port(a, 8);*/
                                SetTimer(2, 5000, NULL);
                        }
                        break;
                }


                case 2:
                        send = 1;
                        KillTimer(2);

                }


                CDialogEx::OnTimer(nIDEvent);

        }


void CSerialConnectionDlg::OnBnClickedButton1()
{
        // TODO:在此添加控件通知处理程序代码
       
        OnOK();
}


void CSerialConnectionDlg::OnEnChangeEditRev()
{
        // TODO:如果该控件是 RICHEDIT 控件,它将不
        // 发送此通知,除非重写 CDialogEx::OnInitDialog()
        // 函数并调用 CRichEditCtrl().SetEventMask(),
        // 同时将 ENM_CHANGE 标志“或”运算到掩码中。

        // TODO:在此添加控件通知处理程序代码
}


void CSerialConnectionDlg::OnEnChangeEditshow3()
{
        // TODO:如果该控件是 RICHEDIT 控件,它将不
        // 发送此通知,除非重写 CDialogEx::OnInitDialog()
        // 函数并调用 CRichEditCtrl().SetEventMask(),
        // 同时将 ENM_CHANGE 标志“或”运算到掩码中。

        // TODO:在此添加控件通知处理程序代码
}
页: [1]
查看完整版本: MFC串口通信的一些小问题