MFC中teechart接收Mscomm串口数据绘图问题.

bolong2017 发布于 2017/07/13 17:27
阅读 887
收藏 0

【开源中国 APP 全新上线】“动弹” 回归、集成大模型对话、畅读技术报告”

 在Mscomm控件接收每100ms的串口数据时,能在文本框显示接收的数据。但teechart控件在接收数据并绘制一部分图后就停止绘制后面的曲线图了。  teechart的绘图函数是在Mscomm的oncomm响应事件中的。代码如下:

// comm1.2Dlg.cpp : 实现文件
//

#include "stdafx.h"
#include "comm1.2.h"
#include "comm1.2Dlg.h"
#include "CSeries.h"
#include "CLegend.h"
#include "CAxes.h"
#include "CAxis.h"
#include "CScroll.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif



// Ccomm12Dlg 对话框




Ccomm12Dlg::Ccomm12Dlg(CWnd* pParent /*=NULL*/)
	: CDialog(Ccomm12Dlg::IDD, pParent)
	, m_EditRxData(_T(""))
	, m_EditTxData(_T(""))
	, strtemp_recive_data(_T(""))
	, X(0)
	, Y(0)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void Ccomm12Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_EDIT_RXDATA, m_EditRxData);
	DDX_Text(pDX, IDC_EDIT_TXDATA, m_EditTxData);
	DDX_Control(pDX, IDC_TAB1, m_TabCtrl);
	DDX_Control(pDX, IDC_COMBO_SERIALPORT, m_ComBo_SerialPort);
	DDX_Control(pDX, IDC_COMBO_BAUD, m_ComBo_Baud);
	DDX_Control(pDX, IDC_COMBO_CAL, m_ComBo_Cal);
	DDX_Control(pDX, IDC_COMBO_BDATA, m_ComBo_BData);
	DDX_Control(pDX, IDC_COMBO_BSTOP, m_ComBo_BStop);
	DDX_Control(pDX, IDC_BUTTON_POORTOPEN, m_Button_Open);
	DDX_Control(pDX, IDC_BUTTON_PORTCLOSE, m_Button_Close);
	DDX_Control(pDX, IDC_BUTTON_SEND, m_Button_Send);
	DDX_Control(pDX, IDC_MSCOMM1, m_CtrlComm);
}

BEGIN_MESSAGE_MAP(Ccomm12Dlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BUTTON_POORTOPEN, &Ccomm12Dlg::OnBnClickedButtonPoortopen)
	ON_BN_CLICKED(IDC_BUTTON_PORTCLOSE, &Ccomm12Dlg::OnBnClickedButtonPortclose)
	ON_BN_CLICKED(IDC_BUTTON_SEND, &Ccomm12Dlg::OnBnClickedButtonSend)
	ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, &Ccomm12Dlg::OnTcnSelchangeTab1)
	ON_BN_CLICKED(IDC_CHECK1, &Ccomm12Dlg::OnBnClickedCheck1)
END_MESSAGE_MAP()


// Ccomm12Dlg 消息处理程序

BOOL Ccomm12Dlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	m_ComBo_SerialPort.AddString("COM1");
	m_ComBo_SerialPort.AddString("COM2");
	m_ComBo_SerialPort.AddString("COM3");
	m_ComBo_SerialPort.SetCurSel(0);

	m_ComBo_Baud.AddString("19200");
	m_ComBo_Baud.AddString("9600");
	m_ComBo_Baud.AddString("115200");
	m_ComBo_Baud.SetCurSel(1);

	m_ComBo_Cal.AddString("无校验");
	m_ComBo_Cal.AddString("奇校验");
	m_ComBo_Cal.AddString("偶校验");
	m_ComBo_Cal.SetCurSel(0);

	m_ComBo_BData.AddString("6");
	m_ComBo_BData.AddString("7");
	m_ComBo_BData.AddString("8");
	m_ComBo_BData.AddString("9");
	m_ComBo_BData.SetCurSel(2);

	m_ComBo_BStop.AddString("1位");
	m_ComBo_BStop.AddString("2位");
	m_ComBo_BStop.SetCurSel(0);

	if(m_CtrlComm.get_PortOpen())
		m_CtrlComm.put_PortOpen(FALSE);
	m_CtrlComm.put_CommPort(1);					//选择串口号1	
	m_CtrlComm.put_RThreshold(2);				//收到两个字节引发OnComm事件
	m_CtrlComm.put_InputMode(1);				//输入模式选为二进制
	m_CtrlComm.put_InBufferSize(1024);			//设置输入缓冲区的大小,Bytes
	m_CtrlComm.put_OutBufferSize(1024);			//设置输出缓冲区的大小,Bytes
	m_CtrlComm.put_Settings("19200,n,8,1");		//设置串口参数,波特率,无奇偶校验,8位数据位,1位停止位
	m_CtrlComm.put_InputMode(1);				//以二进制方法验取数据
