VS2013+MFC+C++通过串口接收发送数据同时显示数据波形,而且可以将数据通过数据库保存

VS2013+MFC+C++通过串口接收发送数据同时显示数据波形,而且可以将数据通过数据库保存

所需工具:VS2013,TeeChart5,Navicat Premium 12,串口控件

只是为了记录自己研究生生涯编程过程中遇到的问题。

遇到的问题

1.注意选用的控件适用平台是32位的还是64位的,否则两个控件适用平台不一致会很麻烦,下载控件时注意协调
2.将软件与硬件结合调试时硬件发送数据速度过快,加延时是非常必要的。
3.面对[X:“41.111”,Y:“51.112”,Z:“61.113”]这种格式的数据若想将X、Y、Z对应的数据分别提取出来显示在对应的编辑框内,
size_t a = txt.find_last_of(‘X’);
size_t b = txt.find_first_of(‘Y’);
string res1 = txt.substr(a + 3, b - 2 - a - 3);
此函数寻找的X,Y是最后位置的,所以若同时传递两组数据,则只识别第二组。
3.注意字符间的转换问题。

最后做出来的界面

VS2013+MFC+C++通过串口接收发送数据同时显示数据波形,而且可以将数据通过数据库保存_第1张图片
VS2013+MFC+C++通过串口接收发送数据同时显示数据波形,而且可以将数据通过数据库保存_第2张图片
VS2013+MFC+C++通过串口接收发送数据同时显示数据波形,而且可以将数据通过数据库保存_第3张图片

相关代码

#include "stdafx.h"
#include "串口V1.h"
#include "串口V1Dlg.h"
#include "afxdialogex.h"
#include 
#include
#include "mysql.h"
#include "vector"
MYSQL mysqlCon;//数据库结构
using namespace std;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
long len = 0;

vector<CString> x;
vector<CString> y;
vector<CString> z;


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
int num_iput = 1;
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()


// C串口V1Dlg 对话框



C串口V1Dlg::C串口V1Dlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(C串口V1Dlg::IDD, pParent)
	, m_EditReceive1(_T(""))
	, m_EditReceive2(_T(""))
	, m_EditReceive3(_T(""))
	, m_EditSend(_T(""))
{
     
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void C串口V1Dlg::DoDataExchange(CDataExchange* pDX)
{
     
	CDialogEx::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_EDIT1, m_EditReceive1);
	DDX_Text(pDX, IDC_EDIT2, m_EditReceive2);
	DDX_Text(pDX, IDC_EDIT3, m_EditReceive3);
	DDX_Text(pDX, IDC_EDIT4, m_EditSend);
	DDX_Control(pDX, IDC_COMBO1, m_comb1);
	DDX_Control(pDX, IDC_COMBO2, m_comb2);
	DDX_Control(pDX, IDC_MSCOMM1, m_mscom);
	DDX_Control(pDX, IDC_EDIT1, m_Edit1);
	DDX_Control(pDX, IDC_EDIT2, m_Edit2);
	DDX_Control(pDX, IDC_EDIT3, m_Edit3);
	DDX_Control(pDX, IDC_TCHART1, m_chart);
}

BEGIN_MESSAGE_MAP(C串口V1Dlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_OPEN, &C串口V1Dlg::OnBnClickedButtonOpen)
	ON_BN_CLICKED(IDC_BUTTON_SEND, &C串口V1Dlg::OnBnClickedButtonSend)
	ON_BN_CLICKED(IDC_BUTTON_, &C串口V1Dlg::OnBnClickedButton)
	ON_BN_CLICKED(IDC_BUTTON_CLOSE, &C串口V1Dlg::OnBnClickedButtonClose)
	ON_BN_CLICKED(IDC_BUTTON_SAVE, &C串口V1Dlg::OnBnClickedButtonSave)
END_MESSAGE_MAP()


// C串口V1Dlg 消息处理程序

