序

确定基本功能:

1.自动寻找串口,并自动添加到下拉框中共选择;

2.有波特率、数据位、停止位、校验位的选择设置;

3.串口打开控制按钮;

4.发送、清除按钮;

5.接收是自动实现的;

6.有定时自动发送功能;

7.有传送文件功能;

8.有状态栏显示,指示串口状态,设置参数和发送接收显示。

下面就一步步实现,本人纯业余,只是记录下来这个学习过程,请勿拍砖。 开发平台Visual Studio 2019社区版,

 

2. 创建MFC项

2.1  打开Visual Studio 2019->创建新项目

 

2.2   选择  MFC应用程序->下一步

 

 

2.3  填写项目名称: commassist  ,选择项目目录 ,点击 创建

 

 

2.4  配置工程

应用程序类型选择:基本对话框

 

 

 

选择最小化,最大化,勾选两个选项

 

 

生成类选择:Dlg

基类:CDialogEx   ,其他选项默认即可,点击  完成

 

项目创建完毕,进入项目。

 

点击进入  “资源视图”  界面,

删除界面上确定和取消按钮以及静态文字。

 

 

 

 

 

 

创建界面

3.1 添加Group Box控件

并且修改两个控件的Caption属性,

上面的GroupBox控件Caption属性改为:接收区

下面的GroupBox控件Caption属性改为:发送区

 

 

 

3.2 添加Static Text控件

如图,从上到下添加5个Static Text控件,并且修改这5个控件的Caption属性

从上到下数:

第1个Static Text控件的Caption属性为:串口号

第2个Static Text控件的Caption属性为:波特率

第3个Static Text控件的Caption属性为:数据位

第4个Static Text控件的Caption属性为:校验位

第5个Static Text控件的Caption属性为:停止位

 

 

 

 

3.3 添加Combo Box控件

在5个Static Text控件的后面分别添加一个Combo Box控件,并且设置属性如下:

从上到下数:

第1个串口号的Combo Box控件:

ID属性:IDC_COMLIST

Sort属性:False

Type属性:下拉列表

 

第2个波特率的Combo Box控件:

ID属性:IDC_BAUD

Type属性:下拉列表

Sort属性:False

Data属性:110;300;600;1200;2400;4800;9600;14400;19200;38400;56000;57600;115200;128000;256000;

 

第3个数据位的Combo Box控件:

ID属性:IDC_BDATA

Type属性:下拉列表

Sort属性:False

Data属性:5;6;7;8;

 

第4个校验位的Combo Box控件:

ID属性:IDC_CAL

Type属性:下拉列表

Sort属性:False

Data属性:None;Odd;Even;Mark;Space;

 

第5个停止位的Combo Box控件:

ID属性:IDC_BSTOP

Type属性:下拉列表

Sort属性:False

Data属性:1;1.5;2;

 

 

 

 

3.4  添加Edit Control控件

在接收区GroupBox控件和发送区Group Box控件中分别添加一个Edit Control。

如图,添加两个Edit Control控件

接收区的Edit Control控件:

ID属性:IDC_EDIT_RX

Multiline属性:True  //可多行显示

Want Return属性:True  //可输入回车换行

Auto  HScroll属性:False

Auto  VScroll属性:True

Modal Frame属性:True

Vertical Scroll属性:True

 

发送区的Edit Control控件:

ID属性:IDC_EDIT_TX

Multiline属性:True

Want Return属性:True

Auto HScroll属性:True

Auto VScroll属性:True

Modal Frame属性:True

Vertical Scroll属性:True

 

 

 

 

3.5  添加按钮控件

添加7个按钮控件,根据图配置按钮控件。

第1个按钮控件:

ID属性:IDC_COMCONTROL

Caption属性:打开串口

 

第2个按钮控件:

ID属性:IDC_BTN_CLRRX

Caption属性:清空显示区

 

第3个按钮控件:

ID属性:IDC_BTN_HANDSEND

Caption属性:手动发送

 

第4个按钮控件:

ID属性:IDC_BTN_CLRTX

Caption属性:清空发送区

 

第5个按钮控件:

ID属性:IDC_BTN_AUTOSEND

Caption属性:自动发送

 

第6个按钮控件:

ID属性:IDC_BTN_SELCTFILE

Caption属性:选择文件

 

第7个按钮控件:

ID属性:IDC_BTN_SENDFILE

Caption属性:发送文件

 

 

 

 

 

 

3.6  添加Check Box控件

如图,添加两个Check Box控件

上面的Check Box控件:

Caption属性:十六进制显示

 

下面的Check Box控件:

Caption属性:十六进制发送

 

 

3.7 添加三个自动发送的控件

第1个控件:Static Text控件

Caption属性:每隔

 

第2个控件:Edit Control控件

ID属性:IDC_EDIT_TIMER

 

第3个控件:Static Control控件

Caption属性:毫秒

 

 

 

3.8  添加选择文件的一个控件

如图,添加一个Edit Control控件

ID属性:IDC_EDIT_FILEPATH

 

 

3.9  添加状态显示Edit Control控件

ID属性:IDC_EDIT_STATUS

Read Only属性:True

 

 

3.10  添加Picture Control控件

ID属性:IDC_STATIC_ICON

Type属性:Icon

Image属性:IDR_MAINFRAME

 

 

 

 

 

3.11  修改外框,添加最小化控件

选中外框,

Minimize Box属性:True

 

 

 

3.12  添加Icon图标

在 资源视图->Icon目录下->添加两个Icon图标

分别命名为IDI_ICON_CLOSE、IDI_ICON_OPEN

 

 

 

 

修改IDR_MAINFRAME图标:

 

3.13  效果图

最终效果图

 

运行时效果图:

 

 

开始写代码

4.1  基本思路

因为串口通信部分代码我可能用在以后的单片机上位机上,因此考虑单独形成CPP和H文件,定义为comm.cpp和comm.h。在comm.cpp中编写串口创建、打开、关闭以及串口监听线程(用于自动接收)的代码,同时加入进制转换或显示的函数,这些在comm.h文件中申明,

在主对话框中包含comm.h即可。想修改按钮样式,在网上搜了一圈,结果不轻松,最后确定创建新类来实现。

 

 

 

4.2  创建自定义按钮类

(1)右击选中项目名->类向导

 

 

 

(2)点击 添加类

 

 

 

 

(3)类名MyButton,基类选择CButton,点击 确定。

 

 

 

 

 

(4)在头文件 MyButton.h 中全部替换为以下变量和函数定义:

 

#if !defined(AFX_MYBUTTON_H__B834D0A9_C834_4584_BC86_9AD8264EB109__INCLUDED_)

#define AFX_MYBUTTON_H__B834D0A9_C834_4584_BC86_9AD8264EB109__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

// MyButton.h : header file

//

 

/////////////////////////////////////////////////////////////////////////////

// MyButton window

 

class MyButton : public CButton

{

 

private:

    int     m_Style; //按钮形状(0-正常,1-当前,2-按下,3-锁定)

    bool b_InRect;   //鼠标进入标志