//	m_CtrlComm.put_RThreshold(1);				//每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件
	m_CtrlComm.put_InputLen(0);					//设置当前接收区数据长度为0
	m_CtrlComm.put_PortOpen(TRUE);				//打开串口
	m_CtrlComm.get_Input();						//先预读缓冲区以清除残留数据 

	m_Button_Close.EnableWindow(FALSE);

	//添加选项卡名称
	TCITEM item;
	item.mask = TCIF_TEXT;
	item.pszText = "恒速恒力控制";
	m_TabCtrl.InsertItem(0,&item);
	item.pszText = "响应时间测试";
	m_TabCtrl.InsertItem(1,&item);

	//设置IDC_TAB1为父窗口
	page1.Create(IDD_DIALOGBAR1,&m_TabCtrl);
	page2.Create(IDD_DIALOGBAR2,&m_TabCtrl);

	//获得IDC_TABTEST客户区大小
	CRect rc;
	m_TabCtrl.GetClientRect(&rc);

	//调整子对话框在父窗口中的位置
	rc.top += 30;
	rc.bottom -= 8;
	rc.left += 8;
	rc.right -= 8;
	
	//设置子对话框尺寸并移动到指定位置
	page1.MoveWindow(&rc);
	page2.MoveWindow(&rc);

	//分别设置隐藏和显示
	page1.ShowWindow(true);
	page2.ShowWindow(false);

	//设置默认的选项卡
	m_TabCtrl.SetCurSel(0);

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

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