BOOL C串口V1Dlg::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:  在此添加额外的初始化代码
	// 串口选择组合框
	CString str;
	int i;
	for (i = 0; i<15; i++)
	{
     
		str.Format(_T("com %d"), i + 1);
		m_comb1.InsertString(i, str);
	}
	m_comb1.SetCurSel(0);//预置COM口

	//波特率选择组合框
	CString str1[] = {
      _T("300"), _T("600"), _T("1200"), _T("2400"), _T("4800"), _T("9600"),
		_T("19200"), _T("38400"), _T("43000"), _T("56000"), _T("57600"), _T("115200") };
	for (int i = 0; i<12; i++)
	{
     
		int judge_tf = m_comb2.AddString(str1[i]);
		if ((judge_tf == CB_ERR) || (judge_tf == CB_ERRSPACE))
			MessageBox(_T("build baud error!"));
	}
	m_comb2.SetCurSel(5);//预置波特率为"9600"

	CAxes m_Axis = m_chart.get_Axis();       //获取坐标轴
	CAxis m_left = m_Axis.get_Left();        //获取纵轴
	CAxis m_bottom = m_Axis.get_Bottom();    //获取横轴
	m_left.put_Automatic(FALSE);             //设置不自动适应
	m_left.put_Minimum(0);                   //设置纵轴起始值
	m_left.put_Maximum(100);                  //设置纵轴结束值
	m_left.put_Increment(0.1);               //设置增量
	m_left.put_StartPosition(0);            //设置起始位置%
	m_left.put_EndPosition(100);              //设置结束位置%


	CAxisTitle m_AxisLeftTitle = m_left.get_Title();//得到纵轴标题
	m_AxisLeftTitle.put_Caption(_T("Y"));//设置纵轴标题
	CAxisTitle m_AxisBottomTitle = m_bottom.get_Title();//得到横轴标题
	m_AxisBottomTitle.put_Caption(_T("X"));//设置横轴标题

	CChartFont m_LeftTitleFont = m_AxisLeftTitle.get_Font();//得到坐标轴字体样式大小
	m_LeftTitleFont.put_Size(14);
	m_LeftTitleFont.put_Bold(TRUE);

	CChartFont m_BottomTitleFont = m_AxisBottomTitle.get_Font();//得到坐标轴样式
	m_BottomTitleFont.put_Size(14);
	m_BottomTitleFont.put_Bold(TRUE);
	m_bottom.put_Automatic(FALSE);          //设置不自动适应
	m_bottom.put_Minimum(0);                //设置横轴起始值
	m_bottom.put_Maximum(100);              //设置横轴结束值
	m_bottom.put_Increment(1);              //设置增量

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

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

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

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



void C串口V1Dlg::OnBnClickedButtonOpen() //打开串口按钮程序
{
     
	// TODO:  在此添加控件通知处理程序代码
	CString str, str1, n;					//定义字符串
	GetDlgItemText(IDC_BUTTON_OPEN, str);
	CWnd *h1;
	h1 = GetDlgItem(IDC_BUTTON_OPEN);		//指向控件的caption

	if (!m_mscom.get_PortOpen())
	{
     
		m_comb2.GetLBText(m_comb2.GetCurSel(), str1);//取得所选的字符串,并存放在str1里面
		str1 = str1 + ',' + 'n' + ',' + '8' + ',' + '1';			//这句话很关键

		m_mscom.put_CommPort((m_comb1.GetCurSel() + 1));	//选择串口
		m_mscom.put_InputMode(1);			//设置输入方式为二进制方式
		m_mscom.put_Settings(str1);		//波特率为(波特率组Á合框)无校验,8数据位,1个停止位
		m_mscom.put_InputLen(1024);		//设置当前接收区数据长度为1024
		m_mscom.put_RThreshold(1);			//缓冲区一个字符引发事件
		m_mscom.put_RTSEnable(1);			//设置RT允许

		m_mscom.put_PortOpen(true);		//打开串口
		if (m_mscom.get_PortOpen())
		{
     
			str = _T("关闭串口");
			UpdateData(true);
			h1->SetWindowText(str);			//改变按钮名称为‘’关闭串口”
		}
	}

	else
	{
     
		m_mscom.put_PortOpen(false);
		if (str != _T("打开串口"))
		{
     
			str = _T("打开串口");
			UpdateData(true);
			h1->SetWindowText(str);			//改变按钮名称为打开串口
		}
	}
}