    CString     m_strText;   //按钮文字

    COLORREF m_ForeColor;//文本颜色

    COLORREF m_MouseInColor;//鼠标进入时文本颜色

    COLORREF m_BackColor;//背景颜色

    COLORREF m_LockForeColor; //锁定按钮的文字颜色

    CRect   m_ButRect;   //按钮尺寸

    CFont* p_Font; //字体

    void DrawButton(CDC* pDC); //画正常按钮

 

// Construction

public:

    MyButton();

    void SetText(CString str); //设置文字

    void SetForeColor(COLORREF color); //设置文本颜色

    void SetBkColor(COLORREF color);       //设置背景颜色

    void SetTextFont(int FontHight, LPCTSTR FontName);  //设置字体

// Attributes

public:

 

    // Operations

public:

 

    // Overrides

        // ClassWizard generated virtual function overrides

        //{{AFX_VIRTUAL(MyButton)

public:

    virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);

protected:

    virtual void PreSubclassWindow();

    //}}AFX_VIRTUAL

 

// Implementation

public:

    virtual ~MyButton();

 

    // Generated message map functions

protected:

    //{{AFX_MSG(MyButton)

    afx_msg void OnNcMouseMove(UINT nHitTest, CPoint point);

    afx_msg void OnNcMButtonDown(UINT nHitTest, CPoint point);

    afx_msg void OnNcMButtonUp(UINT nHitTest, CPoint point);

    //}}AFX_MSG

 

    DECLARE_MESSAGE_MAP()

};

 

/////////////////////////////////////////////////////////////////////////////

 

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

 

#endif // !defined(AFX_MYBUTTON_H__B834D0A9_C834_4584_BC86_9AD8264EB109__INCLUDED_)

 

 

 

(5)MyButton.cpp 中全部替换为下面的代码:

#include "pch.h"

#include "stdafx.h"

#include "commassist.h"

#include "MyButton.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

 

/////////////////////////////////////////////////////////////////////////////

// MyButton

 

MyButton::MyButton()

{

    m_Style = 1; //m_Style = 0;   //按钮形状风格

    b_InRect = false; //鼠标进入标志

    m_strText = _T("");  //按钮文字(使用默认文字)

    m_ForeColor = RGB(200, 0, 0); //文字颜色(黑色)

    m_MouseInColor = RGB(0, 0, 255);   //鼠标进入时文字颜色(蓝色)

    m_BackColor = RGB(200, 200, 230);  //m_BackColor = RGB(243,243,243);      //背景色(灰白色)

    m_LockForeColor = GetSysColor(COLOR_GRAYTEXT);  //锁定按钮的文字颜色

    p_Font = NULL;   //字体指针

 

}

 

MyButton::~MyButton()

{

}

 

 

BEGIN_MESSAGE_MAP(MyButton, CButton)

    //{{AFX_MSG_MAP(MyButton)

    ON_WM_NCMOUSEMOVE()

    ON_WM_NCMBUTTONDOWN()

    ON_WM_NCMBUTTONUP()

    //}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

/////////////////////////////////////////////////////////////////////////////

// MyButton message handlers

 

 

 

void MyButton::PreSubclassWindow()

{

    // TODO: Add your specialized code here and/or call the base class

    ModifyStyle(0, BS_OWNERDRAW);         //设置按钮属性为自画式

    //PreSubclassWindow()在按钮创建前自动执行,所以我们可以在其中做一些初始工作。

    //这里只做了一项工作,就是为按钮设置属性为"自绘"式,这样,用户在添加按钮后,就不需设置"Owner draw"属性了。

    CButton::PreSubclassWindow();

}

 

void MyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)

{

    // TODO: Add your code to draw the specified item

    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

    m_ButRect = lpDrawItemStruct->rcItem;     //获取按钮尺寸

    if (m_strText.IsEmpty())

        GetWindowText(m_strText);           //获取按钮文本

 

    int nSavedDC = pDC->SaveDC();

    VERIFY(pDC);

    DrawButton(pDC);                 //绘制按钮

    pDC->RestoreDC(nSavedDC);

 

}

 

void MyButton::OnNcMouseMove(UINT nHitTest, CPoint point)

{

    // TODO: Add your message handler code here and/or call default

    if (!b_InRect || GetCapture() != this)     //鼠标进入按钮

    {

        b_InRect = true;     //设置进入标志

        SetCapture();        //捕获鼠标

        m_Style = 2; //m_Style = 1;         //设置按钮状态

        Invalidate();        //重绘按钮

    }

    else

    {

        if (!m_ButRect.PtInRect(point))     //鼠标离开按钮

        {

            b_InRect = false;    //清除进入标志

            ReleaseCapture();    //释放捕获的鼠标

            m_Style = 1; //m_Style = 0;         //设置按钮状态

            Invalidate();        //重绘按钮

        }

    }

 

    CButton::OnNcMouseMove(nHitTest, point);

}

 

void MyButton::OnNcMButtonDown(UINT nHitTest, CPoint point)

{

    // TODO: Add your message handler code here and/or call default

    m_Style = 2;

    Invalidate();         //重绘按钮

    CButton::OnLButtonDown(nHitTest, point);

}

 

void MyButton::OnNcMButtonUp(UINT nHitTest, CPoint point)

{

    // TODO: Add your message handler code here and/or call default

    m_Style = 1;

    Invalidate();         //重绘按钮

 

    CButton::OnNcMButtonUp(nHitTest, point);

}

 

void MyButton::DrawButton(CDC* pDC)

{

    //调整状态

    if (m_Style == 3) m_Style = 0;

    if (GetStyle() & WS_DISABLED)

        m_Style = 3;     //禁止状态

    //根据状态调整边框颜色和文字颜色

    COLORREF bColor, fColor;     //bColor为边框颜色,fColor为文字颜色

    switch (m_Style)

    {

    case 0: bColor = RGB(192, 192, 192); fColor = m_ForeColor; break;   //正常按钮

    case 1: bColor = RGB(255, 255, 255); fColor = m_ForeColor; break;   //鼠标进入时按钮

    case 2: bColor = RGB(192, 192, 192); fColor = m_MouseInColor; break;   //按下的按钮

    case 3: bColor = m_BackColor; fColor = m_LockForeColor; break;    //锁定的按钮

    }

    //绘制按钮背景

    CBrush Brush;

    Brush.CreateSolidBrush(m_BackColor);     //背景刷

    pDC->SelectObject(&Brush);

    CPen Pen;

    Pen.CreatePen(PS_SOLID, 3, bColor);

    pDC->SelectObject(&Pen);

    pDC->RoundRect(&m_ButRect, CPoint(10, 10));    //画圆角矩形

    //绘制按钮按下时的边框

    if (m_Style != 2)

    {

        CRect Rect;

        Rect.SetRect(m_ButRect.left + 1, m_ButRect.top + 1, m_ButRect.right, m_ButRect.bottom);

        pDC->DrawEdge(&Rect, BDR_RAISEDINNER, BF_RECT);     //画边框

    }

    //绘制按钮文字

    pDC->SetTextColor(fColor);         //画文字

    pDC->SetBkMode(TRANSPARENT);

    pDC->DrawText(m_strText, &m_ButRect, DT_SINGLELINE | DT_CENTER

        | DT_VCENTER | DT_END_ELLIPSIS);

    //绘制拥有焦点按钮的虚线框

    if (GetFocus() == this)

    {

        CRect Rect;

        Rect.SetRect(m_ButRect.left + 3, m_ButRect.top + 2, m_ButRect.right - 3, m_ButRect.bottom - 2);

        pDC->DrawFocusRect(&Rect);     //画拥有焦点的虚线框

    }

}

 

 

 