void Ccomm12Dlg::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
	{
		CDialog::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR Ccomm12Dlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void Ccomm12Dlg::OnBnClickedButtonPoortopen()
{
	// TODO: 在此添加控件通知处理程序代码
	CString strSerialPortText,strBaudRateText,strCheckDigitText,strDataBitsText,strStopBitText;
	int COM_NUM;
	CString SerialPortMessage;

	//串口数据类型转换
	m_ComBo_SerialPort.GetLBText(m_ComBo_SerialPort.GetCurSel(),strSerialPortText);
	m_ComBo_Baud.GetLBText(m_ComBo_Baud.GetCurSel(),strBaudRateText);
	m_ComBo_Cal.GetLBText(m_ComBo_Cal.GetCurSel(),strCheckDigitText);
	m_ComBo_BData.GetLBText(m_ComBo_BData.GetCurSel(),strDataBitsText);
	m_ComBo_BStop.GetLBText(m_ComBo_BStop.GetCurSel(),strStopBitText);
	COM_NUM = atoi(strSerialPortText.Mid(3));
	if(strCheckDigitText == "奇校验")
		strCheckDigitText = "o";
	else if(strCheckDigitText == "偶校验")
		strCheckDigitText = "e";
	else if(strCheckDigitText == "无校验")
		strCheckDigitText = "n";
	strStopBitText = strStopBitText.Left(strStopBitText.GetLength()-2);
	SerialPortMessage = strBaudRateText+","+strCheckDigitText+","+strDataBitsText+","+strStopBitText;

	this->m_ComBo_SerialPort.EnableWindow(FALSE);
	this->m_ComBo_Baud.EnableWindow(FALSE);
	this->m_ComBo_Cal.EnableWindow(FALSE);
	this->m_ComBo_BData.EnableWindow(FALSE);
	this->m_ComBo_BStop.EnableWindow(FALSE);
	this->m_Button_Close.EnableWindow(TRUE);
	m_Button_Open.EnableWindow(FALSE);

	if(m_CtrlComm.get_PortOpen())
		m_CtrlComm.put_PortOpen(FALSE);
	
	m_CtrlComm.put_CommPort(COM_NUM);			//选择串口号
	m_CtrlComm.put_RThreshold(2);				//收到两个字节引发OnComm事件
	m_CtrlComm.put_InputMode(1);				//输入模式选为二进制
	m_CtrlComm.put_InBufferSize(1024);			//设置输入缓冲区的大小,Bytes
	m_CtrlComm.put_OutBufferSize(1024);			//设置输出缓冲区的大小,Bytes
	m_CtrlComm.put_Settings(SerialPortMessage);	//设置串口参数,波特率,奇偶校验,数据位,停止位
	m_CtrlComm.put_InputMode(1);				//以二进制方法验取数据
//	m_CtrlComm.put_RThreshold(1);				//每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件
	m_CtrlComm.put_InputLen(0);					//设置当前接收区数据长度为0
//	m_ctrlComm.put_PortOpen(TRUE);				//打开串口

	if(!m_CtrlComm.get_PortOpen())
		m_CtrlComm.put_PortOpen(TRUE);
	else
		AfxMessageBox("Can not open serial port!");

	m_CtrlComm.get_Input();						//先预读缓冲区以清除残留数据
	UpdateData(FALSE);
}
BEGIN_EVENTSINK_MAP(Ccomm12Dlg, CDialog)
	ON_EVENT(Ccomm12Dlg, IDC_MSCOMM1, 1, Ccomm12Dlg::OnCommMscomm1, VTS_NONE)
END_EVENTSINK_MAP()

void Ccomm12Dlg::OnCommMscomm1()
{
	// TODO: 在此处添加消息处理程序代码
	VARIANT variant_inp;
	COleSafeArray safearray_inp;
	long len,k;
	BYTE rxdata[2048];
	BYTE bt = NULL;
	if(m_CtrlComm.get_CommEvent() == 2)					//事件值为2表示接收缓冲区内有字符
	{
		
		//以下你可以根据自己的通信协议加入处理代码
		UpdateData(TRUE);
		variant_inp = m_CtrlComm.get_Input();			//读缓冲区
		safearray_inp = variant_inp;					//VARIANT型变量转换为ColeSafeArray型变量
		len = safearray_inp.GetOneDimSize();			//得到有效数据长度
		for(k=0;k<len;k++)
			safearray_inp.GetElement(&k,rxdata+k);		//转换为BYTE型数组
		for(k=0;k<len;k++)								//将数组转换为Cstring型变量
		{
			bt = *(char*)(rxdata+k);					//字符型
			//strtemp_recive_data.Format("%X",bt);		//将字符送入临时变量strtemp存放 
			m_EditRxData+=bt;							//加入接收编辑框对应字符串 
			strtemp_recive_data+=bt;
		}
		while(!strtemp_recive_data.IsEmpty()&&AllisNum(strtemp_recive_data.Left(1)))
		{
			long count = 0;
			int i,nStart = 0,nEnd = 0,nX_End = 0;
			for(i=0;i<strtemp_recive_data.GetLength();i++)
			{
				if((strtemp_recive_data)[i] == ',')
				{
					count++;
					if(count == 1)
					{
						nX_End = i;
					}
					else if(count == 3)
					{
						nStart = i;
					}
					else if(count == 4)
					{
						nEnd = i;
						break;
					}
				}
			}
			CString strtempY = strtemp_recive_data.Mid(nStart+1,nEnd-nStart-1);
			if(AllisNum(strtempY))
				Y = atof(strtempY);
			else
				continue;
			
			CString strtempX = strtemp_recive_data.Left(nX_End);
			if(AllisNum(strtempX))
				X = atof(strtempX);
			else
				continue;
//================================================================================
			COleSafeArray XValues;
			COleSafeArray YValues;

			DWORD Xnum[] = {10000};
			DWORD Ynum[] = {10000};
			
			XValues.Create(VT_R8,1,Xnum);
			YValues.Create(VT_R8,1,Ynum);

			double tmp;
			long index = 0;
			for(long i=0;i<10;i++)
			{
				tmp = X;
				XValues.PutElement(&index,&tmp);
				tmp = Y;
				YValues.PutElement(&index,&tmp);
				index++;
			}

			CSeries serDemo = (CSeries)page1.m_CtrlTchart1.Series(0);
			serDemo.AddXY(X,Y,strtempX,0);
			CAxes chartaxis = (CAxes)page1.m_CtrlTchart1.get_Axis();
			CAxis chartaxisbottem = (CAxis)chartaxis.get_Bottom();
			chartaxisbottem.Scroll(1.0,TRUE);
			
			strtemp_recive_data.Empty();						//当字符串第一个为数字时清空
		}
		strtemp_recive_data.Empty();							//当字符串第一个不为数字时清空
	}
	UpdateData(FALSE);
	CEdit* pedit = (CEdit*)GetDlgItem(IDC_EDIT_RXDATA);
	pedit->LineScroll(pedit->GetLineCount());
}

void Ccomm12Dlg::OnBnClickedButtonPortclose()
{
	// TODO: 在此添加控件通知处理程序代码
	this->m_ComBo_SerialPort.EnableWindow(TRUE);
	this->m_ComBo_Baud.EnableWindow(TRUE);
	this->m_ComBo_Cal.EnableWindow(TRUE);
	this->m_ComBo_BData.EnableWindow(TRUE);
	this->m_ComBo_BStop.EnableWindow(TRUE);
	this->m_Button_Open.EnableWindow(TRUE);
	
	if(m_CtrlComm.get_PortOpen())
		m_CtrlComm.put_PortOpen(FALSE);
}

void Ccomm12Dlg::OnBnClickedButtonSend()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	m_CtrlComm.put_Output(COleVariant(m_EditTxData));
}