void C串口V1Dlg::OnBnClickedButtonSend() //发送数据按钮程序
{
     
	// TODO:  在此添加控件通知处理程序代码
	UpdateData(true);							//更新控件数据
	m_mscom.put_Output(COleVariant(m_EditSend));//把发送编辑框的数据发送出去
}


void C串口V1Dlg::OnBnClickedButton()  //清除数据按钮程序
{
     
	// TODO:  在此添加控件通知处理程序代码
	m_EditReceive1 = _T("");	//给接收编辑框发送空格符
	m_EditReceive2 = _T("");
	m_EditReceive3 = _T("");
	UpdateData(false);		//更新数据
}


void C串口V1Dlg::OnBnClickedButtonClose()  //退出按钮程序
{
     
	// TODO:  在此添加控件通知处理程序代码
	if (m_mscom.get_PortOpen())
		m_mscom.put_PortOpen(false);
	CDialogEx::OnCancel();
}
BEGIN_EVENTSINK_MAP(C串口V1Dlg, CDialogEx)
	ON_EVENT(C串口V1Dlg, IDC_MSCOMM1, 1, C串口V1Dlg::OnCommMscomm1, VTS_NONE)
END_EVENTSINK_MAP()


void C串口V1Dlg::OnCommMscomm1()  //串口控件程序
{
     
	// TODO:  在此处添加消息处理程序代码
	CSeries lineSeries0 = (CSeries)m_chart.Series(0);
	CSeries lineSeries1 = (CSeries)m_chart.Series(1);
	CSeries lineSeries2 = (CSeries)m_chart.Series(2);

	if (m_mscom.get_CommEvent() == 2)
	{
     
		char str[1024] = {
      0 };
		long len1, k;
		VARIANT InputData = m_mscom.get_Input();	//读缓冲区
		COleSafeArray fs;
		fs = InputData;	//VARIANT型变À量转换为COleSafeArray型变量
		len1 = fs.GetOneDimSize();
		len += len1 - 16;
		for (k = 0; k < fs.GetOneDimSize(); k++)
			fs.GetElement(&k, str + k);	//转换为BYTE型数组



		string txt = str ;
		size_t a = txt.find_last_of('X');
		size_t b = txt.find_first_of('Y');
		string res1 = txt.substr(a + 3, b - 2 - a - 3);


		size_t c = txt.find_last_of('Y');
		size_t d = txt.find_first_of('Z');
		string res2 = txt.substr(c + 3, d - 2 - c - 3);

		size_t e = txt.find_last_of('Z');
		size_t f = txt.find_first_of(']');
		string res3 = txt.substr(e + 3, f - 2 - e - 2);

		CString res1_C, res2_C, res3_C;
		res1_C = res1.c_str();
		res2_C = res2.c_str(); 
		res3_C = res3.c_str();
		m_EditReceive1 += res1_C;      //	接收到编辑框里面
		m_EditReceive2 += res2_C;
		m_EditReceive3 += res3_C;

		x.push_back(res1_C);
		y.push_back(res2_C);
		z.push_back(res3_C);

		if (len > 1024)
		{
     
			m_EditReceive1 = _T("");	//给接收编辑框发送空格符
			m_EditReceive2 = _T("");
			m_EditReceive3 = _T("");
			UpdateData(false);
			len = 0;
		}

		m_EditReceive1 += "\r\n";      //	接收到编辑框里面进行换行
		m_EditReceive2 += "\r\n";
		m_EditReceive3 += "\r\n";


		//SetTimer(1,10,NULL);		//延时10ms
		UpdateData(false);

		//m_Edit1.SetSel(-1, -1);
		//this->SetDlgItemTextW(IDC_EDIT1, m_EditReceive1);//将m_EditReceive内容显示到ID为IDC_EDIT1的编辑框的最后位置
		//m_Edit1.LineScroll(m_Edit1.GetLineCount() - 1, 0);//将垂直滚动条滚动到最后一

		//m_Edit2.SetSel(-1, -1);
		//this->SetDlgItemTextW(IDC_EDIT2, m_EditReceive2);//将m_EditReceive内容显示到ID为IDC_EDIT1的编辑框的最后位置
		//m_Edit2.LineScroll(m_Edit2.GetLineCount() - 1, 0);//将垂直滚动条滚动到最后一

		//m_Edit3.SetSel(-1, -1);
		//this->SetDlgItemTextW(IDC_EDIT3, m_EditReceive3);//将m_EditReceive内容显示到ID为IDC_EDIT1的编辑框的最后位置
		//m_Edit3.LineScroll(m_Edit3.GetLineCount() - 1, 0);//将垂直滚动条滚动到最后一
		double dispaly_tmp = strtod(str, NULL);
		//double m = _ttof(dispaly_tmp);
		double dispaly_tmp1 = _ttof(res1_C);
		lineSeries0.AddXY((double)num_iput, dispaly_tmp1, NULL, 0);
		double dispaly_tmp2 = _ttof(res2_C);
		lineSeries1.AddXY((double)num_iput, dispaly_tmp2, NULL, 0);
		double dispaly_tmp3 = _ttof(res3_C);
		lineSeries2.AddXY((double)num_iput, dispaly_tmp3, NULL, 0);
		num_iput++;
		if (num_iput > 100)
		{
     
			lineSeries0.Clear();
			lineSeries1.Clear();
			lineSeries2.Clear();
		    num_iput = 1;

		}
	}
}