//设置按钮文本

void MyButton::SetText(CString str)

{

    m_strText = _T("");

    SetWindowText(str);

}

 

//设置文本颜色

void MyButton::SetForeColor(COLORREF color)

{

    m_ForeColor = color;

    Invalidate();

}

 

//设置背景颜色

void MyButton::SetBkColor(COLORREF color)

{

    m_BackColor = color;

    Invalidate();

}

 

//设置字体(字体高度、字体名)

void MyButton::SetTextFont(int FontHight, LPCTSTR FontName)

{

    if (p_Font)     delete p_Font;     //删除旧字体

    p_Font = new CFont;

    p_Font->CreatePointFont(FontHight, FontName);     //创建新字体

    SetFont(p_Font);                 //设置字体

}

 

///由于新字体由 new 生成,必须显式回收,这项工作可以在 CMyButton类 的析构函数中进行:

 

/*CMyButton::~CMyButton()

{

     if ( p_Font )     delete p_Font;         //删除字体

}

*/

//这样一个可设置颜色、字体的按钮类就做好了。使用时,先在对话框中放置好按钮,再用 ClassWizard 为按钮添加控制变量,

//并且将变量的类型设置为 CMyButton。之后,可以用该变量调用接口函数设置按钮颜色和字体。

 

 

OK,自定义按钮完成。

 

 

4.3  实现过程及代码

4.3.1给相应控件添加变量

现在可以对按钮,EDIT框等控件添加变量,文字描述麻烦,上图:

 

 

 

4.3.2 新建comm.cpp

编写内容如下:

#include "pch.h"

#include "stdafx.h"

#include "commassist.h"

#include "commassistDlg.h"

#include "comm.h"

char ConvertHexChar(char ch);

HANDLE hCom; //串口句柄

CString strcomname; //串口名,如"COM1"

bool ComIsOK; //串口打开状态标识,为真表示已打开,否则未打开

 

//============自动寻找串口函数================================= //

//函数功能:通过扫描注册表来找出当前所有物理串口

//输入参数:无

//返回类型:无

//说    明:若搜索成功,则每搜到一个串口便发送消息通知主对话框,并将串口号以WPARAM传递

void FindComm()

{

    //枚举当前系统中的串口

    LONG result = 0;

    HKEY key = NULL;

 

    result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, //需要打开的主键的名称             

        "HARDWARE\\DEVICEMAP\\SERIALCOMM",

        //需要打开的子键的名称,设备串口 

        0, //保留,必须设置为0 

        KEY_READ, //安全访问标记,也就是权限 

        &key); //得到的将要打开键的句柄,当不再需要句柄,

               //必须调用 RegCloseKey 关闭它

    if( result )

    {

        AfxMessageBox("无法获取串口,请确认是否安装并连接串口!");

        return;

    }

    TCHAR portname[250]; //串口名

    TCHAR data[250];

    DWORD portnamelen = 0; //串口名长度

    DWORD datalen = 0;

    int index = 0;

    while(1) //找完COM后跳出

    {

        portnamelen = 255;

        datalen = 255;

        result = RegEnumValue(key,

            //Long,一个已打开项的句柄,或者指定一个标准项名              

            index++,

            //Long,欲获取值的索引。注意第一个值的索引编号为零  

            portname,

            //String,用于装载位于指定索引处值名的一个缓冲区  

            &portnamelen,

            //Long,用于装载lpValueName缓冲区长度的一个变量。

            //一旦返回,它会设为实际载入缓冲区的字符数量  

            NULL,

            //Long,未用;设为零  

            NULL,

            //Long,用于装载值的类型代码的变量  

            (LPBYTE)data, //Byte,用于装载值数据的一个缓冲区

            &datalen); //Long,用于装载lpData缓冲区长度的一个变量。

           //一旦返回,它会设为实际载入缓冲区的字符数量

        if( result ) 

            break;

 

           //发送消息,WM_USER+1为自定义消息,即找到串口的,并将串口号"COMx"通过WPARA M参数传送给主对话框窗口

           //::AfxGetMainWnd()->m_hWnd,获得主对话框句柄

           //(WPARAM)(LPCTSTR)data,类型转换

        ::SendMessage(::AfxGetMainWnd()->m_hWnd,WM_FOUNDCOMM,(WPARAM)(LPCTSTR)data,0);

    }

    RegCloseKey(key); //调用 RegCloseKey 关闭打开键的句柄

}

//==========串口打开函数===========================

//功    能:打开串口,将已打开的串口句柄赋值给hCom,给出串口打开状态ComIsOK,完成串口状态 设置

//输入参数:波特率,数据位,停止位,校验位

//返回类型:无

 

void OpenComm(int nBaud, int nData, int nStop, int nCal) {

    hCom = CreateFile(strcomname, //串口号

        GENERIC_READ | GENERIC_WRITE, //允许读或写

        0, //独占方式

        NULL,

        OPEN_EXISTING, //打开而不是创建

        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,//重叠方式,用于异步通信

        NULL );

        if (hCom == INVALID_HANDLE_VALUE)

        {

            AfxMessageBox(_T("打开COM失败,串口不存在或已被占用!"));

            ComIsOK = false; return;

        }

        ComIsOK = true;

        SetCommMask(hCom, EV_TXEMPTY | EV_RXCHAR); //设置事件掩码,暂时没用上

        SetupComm(hCom,1024,1024); //设置输入缓冲区和输出缓冲区的大小都是1024

        COMMTIMEOUTS TimeOuts; //设定读超时

        TimeOuts.ReadIntervalTimeout = MAXDWORD;

        TimeOuts.ReadTotalTimeoutConstant = 0;

        TimeOuts.ReadTotalTimeoutMultiplier = 0; //设定写超时

        TimeOuts.WriteTotalTimeoutConstant = 500;

        TimeOuts.WriteTotalTimeoutMultiplier = 100;

        if(SetCommTimeouts(hCom,&TimeOuts) == false)

        {

            CloseHandle(hCom);

            ComIsOK = false; return;

        } //串口属性配置

        DCB dcb;

        GetCommState(hCom,&dcb);

        dcb.BaudRate=nBaud; //dcb.BaudRate=9600; //波特率为9600

        dcb.ByteSize=nData; //dcb.ByteSize=8; //每个字节为8位

        dcb.StopBits=nStop; //dcb.StopBits=ONESTOPBIT;   //1位停止位

        dcb.Parity=nCal; //dcb.Parity=NOPARITY; //无奇偶检验位

        SetCommState(hCom, &dcb);

        PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR);

        if (SetCommState(hCom, &dcb) == false)

        {

            CloseHandle(hCom);

            ComIsOK = false;

            return;

        }

        return;

}

 