void Ccomm12Dlg::OnTcnSelchangeTab1(NMHDR *pNMHDR, LRESULT *pResult)
{
	// TODO: 在此添加控件通知处理程序代码
	int CurSel = m_TabCtrl.GetCurSel();

    switch(CurSel)
    {
    case 0:
		page1.ShowWindow(true);
		page2.ShowWindow(false);
        break;
    case 1:
		page1.ShowWindow(false);
		page2.ShowWindow(true);
        break;
    }
	*pResult = 0;
}

void Ccomm12Dlg::OnBnClickedCheck1()
{
	// TODO: 在此添加控件通知处理程序代码
	CButton* pBtn = (CButton*)GetDlgItem(IDC_CHECK1);
	CByteArray hexdata;
	int len;
	if(pBtn->GetCheck())
	{
		len = String2Hex("AABB04F87878FF",hexdata);
		m_CtrlComm.put_Output(COleVariant(hexdata));
	}
	else
	{
		len = String2Hex("AABB04F07070FF",hexdata);
		m_CtrlComm.put_Output(COleVariant(hexdata));
	}
	
}

// 十六进制转换函数
int Ccomm12Dlg::String2Hex(CString str, CByteArray& senddata)
{
	int hexdata,lowhexdata;
	int hexdatalen=0;
	int len=str.GetLength();
	senddata.SetSize(len/2);
	for(int i=0;i<len;)
	{
		char lstr,hstr=str[i];
		if(hstr==' ')
		{
			i++;
			continue;
		}
		i++;
		if(i>=len)
			break;
		lstr=str[i];
		hexdata=ConvertHexChar(hstr);
		lowhexdata=ConvertHexChar(lstr);
		if((hexdata==16)||(lowhexdata==16))
			break;
		else
			hexdata=hexdata*16+lowhexdata;
		i++;
		senddata[hexdatalen]=(char)hexdata;
		hexdatalen++;
	}
	senddata.SetSize(hexdatalen);
	return hexdatalen;
}

// 将一个字符转换为相应的十六进制
char Ccomm12Dlg::ConvertHexChar(char ch)
{
	if((ch>='0')&&(ch<='9'))
		return ch-0x30;
	else if((ch>='A')&&(ch<='F'))
		return ch-'A'+10;
	else if((ch>='a')&&(ch<='f'))
		return ch-'a'+10;
	else 
		return ch;
}
// 判断字符串是否为数字
bool Ccomm12Dlg::AllisNum(CString str)
{
	for(int i = 0;i<str.GetLength();i++)
	{
		int num = (int)str[i];
		if(num >=48 && num<= 57)
			continue;
		else
			return false;
	}
	return true;
}

运行到这里teechart就停止绘制曲线了,但文本框能正常显示继续接收的数据。这是不是与teechart的绘制效率有关?

加载中
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部