void C串口V1Dlg::OnBnClickedButtonSave()
{
     
	// TODO:  在此添加控件通知处理程序代码
	// UpdateDate(TRUE);

	for (int i = 0; i < x.size(); i++)
	{
     
		CString local_X = x[i].GetBuffer();
		CString local_Y = y[i].GetBuffer();
		CString local_Z = z[i].GetBuffer();
		// 创建 MYSQL 对象。
		MYSQL local_mysql;
		// 初始化 MYSQL 对象。
		mysql_init(&local_mysql);
		// 连接数据库
		if (!mysql_real_connect(&local_mysql, "localhost", "root", "123456", "test", 3306, NULL, 0))
		{
     
			AfxMessageBox(_T("connect to database failed!"));
		}
		else
		{
     
			//AfxMessageBox(_T("connect to database success!"));
			// 设置字符集, 使程序支持中文。
			mysql_query(&local_mysql, "set names 'gb2312'");
		}

		// 创建 SQL 语句字符串
		CString sql_insert;
		//sql_insert.Format(_T("insert into test.emp_test(X, Y, Z) values (2, 2, 3)"))/* local_X, local_Y, local_Z*/;
		// 执行 sql 语句。
		// mysql_query() 的返回值份很多情形, 进行判断使要注意。
		char insert[1024];

		sprintf_s(insert, "insert into test.emp_test(X, Y, Z) values (\'%s\', \'%s\', \'%s\')", local_X, local_Y, local_Z);
		if (mysql_query(&local_mysql, insert) == 0)
		{
     
			//AfxMessageBox(_T("insert succeed!"));
		}
		else{
     
			AfxMessageBox(_T("insert failed!"));
		}
	}
	// 关闭 local_mysql 所关联的数据库连接, 一般情况下不用写。
	//mysql_close(&local_mysql);
	UpdateData(FALSE)}









你可能感兴趣的:(VS+MFC)