//==========串口关闭控制函数=====================

void CloseComm()

{

    CloseHandle(hCom);

    hCom = NULL;

    ComIsOK = false;

}

 

 

//==========串口监听线程函数======================

UINT ThreadFunc(LPVOID pParam)

{

    // CCommassistDlg* pdlg = (CCommassistDlg*)pParam; //定义指针指向主对话框

    COMSTAT ComStat;

    DWORD dwErrorFlags;

    while(ComIsOK)

    {

        DWORD dwBytesRead = 100;

        ClearCommError(hCom,&dwErrorFlags,&ComStat);

        dwBytesRead = min(dwBytesRead,(DWORD)ComStat.cbInQue);

        if(!dwBytesRead)

        {

            Sleep(10);//continue;//使用continue时,打开串口后CPU占用率非常高

        } else ::SendMessage(::AfxGetMainWnd()->m_hWnd,WM_READCOMM,1,0); //发送消息,已读到

    }

    return 0;

}

 

//=================字符串转16进制显示==========

//字符串转16进制显示的函数

//传入参数Data为字符串

//Blank_allow为空格允许标志,为真则代表允许加入空格

//函数返回为CString的结果sResult

CString DisplayCString2Hex(CString Data, bool Blank_allow)

{

    CString sResult;

    CString sTemp;

    int Data_Length;

    Data_Length = Data.GetLength();

    if (Data_Length == 0)

        return "";

    char *pchar = new char[Data_Length+1]; //用了new分配内存空间,要记得释放

    strncpy_s(pchar, Data_Length+1,Data,Data_Length);//此处使用strncpy_s(char * str2, int size2, char * str1, int size1);

                                                   //这里多了一个长度,就是被复制的str2的长度,我们可以用sizeof(str2)来表示这个长度

    for(int i=0; i<Data_Length; i++)

    {

        sTemp.Format("%02X",pchar[i]);

        if(Blank_allow)

        {

            if(i == Data_Length -1)

                sResult = sResult + sTemp; //去掉最后一个空格

            else

                sResult = sResult + sTemp+" ";

        }

        else sResult = sResult + sTemp;

    }

    delete pchar; //释放内存空间

    return sResult;

}

 

 

char ConvertHexChar(char ch)

{

    //将一个字符转换为相应的十六进制

    if ((ch >= \'0\') && (ch <= \'9\'))

        return ch - 48;//0x30;

    else if ((ch >= \'A\') && (ch <= \'F\'))

        return ch - \'A\' + 10;

    else if ((ch >= \'a\') && (ch <= \'f\'))

        return ch - \'a\' + 10;

    else return (-1);

}

 

 

//=================16进制转字符串======================

//16进制转字符串,输入16进制的字符串,输出转换为16进制码

//传入参数str为字符串,判断输入是否按照16进制格式输入

int ConvertHexC2String(CString str, CByteArray& senddata)

{

    //先判断输入字符串是否2个字符一组

    int str_Length,iLength;

    int hexdata, l_data;

    char hstr,lstr;

    char cTemp; str_Length = str.GetLength();

    iLength = 0;

    senddata.SetSize(str_Length/2); //预先设置数组长度,不设置时,允许有错

    char *ppchar = new char[str_Length+1];

    strncpy_s(ppchar, str_Length+1,str,str_Length);

    for(int i=0; i<str_Length; )

    {

        cTemp = ppchar[i];

        if(cTemp == \' \')

        {

            //iLength--;

            i++;

            continue; //如检测到空格则跳过,继续下一次循环

        }

        else

        {

            hstr = ppchar[i]; //取出字符作为16进制高位

            i++;

            lstr = ppchar[i]; //取出下一个字符作为16进制低位

            if(lstr == \' \') //若取出的低位为空格,则不符合16进制2个一组的格式,终止循环

            {

                AfxMessageBox("请按照16进制每2个字符一组的方式输入", MB_ICONERROR); break;

            }

            else

            {

                hexdata = ConvertHexChar(hstr); //高位转换为相应的0进制

                l_data = ConvertHexChar(lstr); //低位转换为相应的10进制

                if( (hexdata == -1) || (l_data == -1) )

                {

                    AfxMessageBox("请按照16进制字符要求输入",MB_ICONERROR);

                    break;

                }

                else

                    hexdata = hexdata*16 + l_data; //安装16进制方式高位低位合并

                senddata[iLength] = (char)hexdata; //int整型数转换为char字符型,并存入数组senddata[]

                i++; //进入下一次循环

                iLength++; //成功转换一组(2个)字符,记录长度加1

            }

        }

    }

    senddata.SetSize(iLength);

    delete ppchar;

    return iLength;         

}

 

 

//=================16进制转字符串显示=====================

//16进制转字符串显示的函数

//传入参数Data为16进制的字符串

//函数返回为CString的结果sResult

CString DisplayHex2CString(CString Data)

{

    CString sResult;

    CString sTemp;

    int Data_Length;

    Data_Length = Data.GetLength();

    if (Data_Length == 0)

        return "";

    char* pchar = new char[Data_Length+1]; //用了new分配内存空间,要记得释放

    strncpy_s(pchar, Data_Length+1,Data,Data_Length);

    for (int i = 0; i < Data_Length; i++)

    {

        sTemp.Format("%02X", pchar[i]);

        sResult = sResult + sTemp;

    }

    delete pchar; //释放内存空间

    return sResult;

}

 

4.2.3  新建comm.h

编写如下:

#pragma once

#define WM_FOUNDCOMM WM_USER + 1 //自定义消息WM_FOUNDCOMM,收到该消息表示串口已经找到

#define WM_READCOMM WM_USER + 2 //自定义消息WM_READCOMM,收到该消息缓冲区有数据,可以读取

extern void FindComm(); //申明为外部函数

extern void OpenComm(int nBaud, int nData, int nStop, int nCal);

extern void CloseComm(); extern UINT ThreadFunc(LPVOID pParam); //申明全局线程处理函数

extern CString DisplayCString2Hex(CString Data, bool Blank_allow);

extern CString DisplayHex2CString(CString Data);

extern int ConvertHexC2String(CString str, CByteArray &senddata);

extern bool ComIsOK; //申明为外部变量

extern HANDLE hCom;

extern CString strcomname;

 

 

4.2.4  在commassistDlg.h中替换为如下代码

 

// commassistDlg.h: 头文件

//

 

#pragma once

#include "MyButton.h"

 

// CcommassistDlg 对话框

class CcommassistDlg : public CDialogEx

{

// 构造

public:

    CcommassistDlg(CWnd* pParent = nullptr);   // 标准构造函数

    CWinThread* pReceiveThread;

    void ShowStatus();

    int m_intTxCnt;

    int m_intRxCnt;

    BOOL m_bAutoSend;

    DWORD ReadComm();

// 对话框数据

#ifdef AFX_DESIGN_TIME

    enum { IDD = IDD_COMMASSIST_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()

public:

    afx_msg void OnEnChangeEdit1();

    CComboBox m_baud;

    CComboBox m_bdata;

    CComboBox m_bstop;

    CComboBox m_cal;

    MyButton m_autosend;//MyButton

    MyButton m_clrrx;//MyButton

    MyButton m_clrtx;//MyButton

    MyButton m_handsend;//MyButton

    MyButton m_selfile;//MyButton

    MyButton m_sendfile;//MyButton

    BOOL m_check_hexrx;

    BOOL m_check_hextx;

    MyButton m_comcontrol;//MyButton

    CComboBox m_comlist;

    CString m_strFilePath;

    CString m_strStatus;

    CEdit m_CEditStatus;

    CString m_strTimer;

    CString m_strOut;

    CStatic m_ctrlIcon;

    DWORD  HandSendNum;

    virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);

 

    afx_msg void OnComcontrol();

    afx_msg void OnClose();

    afx_msg void OnBtnHandsend();

    afx_msg void OnBtnClrrx();

    afx_msg void OnBtnClrtx();

    afx_msg void OnTimer(UINT_PTR nIDEvent);

    afx_msg void OnBtnAutosend();

    afx_msg void OnCheckHexrx();

    afx_msg void OnCheckHextx();

    afx_msg void OnBtnSelctfile();

    afx_msg void OnBtnSendfile();

    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);

   

    //afx_msg void OnCbnSelchangeBaud();

};

 

 

4.2.5  在commassistDlg.cpp中替换为如下代码

 

// commassistDlg.cpp: 实现文件

//

 

#include "pch.h"

#include "framework.h"

#include "commassist.h"

#include "commassistDlg.h"

#include "afxdialogex.h"

#include "comm.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

 

 

CString strIn;

CString strOut;

CString m_strFile;

 

 

// 用于应用程序“关于”菜单项的 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()

 

 

// CcommassistDlg 对话框

 

 

 

CcommassistDlg::CcommassistDlg(CWnd* pParent /*=nullptr*/)

         : CDialogEx(IDD_COMMASSIST_DIALOG, pParent)

         , m_check_hexrx(FALSE)

         , m_check_hextx(FALSE)

         , m_strFilePath(_T(""))

         , m_strStatus(_T(""))

         , m_strTimer(_T(""))

         , m_strOut(_T(""))

{

 

        

         //下面就是自己添加的变量初始化

         m_strTimer = "1000";

         m_strFilePath = "请选择要发送的文件";

         m_intTxCnt = 0;

         m_intRxCnt = 0;

         m_bAutoSend = 0;

         strIn = "";

         strOut = "";

         m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

 

}

 

 

 

void CcommassistDlg::DoDataExchange(CDataExchange* pDX)

{

         CDialogEx::DoDataExchange(pDX);

         DDX_Control(pDX, IDC_BAUD, m_baud);

         DDX_Control(pDX, IDC_BDATA, m_bdata);

         DDX_Control(pDX, IDC_BSTOP, m_bstop);

         DDX_Control(pDX, IDC_BTN_AUTOSEND, m_autosend);

         DDX_Control(pDX, IDC_BTN_CLRRX, m_clrrx);

         DDX_Control(pDX, IDC_BTN_CLRTX, m_clrtx);

         DDX_Control(pDX, IDC_BTN_HANDSEND, m_handsend);

         DDX_Control(pDX, IDC_BTN_SELCTFILE, m_selfile);

         DDX_Control(pDX, IDC_BTN_SENDFILE, m_sendfile);

         DDX_Control(pDX, IDC_CAL, m_cal);

         DDX_Check(pDX, IDC_CHECK_HEXRX, m_check_hexrx);

         DDX_Check(pDX, IDC_CHECK_HEXTX, m_check_hextx);

         DDX_Control(pDX, IDC_COMCONTROL, m_comcontrol);

         DDX_Control(pDX, IDC_COMLIST, m_comlist);

         DDX_Text(pDX, IDC_EDIT_FILEPATH, m_strFilePath);

         DDX_Text(pDX, IDC_EDIT_STATUS, m_strStatus);

         DDX_Control(pDX, IDC_EDIT_STATUS, m_CEditStatus);

         DDX_Text(pDX, IDC_EDIT_TIMER, m_strTimer);

         DDX_Text(pDX, IDC_EDIT_TX, m_strOut);

         DDX_Control(pDX, IDC_STATIC_ICON, m_ctrlIcon);

 

}

 

BEGIN_MESSAGE_MAP(CcommassistDlg, CDialogEx)

         ON_WM_SYSCOMMAND()

         ON_WM_PAINT()

         ON_WM_QUERYDRAGICON()

         ON_BN_CLICKED(IDC_COMCONTROL, &CcommassistDlg::OnComcontrol)

         ON_WM_CLOSE()

         ON_BN_CLICKED(IDC_BTN_HANDSEND, &CcommassistDlg::OnBtnHandsend)

         ON_BN_CLICKED(IDC_BTN_CLRRX, &CcommassistDlg::OnBtnClrrx)

         ON_BN_CLICKED(IDC_BTN_CLRTX, &CcommassistDlg::OnBtnClrtx)

         ON_WM_TIMER()

         ON_BN_CLICKED(IDC_BTN_AUTOSEND, &CcommassistDlg::OnBtnAutosend)

         ON_BN_CLICKED(IDC_CHECK_HEXRX, &CcommassistDlg::OnCheckHexrx)

         ON_BN_CLICKED(IDC_CHECK_HEXTX, &CcommassistDlg::OnCheckHextx)

         ON_BN_CLICKED(IDC_BTN_SELCTFILE, &CcommassistDlg::OnBtnSelctfile)

         ON_BN_CLICKED(IDC_BTN_SENDFILE, &CcommassistDlg::OnBtnSendfile)

         ON_WM_CTLCOLOR()/**/

         //ON_CBN_SELCHANGE(IDC_BAUD, &CcommassistDlg::OnCbnSelchangeBaud)

END_MESSAGE_MAP()

 

 

// CcommassistDlg 消息处理程序

 

BOOL CcommassistDlg::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);                  // 设置小图标

         SetWindowText("MyCommassit--Mr Wang");

         // TODO: 在此添加额外的初始化代码

         //AfxGetApp()->SetWindowText("你要显示的东西如果不想显示置空就行");

         m_comcontrol.SetForeColor(RGB(255, 0, 0));

         FindComm(); //调用自动找串口函数

         m_comlist.SetCurSel(0); //设置串口号下拉框默认值为第一个

         m_baud.SetCurSel(6); //设置波特率下拉框默认值为9600

         m_bdata.SetCurSel(3); //设置数据位下拉框默认值为8位

         m_bstop.SetCurSel(0); //设置停止位下拉框默认值为1

         m_cal.SetCurSel(0); //设置校验位下拉框默认值为None无

         GetDlgItem(IDC_BTN_HANDSEND)->EnableWindow(false); //设置手动发送按钮不可用

         GetDlgItem(IDC_BTN_AUTOSEND)->EnableWindow(false); //设置自动发送按钮不可用

         GetDlgItem(IDC_EDIT_TIMER)->EnableWindow(false); //设置发送间隔按钮不可用

         GetDlgItem(IDC_BTN_SELCTFILE)->EnableWindow(false); //设置选择文件按钮不可用

         GetDlgItem(IDC_BTN_SENDFILE)->EnableWindow(false); //设置发送文件按钮不可用

         ShowStatus();

        

         //下面语句用于解决程序运行后初始化EDIT框内容被默认自动选中状态

         //返回值需更改为FALSE

         GetFocus(); //获取焦点

         SetFocus(); //设置焦点

         m_CEditStatus.SetSel(-1,-1,FALSE); //设置

 

         // PostMessage(EM_SETSEL,-1,0);

         return FALSE;  // return TRUE  unless you set the focus to a control  return TRUE; 

                                        // 除非将焦点设置到控件,否则返回 TRUE

}

 

void CcommassistDlg::OnSysCommand(UINT nID, LPARAM lParam)

{

         if ((nID & 0xFFF0) == IDM_ABOUTBOX)

         {

                   CAboutDlg dlgAbout;

                   dlgAbout.DoModal();

         }

         else

         {

                   CDialogEx::OnSysCommand(nID, lParam);

         }

}

 

// 如果向对话框添加最小化按钮,则需要下面的代码

//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,

//  这将由框架自动完成。

 

void CcommassistDlg::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 CcommassistDlg::OnQueryDragIcon()

{

         return static_cast<HCURSOR>(m_hIcon);

}

 

 

 

LRESULT CcommassistDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)

{

         // TODO: 在此添加专用代码和/或调用基类

         switch(message) {

                   case WM_FOUNDCOMM :

                   {//已找到串口,串口号以字符串形式由wParam传递

                            m_comlist.AddString((LPCTSTR)wParam); //用AddString添加一个字符串即COM号到m_comlist列表框中

                            break;

                   }

                   case WM_READCOMM :

                   {   //读串口消息

                            ReadComm();

                            this->SendDlgItemMessage(IDC_EDIT_RX, WM_VSCROLL, SB_BOTTOM, 0); //滚动条始终在底部

                            break;

                   }

         }

 

         return CDialogEx::WindowProc(message, wParam, lParam);

}

 

 

 

 

void CcommassistDlg::OnComcontrol()

{

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

         int nBaud,nData,nStop,nCal,nTemp;

         CString sTemp,siTemp;

         //波特率下拉框设置=================

         nTemp=m_baud.GetCurSel();

         switch (nTemp)

         {

                   case 0: nBaud = CBR_110; break;

                   case 1: nBaud = CBR_300; break;

                   case 2: nBaud = CBR_600; break;

                   case 3: nBaud = CBR_1200; break;

                   case 4: nBaud = CBR_2400; break;

                   case 5: nBaud = CBR_4800; break;

                   case 6: nBaud = CBR_9600; break;

                   case 7: nBaud = CBR_14400; break;

                   case 8: nBaud = CBR_19200; break;

                   case 9: nBaud = CBR_38400; break;

                   case 10: nBaud = CBR_56000; break;

                   case 11: nBaud = CBR_57600; break;

                   case 12: nBaud = CBR_115200; break;

                   case 13: nBaud = CBR_128000; break;

                   case 14: nBaud = CBR_256000; break;

         }

         //数据位下拉框设置=================

         nTemp=m_bdata.GetCurSel();

          switch(nTemp)

          {

          case 0: nData = 5; break;

          case 1: nData = 6; break;

          case 2: nData = 7; break;

          case 3:nData = 8; break;

          }

 

          //停止位下拉框设置=================

         nTemp=m_bstop.GetCurSel();

         switch(nTemp)

         {

                   case 0: nStop = ONESTOPBIT; break;

                   case 1: nStop = ONE5STOPBITS; break;

                   case 2: nStop = TWOSTOPBITS; break;

         }

         //校验位下拉框设置=================

         nTemp=m_cal.GetCurSel();

         switch(nTemp)

         {

                   case 0: nCal = NOPARITY; break;

                   case 1: nCal = ODDPARITY; break;

                   case 2: nCal = EVENPARITY; break;

                   case 3: nCal = MARKPARITY;break;

                   case 4: nCal = SPACEPARITY;break;

         }

         int commnum_buf;

         commnum_buf = m_comlist.GetCurSel();

         if (commnum_buf < 0)

         {

                   MessageBox("获取串口错误", "错误", MB_ICONERROR);

                   ComIsOK = FALSE;

                   return;

         }

         m_comlist.GetLBText(commnum_buf, strcomname);

         if (!ComIsOK)

         {

                   OpenComm(nBaud, nData, nStop, nCal); //调用打开串口函数OpenComm()

                   if(ComIsOK)

                            pReceiveThread=AfxBeginThread(ThreadFunc,this,THREAD_PRIORITY_LOWEST);

                   //启动接收线程

                   ShowStatus();

                   if (!ComIsOK)

                            m_comcontrol.SetWindowText("打开串口");

                   else

                   {

                            m_comcontrol.SetText("关闭串口"); //按钮显示状态改变

                            m_comcontrol.SetForeColor(RGB(0,155,0)); //串口打开后文本颜色变绿

                            m_ctrlIcon.SetIcon((HICON)LoadImage(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_ICON_OPEN), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CXICON), 0)); //显示打开icon

                            m_comlist.EnableWindow(false); //设置串口号下拉框不可用

                            m_baud.EnableWindow(false); //设置波特率下拉框不可用

                            m_bdata.EnableWindow(false); //设置数据位下拉框不可用

                            m_bstop.EnableWindow(false); //设置停止位下拉框不可用

                            m_cal.EnableWindow(false); //设置校验位下拉框不可用

                            GetDlgItem(IDC_BTN_HANDSEND)-> EnableWindow(true); //设置手动发送按钮不可用

                            GetDlgItem(IDC_BTN_AUTOSEND)-> EnableWindow(true); //设置自动发送按钮可用

                            GetDlgItem(IDC_EDIT_TIMER) ->  EnableWindow(true); //设置发送间隔按钮可用

                            GetDlgItem(IDC_BTN_SELCTFILE)->EnableWindow(true); //设置选择文件按钮可用

                            GetDlgItem(IDC_BTN_SENDFILE)-> EnableWindow(true); //设置发送文件按钮可用

                   }

                   return;

         }

         else {

                   CloseComm(); //调用关闭串口函数CloseComm()

                   // TerminateThread(pReceiveThread,0);

                   ShowStatus();

                   m_comcontrol.SetText("打开串口");

                   m_comcontrol.SetForeColor(RGB(255,0,0));

                   m_ctrlIcon.SetIcon((HICON)LoadImage(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_ICON_CLOSE), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CXICON), 0)); //显示关闭icon

                   m_comlist.EnableWindow(true); //设置串口号下拉框可用

                   m_baud.EnableWindow(true); //设置波特率下拉框可用

                   m_bdata.EnableWindow(true); //设置数据位下拉框可用

                   m_bstop.EnableWindow(true); //设置停止位下拉框可用

                   m_cal.EnableWindow(true); //设置校验位下拉框可用

                   GetDlgItem(IDC_BTN_HANDSEND)-> EnableWindow(false); //设置手动发送按钮不可用

                   GetDlgItem(IDC_BTN_AUTOSEND)-> EnableWindow(false); //设置自动发送按钮不可用

                   GetDlgItem(IDC_EDIT_TIMER) ->  EnableWindow(false); //设置发送间隔按钮不可用

                   GetDlgItem(IDC_BTN_SELCTFILE)->EnableWindow(false); //设置选择文件按钮不可用

                   GetDlgItem(IDC_BTN_SENDFILE)-> EnableWindow(false); //设置发送文件按钮不可用

                   return;

         }

 

}

 

DWORD CcommassistDlg::ReadComm()

{

         CString strTemp;

         OVERLAPPED m_osRead;

         memset(&m_osRead, 0, sizeof(OVERLAPPED));

         m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

         char lpInBuffer[1024];

         DWORD dwBytesRead = 1024;

         BOOL bReadStatus;

         bReadStatus = ReadFile(hCom, lpInBuffer, dwBytesRead, &dwBytesRead, &m_osRead);

         if (!bReadStatus) //如果ReadFile函数返回FALSE

         {

                   if(GetLastError()==ERROR_IO_PENDING) //GetLastError()函数返回ERROR_IO_PENDING,表明串口正在进行读操作

                   {

                            WaitForSingleObject(m_osRead.hEvent,2000); //使用WaitForSingleObject函数等待,直到读操作完成或延时已达到2000ms

                            //当串口读操作进行完毕后,m_osRead的hEvent事件会变为有信号

                            PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);

                            return dwBytesRead;

                   }

                   return 0;

         }

         lpInBuffer[dwBytesRead] = NULL;

         strTemp = lpInBuffer;

         m_intRxCnt += strTemp.GetLength(); //接收到字节数统计

         // GetDlgItemText(IDC_EDIT_RX,strIn);

         strIn += strTemp;

         OnCheckHexrx();

         ShowStatus();

         return 1;

}

 

 

void CcommassistDlg::OnClose()

{

         // TODO: 在此添加消息处理程序代码和/或调用默认值

         TerminateThread(pReceiveThread, 0); //程序退出时,关闭串口监听线程

         WaitForSingleObject(pReceiveThread,INFINITE);

         CDialogEx::OnClose();

}

 

 

void CcommassistDlg::OnBtnHandsend()

{

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

          if(ComIsOK == FALSE)

          {

                    MessageBox("请先打开串口","提示",MB_ICONINFORMATION);

                    return ;//return 0;

          }

          BOOL bWriteStat;

          UpdateData(TRUE);

          CString   str, sTemp;

          DWORD dwBytesWritten = 1024;

          OVERLAPPED m_osWrite;

          memset(&m_osWrite, 0, sizeof(OVERLAPPED));

          m_osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

          COMSTAT ComStat;

          DWORD dwErrorFlags;

          // dwBytesWritten = OnCheckHextx();

          GetDlgItem(IDC_EDIT_TX)-> GetWindowText(strOut);

          if (m_check_hextx) {

                    int i, n;

                    CString strTemp;

                    CByteArray hexdata;

                    // GetDlgItem(IDC_EDIT_TX)-> GetWindowText(strOut);

                    dwBytesWritten = ConvertHexC2String(strOut,hexdata);

                    n = hexdata.GetSize();

                    for(i=0;i<n;i++)

                    {

                             str.Format("%c", hexdata[i]);

                             strTemp += str;

                    }

                    // SetDlgItemText(IDC_EDIT_TX,strTemp);

                    strOut = strTemp;

          }

          else

          {

                    GetDlgItem(IDC_EDIT_TX)-> GetWindowText(str);

                    SetDlgItemText(IDC_EDIT_TX,"");

                    sTemp = DisplayHex2CString(str);

                    dwBytesWritten = str.GetLength();

                    SetDlgItemText(IDC_EDIT_TX,strOut);

          }

          UpdateData();

          if(dwBytesWritten==0)

          {

                    MessageBox("请在发送区内输入要发送的内容", "提示", MB_ICONINFORMATION);

                    //HandSendNum = 0;//return 0;

                    return;

          }

 

          m_intTxCnt += dwBytesWritten;

          ShowStatus();

          ClearCommError(hCom, &dwErrorFlags, &ComStat);

          bWriteStat = WriteFile(hCom, strOut, dwBytesWritten, &dwBytesWritten, &m_osWrite);

          if (!bWriteStat)

          {

                    if (GetLastError() == ERROR_IO_PENDING)

                    {

                             WaitForSingleObject(m_osWrite.hEvent, 1000);

                             HandSendNum=dwBytesWritten;//return dwBytesWritten;

                    }

                    //HandSendNum = 0;//return 0;

                    return;

          }

          ShowStatus();

          PurgeComm(hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);

          //HandSendNum= dwBytesWritten;//return dwBytesWritten;

          return;

}

 

 

void CcommassistDlg::ShowStatus()

{

         //状态栏显示状态

         CString strTXcnt;

         CString strRXcnt;

         CString sTemp;

         CString comnum;

         CString strBaud, strStop, strData, strCal;

         UpdateData(true);

         if (ComIsOK)

         {

                   m_comlist.GetLBText(m_comlist.GetCurSel(), sTemp);

                   comnum = sTemp + "已打开";

         }

         else

                   comnum = "未打开串口";

         strTXcnt.Format("发送:%d", m_intTxCnt);

         strRXcnt.Format("接收:%d", m_intRxCnt);

        

         m_baud.GetLBText(m_baud.GetCurSel(), strBaud);

         m_bstop.GetLBText(m_bstop.GetCurSel(), strStop);

         m_bdata.GetLBText(m_bdata.GetCurSel(), strData);

         m_cal.GetLBText(m_cal.GetCurSel(), strCal);

         m_strStatus = "串口: " + comnum + "  " + "状态: " + strTXcnt + ", " + strRXcnt + ", " + "波特率: " + strBaud +

                   ", " + "数据位: " + strData + ", " + "停止位: " + strStop + ", " + "校验位: " + strCal;

         UpdateData(FALSE);

 

}

 

void CcommassistDlg::OnBtnClrrx()

{

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

         GetDlgItem(IDC_EDIT_RX);

         SetDlgItemText(IDC_EDIT_RX, "");

         m_intRxCnt = 0;

         m_intTxCnt = 0;

         strIn = "";

         ShowStatus();

        

}

 

 

void CcommassistDlg::OnBtnClrtx()

{

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

         GetDlgItem(IDC_EDIT_TX);

         SetDlgItemText(IDC_EDIT_TX, "");

}

 

 

void CcommassistDlg::OnTimer(UINT_PTR nIDEvent)

{

         // TODO: 在此添加消息处理程序代码和/或调用默认值

         if (nIDEvent == 1)  

                   OnBtnHandsend();

         else if (nIDEvent == 2)

                   return;

         CDialogEx::OnTimer(nIDEvent);

}

 

 

void CcommassistDlg::OnBtnAutosend()

{

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

         UpdateData(TRUE);

         m_bAutoSend = !m_bAutoSend;// m_bAutoSend

         if (!m_strOut.GetLength())

         {

                   MessageBox("请先输入要发送的内容", "提示", MB_ICONINFORMATION);

                   m_bAutoSend = !m_bAutoSend;

         }

         else

         {

                   if (m_bAutoSend)

                   {

                            SetTimer(1, atoi(m_strTimer.GetBuffer(m_strTimer.GetLength())), NULL); //设置定时

                            m_autosend.SetText("停止");

                            GetDlgItem(IDC_COMCONTROL)->EnableWindow(false);

                            GetDlgItem(IDC_BTN_CLRTX)->EnableWindow(false);

                            GetDlgItem(IDC_BTN_CLRRX)->EnableWindow(false);

                            GetDlgItem(IDC_BTN_HANDSEND)->EnableWindow(false);

                            GetDlgItem(IDC_BTN_SELCTFILE)->EnableWindow(false);

                            GetDlgItem(IDC_BTN_SENDFILE)->EnableWindow(false);

                   }

                   else

                   {

                            KillTimer(1);

                            m_autosend.SetText("自动发送");

                            GetDlgItem(IDC_COMCONTROL)->EnableWindow(true);

                            GetDlgItem(IDC_BTN_CLRTX)->EnableWindow(true);

                            GetDlgItem(IDC_BTN_CLRRX)->EnableWindow(true);

                            GetDlgItem(IDC_BTN_HANDSEND)->EnableWindow(true);

                            GetDlgItem(IDC_BTN_SELCTFILE)->EnableWindow(true);

                            GetDlgItem(IDC_BTN_SENDFILE)->EnableWindow(true);

                   }

         }

}

 

 

void CcommassistDlg::OnCheckHexrx()

{

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

         UpdateData(TRUE);

         CString hexIn;

         CString sTemp;

         if (m_check_hexrx)

         {

                   hexIn = DisplayCString2Hex(strIn, true);

                   GetDlgItem(IDC_EDIT_RX)->SetWindowText(hexIn);

                   //将hexIn内容放入IDC_EDIT_RX框内,即为显示转换

         } else

                   GetDlgItem(IDC_EDIT_RX)-> SetWindowText(strIn);

            //将strIn内容放入IDC_EDIT_RX框内,即为显示不转换

         return;

 

}

 

 

void CcommassistDlg::OnCheckHextx()

{

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

         UpdateData();

         CString hexOut;

         CString str, sTemp;

         GetDlgItem(IDC_EDIT_TX)->GetWindowText(strOut);

         if (m_check_hextx)

         {

                   str = DisplayCString2Hex(strOut, true);

                   strOut = str;

         }

         else {

                   int i, n;

                   CString strTemp;

                   CByteArray hexdata;

                   ConvertHexC2String(strOut, hexdata);

                   n = hexdata.GetSize();

                   for (i = 0; i < n; i++)

                   {

                            str.Format("%c", hexdata[i]);

                            strTemp += str;

                   }

                   strOut = strTemp;

         }

         GetDlgItem(IDC_EDIT_TX)->SetWindowText(strOut);

         //将strOut内容放入IDC_EDIT_TX框内,即为不转换

         UpdateData();

         return;

 

}

 

 

void CcommassistDlg::OnBtnSelctfile()

{

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

         CFile file;

         m_strFile.Empty();

         CFileDialog FileDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "文本文件(*.txt)|*.txt||"); if (FileDlg.DoModal() == IDOK) //打开文件对话框

         m_strFilePath = FileDlg.GetPathName(); //得到文件路经

         else

                   return;

         file.Open(m_strFilePath, CFile::modeRead | CFile::typeBinary);//打开这个文件

         file.Read(m_strFile.GetBuffer(file.GetLength()), file.GetLength()); //读文件

         m_strFile.ReleaseBuffer(); if(m_strFile.GetLength() >= 2048)

         {     

                   AfxMessageBox("文件的长度超过2k字节!",MB_ICONINFORMATION);

         }

         else

         {  

                   m_strOut += m_strFile; //文件内容加入发送框变量内   

                   UpdateData(false); //更新发送框内容

         }

         file.Close();

}

 

 

void CcommassistDlg::OnBtnSendfile()

{

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

         COMSTAT state;

         DWORD errors;

         CString sTemp;

         int iTemp;

         ClearCommError(hCom, &errors, &state); //清除串口错误、得到当前状态

         iTemp=m_strOut.GetLength(); //写入串口的字符串长度,由EDIT控件内字符串数决定

         iTemp += iTemp;

         OnBtnHandsend(); //调用发送函数

         GetDlgItem(IDC_EDIT_FILEPATH)->SetDlgItemText(IDC_EDIT_FILEPATH,"");

         UpdateData(false); //更新发送框内容;

 

}

 

 

HBRUSH CcommassistDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)

{

         HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);

 

         // TODO:  在此更改 DC 的任何特性

         if (nCtlColor == CTLCOLOR_DLG)   //所有对话框

         {    

                   HBRUSH   brush=CreateSolidBrush(RGB(220,250,250));

                   return   brush;  

         }

         if(nCtlColor == CTLCOLOR_STATIC)  

         {

                   pDC->SetTextColor(RGB(50, 50, 50));        

                   //pDC->SetBkColor(RGB(128,128,128));//设置文本背景色       

                   //pDC->SetTextColor(RGB(55,55,66));       

                   pDC->SetBkMode(TRANSPARENT);//设置背景透明   

         }

         switch (pWnd->GetDlgCtrlID())                

         {

                   //针对ID为IDC_CTL1、IDC_CTL2和IDC_CTL3的控件进行同样的设置   

                   case IDC_EDIT_RX:       

                   {           

                            //pDC->SetBkMode(TRANSPARENT);//背景色透明           

                            //pDC->SetTextColor(RGB(250,0,0));// 设置字体颜色为红色

                            pDC->SetTextColor(RGB(0, 0, 255));// 设置字体颜色为   //255 

                            pDC->SetBkColor(RGB(255, 255, 255));   // 改为背景颜色即可 

                            hbr = CreateSolidBrush(RGB(255, 255, 255));//背景

 

                            //Invalidate(false);

                            break;

                   }

                  

                   case IDC_EDIT_TX:       

                   {  

                       pDC->SetTextColor(RGB(0,0,255));// 设置字体颜色为   //255 

                            pDC->SetBkColor(RGB(255, 255, 255));   // 改为背景颜色即可 

                            hbr = CreateSolidBrush(RGB(255, 255, 255));//背景

                            break;

                   }

 

 

                   default:break;

         }

         // TODO:  如果默认的不是所需画笔,则返回另一个画笔

         return hbr;

}

 

 

 

 

 

 

总结

         至此,串口调试工具已经完成设计。

相关文章: