码迷,mamicode.com
首页 > 编程语言 > 详细

VS2015编写的MFC上位机,波特率可调,可动态显示曲线,可显示三维

时间:2018-11-19 14:11:03      阅读:233      评论:0      收藏:0      [点我收藏+]

标签:har   缓冲区   form   介绍   动态   enum   教学   com   vpp   

 

VS2015编写的MFC上位机,波特率可调,可动态显示曲线,可显示三维

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_17783559/article/details/50516228

近期做一个项目正好涉及MFC编写串口上位机,主要用于动态显示曲线和陀螺仪三维信息,想做飞思卡尔或者四旋翼的小伙伴可以借鉴一下,首先贴个结果图:

技术分享图片

下面来简单讲解一下这个上位机的核心步骤:

1、首先新建一个串口通信的程序,网上的示例代码有很多,详细的教学文档下载:

http://download.csdn.net/detail/plutus_lee/4525446

2、自动搜索可用串口

新建一个Combo-box Control控件,ID为IDC_COMBO_COM,并输入可选择数据

技术分享图片

在OnInitDialog()中调用MYUART_GetComNum()函数即可获得当前可用的串口号,并显示在IDC_COMBO_COM控件中

MYUART_GetComNum()函数如下:


bool CfuzhikejiDlg::MYUART_GetComNum(void)
{
long lReg;
HKEY hKey;
DWORD MaxValueLength;
DWORD dwValueNumber;


lReg = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
0, KEY_QUERY_VALUE, &hKey);


if (lReg != ERROR_SUCCESS) //成功时返回ERROR_SUCCESS,
{
//MessageBox(TEXT("未自动找到串口!\nOpen Registry Error!\n"));
return FALSE;
}


lReg = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
&dwValueNumber, &MaxValueLength, NULL, NULL, NULL);


if (lReg != ERROR_SUCCESS) //没有成功
{
//MessageBox(TEXT("未自动找到串口!\nGetting Info Error!\n"));
return FALSE;
}


TCHAR *pValueName, *pCOMNumber;
DWORD cchValueName, dwValueSize = 10;


for (int i = 0; i < dwValueNumber; i++)
{
cchValueName = MaxValueLength + 1;
dwValueSize = 10;
pValueName = (TCHAR*)VirtualAlloc(NULL, cchValueName, MEM_COMMIT, PAGE_READWRITE);
lReg = RegEnumValue(hKey, i, pValueName,
&cchValueName, NULL, NULL, NULL, NULL);


if ((lReg != ERROR_SUCCESS) && (lReg != ERROR_NO_MORE_ITEMS))
{
//MessageBox(TEXT("未自动找到串口!\nEnum Registry Error or No More Items!\n"));
return FALSE;
}


pCOMNumber = (TCHAR*)VirtualAlloc(NULL, 6, MEM_COMMIT, PAGE_READWRITE);
lReg = RegQueryValueEx(hKey, pValueName, NULL,
NULL, (LPBYTE)pCOMNumber, &dwValueSize);


if (lReg != ERROR_SUCCESS)
{
//MessageBox(TEXT("未自动找到串口!\nCan not get the name of the port"));
return FALSE;
}


CString str(pCOMNumber);
int len=str.GetLength();
str = str.Right(len - 3);
((CComboBox*)GetDlgItem(IDC_COMBO_COM))->SetCurSel(atoi(str)-1);//把获取的值加入到ComBox控件中
VirtualFree(pValueName, 0, MEM_RELEASE);
VirtualFree(pCOMNumber, 0, MEM_RELEASE);
}


return TRUE;
}

说明:

pCOMNumber即为可用的COM口号,如果在设备管理器里面有COM3口可用,那么CString str(pCOMNumber)执行后,str的值为“COM3”

 

2、更改波特率等参数

新建Combo-box Control控件,ID分别为IDC_COMBO_BOTELV、IDC_COMBO_JIAOYANWEI、IDC_COMBO_SHUJUWEI 、IDC_COMBO_TINGZHIWEI,并输入可选择数据如下:

技术分享图片技术分享图片技术分享图片技术分享图片

在OnInitDialog()中设置初始值

((CComboBox*)GetDlgItem(IDC_COMBO_BOTELV))->SetCurSel(0);
((CComboBox*)GetDlgItem(IDC_COMBO_JIAOYANWEI))->SetCurSel(2);
((CComboBox*)GetDlgItem(IDC_COMBO_SHUJUWEI))->SetCurSel(3);
((CComboBox*)GetDlgItem(IDC_COMBO_TINGZHIWEI))->SetCurSel(0);

添加“打开串口按钮”,添加点击事件如下:

void CfuzhikejiDlg::OnBnClickedButtonOpencom()
{
// TODO: 在此添加控件通知处理程序代码
if (m_cComm.get_PortOpen()) //如果发现串口本来是打开的,则关闭串口
m_cComm.put_PortOpen(FALSE);
CString m_Combo_COM;
GetDlgItemText(IDC_COMBO_COM, m_Combo_COM);
int len = m_Combo_COM.GetLength();
m_Combo_COM = m_Combo_COM.Right(len - 3);
m_cComm.put_CommPort(atoi(m_Combo_COM));        //选择COM端口
m_cComm.put_InputMode(1);       //输入方式为二进制方式
m_cComm.put_InBufferSize(1024); //设置输入缓冲区
m_cComm.put_OutBufferSize(1024); //设置输出缓冲区
CString str;
int m_Combo_BOTELV = GetDlgItemInt(IDC_COMBO_BOTELV);
str.Format(_T("%d,"), m_Combo_BOTELV);
CString m_Combo_JIAOYANWEI, m_Combo_SHUJUWEI, m_Combo_TINGZHIWEI;
GetDlgItemText(IDC_COMBO_JIAOYANWEI, m_Combo_JIAOYANWEI);
GetDlgItemText(IDC_COMBO_SHUJUWEI, m_Combo_SHUJUWEI);
GetDlgItemText(IDC_COMBO_TINGZHIWEI, m_Combo_TINGZHIWEI);
str = str + m_Combo_JIAOYANWEI+_T(",")+ m_Combo_SHUJUWEI+_T(",")+ m_Combo_TINGZHIWEI;
m_cComm.put_Settings(str);//波特率,无校验,个数据位,个停止位
//m_cComm.put_Settings(TEXT("9600,n,8,1"));//波特率,无校验,个数据位,个停止位
if (!m_cComm.get_PortOpen())
{
m_cComm.put_PortOpen(TRUE); //打开串口
m_cComm.put_RThreshold(16); //每当接收缓冲区有个字符则接收串口数据
m_cComm.put_InputLen(0); //设置当前缓冲区长度为0
m_cComm.get_Input(); //预读缓冲区以清除残留数据
AfxMessageBox(_T("串口打开成功!"));
}
else
AfxMessageBox("打开端口失败!", MB_ICONSTOP, 0);
}

红色标注部分为更改参数得代码,都是些简单的语句,就不做介绍了。

每次接收16个字节,最后两位为CRC16校验位,由单片机中发送的。

3、接收到数据的处理

void CfuzhikejiDlg::OnComm()
{
// TODO: 在此处添加消息处理程序代码
//从串口接收数据并显示在编辑框中
VARIANT variant_inp;
COleSafeArray safearray_inp;
long len, k;
byte rxdata[512]; //设置BYTE数组
CString strtemp;
unsigned short CRC16 = 0;
short temp[4];
short temp1[3];
float temp_y_axis[4];
if (m_cComm.get_CommEvent() == 2) //值为表示接收缓冲区内有字符
{
variant_inp = m_cComm.get_Input(); //读缓冲区消息
safearray_inp = variant_inp; //变量转换
len = safearray_inp.GetOneDimSize(); //得到有效的数据长度
for (k = 0; k < len; k++)
safearray_inp.GetElement(&k, rxdata + k);
CRC16 = CRC_CHECK(rxdata, len);//CRC16校验
if (CRC16 == 0&& View_Flag ==TRUE)
{
for (k = 0; k < 4; k++) //将数组转换为CString型变量,不包含校验位
{
temp[k] = (short)((rxdata[2 * k + 1] << 8 )| (rxdata[2 * k]));
temp_y_axis[k] = (float)temp[k];
m_plot.AddNewPoint(m_time, temp_y_axis[k], k);
}
m_time += 0.20f;
}
if (CRC16 == 0)
{
temp1[0] = (short)((rxdata[9] << 8) | (rxdata[8]));
temp1[1] = (short)((rxdata[11] << 8) | (rxdata[10]));
temp1[2] = (short)((rxdata[13] << 8) | (rxdata[12]));
m_OpenGL.m_xAngle = temp1[1] / 10;
m_OpenGL.m_yAngle = -temp1[2] / 10;
m_OpenGL.m_zAngle = temp1[0] / 10;
m_OpenGL.InvalidateRect(NULL, FALSE);
}
for (k = 0; k < len; k++) //将数组转换为CString型变量
{
if (k == len - 1)
{
char bt = *(char*)(rxdata + k); //字符型
strtemp.Format("%c", bt); //将字符送入临时变量strtemp存放
m_strRecvData += strtemp; //加入接收编辑框对应字符串
}
}
}
SetDlgItemText(IDC_EDIT_RECV, m_strRecvData);
//UpdateData(FALSE); //更新编辑框内容
m_strRecvData.Empty();
}

黄色背景处代码为:绘制动态曲线的添加点的代码,红色背景为显示陀螺仪三维欧拉角的代码。

16个8位数据储存内容为,第1-8个8位数据为4个16字节绘制动态曲线的数据,一共可绘制四条,第9-14个8位数据为3个16字节陀螺仪三维欧拉角的数据,对应翻滚角,俯仰角和偏航角。

4、绘制动态曲线

主要是参考这篇博文编的http://blog.csdn.net/nuaazdh/article/details/7857223

自己加入按住右键拖动,方向键左右移动,滚动鼠标中键放大缩小等功能。

void CPlot::OnMouseMove(UINT nFlags, CPoint point)
{
if (LBTNDOWN_FLAG)
{
LBTNMOWE_FLAG = TRUE;
m_midPoint = point;
OnPaint();//重绘
}
if (RBTNDOWN_FLAG)
{
m_RendPoint = point;
m_XLwLmt_Trace -= (m_RendPoint.x - m_RstartPoint.x)*m_vppXAxis;
m_XUpLmt_Trace -= (m_RendPoint.x - m_RstartPoint.x)*m_vppXAxis;
m_YLwLmt_Trace += (m_RendPoint.y - m_RstartPoint.y)*m_vppYAxis;
m_YUpLmt_Trace += (m_RendPoint.y - m_RstartPoint.y)*m_vppYAxis;
m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);
m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);
OnPaint();
m_RstartPoint = m_RendPoint;


}
}
void CPlot::OnLButtonUp(UINT nFlag,CPoint point)
{
LBTNDOWN_FLAG = FALSE;
LBTNMOWE_FLAG = FALSE;
m_endPoint = point;
ScaleProcess();// 缩放处理
OnPaint(); // 重绘
TRACE("Left Button Up.Point Coordinate:x=%d,y=%d.\n",point.x,point.y);
CStatic::OnLButtonUp(nFlag,point);
}


void CPlot::OnLButtonDblClk( UINT nFlags, CPoint point )
{
m_bAdjustable = TRUE;// 重新进行自调整
m_axisX.SetAxisRange(m_originXLwLmt,m_originXUpLmt);
m_axisY.SetAxisRange(m_originYLwLmt,m_originYUpLmt);
m_XLwLmt_Trace = m_originXLwLmt;
m_XUpLmt_Trace = m_originXUpLmt;
m_YLwLmt_Trace = m_originYLwLmt;
m_YUpLmt_Trace = m_originYUpLmt;
OnPaint(); // 重绘
CStatic::OnLButtonDblClk(nFlags,point);
}
BOOL CPlot::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
// TODO: Add your message handler code here and/or call default
float proportion=(m_rectPlot.right- m_rectPlot.left)/(m_rectPlot.bottom- m_rectPlot.top);
m_XLwLmt_Trace -= 2.0*zDelta / 120;
m_XUpLmt_Trace += 2.0*zDelta / 120;
m_YLwLmt_Trace -= 2.0* proportion*zDelta / 120;
m_YUpLmt_Trace += 2.0* proportion*zDelta / 120;
m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);
m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);
OnPaint();
//InvalidateRect(NULL, FALSE);//效果一样
return CStatic::OnMouseWheel(nFlags, zDelta, pt);
}
BOOL CPlot::PreTranslateMessage(MSG* pMsg)
{
// TODO: 在此添加专用代码和/或调用基类
float proportion = (m_rectPlot.right - m_rectPlot.left) / (m_rectPlot.bottom - m_rectPlot.top);
if (pMsg->message == WM_KEYDOWN)
{
switch (pMsg->wParam)
{
case VK_UP:     
m_YLwLmt_Trace -= 2.0* proportion;
m_YUpLmt_Trace -= 2.0* proportion;
m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);
m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);
OnPaint();
return TRUE;
break;
case VK_DOWN:   
m_YLwLmt_Trace += 2.0* proportion;
m_YUpLmt_Trace += 2.0* proportion;
m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);
m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);
OnPaint();
return TRUE;
break;
case VK_LEFT:   
m_XLwLmt_Trace += 2.0;
m_XUpLmt_Trace += 2.0;
m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);
m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);
OnPaint();
return TRUE;
break;
case VK_RIGHT:  
m_XLwLmt_Trace -= 2.0;
m_XUpLmt_Trace -= 2.0;
m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);
m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);
OnPaint();
return TRUE;
break;
default:        MessageBox("Press the arrow keys only");
return TRUE;
break;
}
}
return FALSE;
}
void CPlot::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_RstartPoint = point;
RBTNDOWN_FLAG = TRUE;
CStatic::OnRButtonDown(nFlags, point);
}


void CPlot::OnRButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
RBTNDOWN_FLAG = FALSE;
CStatic::OnRButtonUp(nFlags, point);
}

5、OPENGL绘制三维图

参考绘制代码下载:http://download.csdn.net/download/qian365013263/2276152

我主要是基于以上的绘制方法改动得到自己的绘制结果的,因为上面是单文档程序需要我们转成对话框程序,转换并不难但是记得最后调用析构函数去除野指针:

重载函数如下:

OpenGLView::~OpenGLView()
{
if (::wglMakeCurrent(0, 0) == FALSE)
MessageBox("Could not make RC non-current");
if (::wglDeleteContext(m_hRC) == FALSE)
MessageBox("Could not delete RC");
if (m_pDC)
delete m_pDC;
m_pDC = NULL;
}

 

 

最后经过我的各种融合,总算是完成了这个工程,虽然不是所有代码都是自己编的,但是也没有看到相关方面的工程,姑且算个原创吧!

链接: http://pan.baidu.com/s/1bnINhxl 密码: w4z2

我的工程文件105M,为什么这么大啊,求解??

近期做一个项目正好涉及MFC编写串口上位机,主要用于动态显示曲线和陀螺仪三维信息,想做飞思卡尔或者四旋翼的小伙伴可以借鉴一下,首先贴个结果图:


下面来简单讲解一下这个上位机的核心步骤:
1、首先新建一个串口通信的程序,网上的示例代码有很多,详细的教学文档下载:
http://download.csdn.net/detail/plutus_lee/4525446
2、自动搜索可用串口
新建一个Combo-box Control控件,ID为IDC_COMBO_COM,并输入可选择数据


在OnInitDialog()中调用MYUART_GetComNum()函数即可获得当前可用的串口号,并显示在IDC_COMBO_COM控件中
MYUART_GetComNum()函数如下:

bool CfuzhikejiDlg::MYUART_GetComNum(void){long lReg;HKEY hKey;DWORD MaxValueLength;DWORD dwValueNumber;

lReg = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"),0, KEY_QUERY_VALUE, &hKey);

if (lReg != ERROR_SUCCESS) //成功时返回ERROR_SUCCESS,{//MessageBox(TEXT("未自动找到串口!\nOpen Registry Error!\n"));return FALSE;}

lReg = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,&dwValueNumber, &MaxValueLength, NULL, NULL, NULL);

if (lReg != ERROR_SUCCESS) //没有成功{//MessageBox(TEXT("未自动找到串口!\nGetting Info Error!\n"));return FALSE;}

TCHAR *pValueName, *pCOMNumber;DWORD cchValueName, dwValueSize = 10;

for (int i = 0; i < dwValueNumber; i++){cchValueName = MaxValueLength + 1;dwValueSize = 10;pValueName = (TCHAR*)VirtualAlloc(NULL, cchValueName, MEM_COMMIT, PAGE_READWRITE);lReg = RegEnumValue(hKey, i, pValueName,&cchValueName, NULL, NULL, NULL, NULL);

if ((lReg != ERROR_SUCCESS) && (lReg != ERROR_NO_MORE_ITEMS)){//MessageBox(TEXT("未自动找到串口!\nEnum Registry Error or No More Items!\n"));return FALSE;}

pCOMNumber = (TCHAR*)VirtualAlloc(NULL, 6, MEM_COMMIT, PAGE_READWRITE);lReg = RegQueryValueEx(hKey, pValueName, NULL,NULL, (LPBYTE)pCOMNumber, &dwValueSize);

if (lReg != ERROR_SUCCESS){//MessageBox(TEXT("未自动找到串口!\nCan not get the name of the port"));return FALSE;}

CString str(pCOMNumber);int len=str.GetLength();str = str.Right(len - 3);((CComboBox*)GetDlgItem(IDC_COMBO_COM))->SetCurSel(atoi(str)-1);//把获取的值加入到ComBox控件中VirtualFree(pValueName, 0, MEM_RELEASE);VirtualFree(pCOMNumber, 0, MEM_RELEASE);}

return TRUE;}
说明:
pCOMNumber即为可用的COM口号,如果在设备管理器里面有COM3口可用,那么CString str(pCOMNumber)执行后,str的值为“COM3”
 
2、更改波特率等参数
新建Combo-box Control控件,ID分别为IDC_COMBO_BOTELV、IDC_COMBO_JIAOYANWEI、IDC_COMBO_SHUJUWEI 、IDC_COMBO_TINGZHIWEI,并输入可选择数据如下:


在OnInitDialog()中设置初始值
((CComboBox*)GetDlgItem(IDC_COMBO_BOTELV))->SetCurSel(0);((CComboBox*)GetDlgItem(IDC_COMBO_JIAOYANWEI))->SetCurSel(2);((CComboBox*)GetDlgItem(IDC_COMBO_SHUJUWEI))->SetCurSel(3);((CComboBox*)GetDlgItem(IDC_COMBO_TINGZHIWEI))->SetCurSel(0);
添加“打开串口按钮”,添加点击事件如下:
void CfuzhikejiDlg::OnBnClickedButtonOpencom(){// TODO: 在此添加控件通知处理程序代码if (m_cComm.get_PortOpen()) //如果发现串口本来是打开的,则关闭串口m_cComm.put_PortOpen(FALSE);CString m_Combo_COM;GetDlgItemText(IDC_COMBO_COM, m_Combo_COM);int len = m_Combo_COM.GetLength();m_Combo_COM = m_Combo_COM.Right(len - 3);m_cComm.put_CommPort(atoi(m_Combo_COM));        //选择COM端口m_cComm.put_InputMode(1);       //输入方式为二进制方式m_cComm.put_InBufferSize(1024); //设置输入缓冲区m_cComm.put_OutBufferSize(1024); //设置输出缓冲区CString str;int m_Combo_BOTELV = GetDlgItemInt(IDC_COMBO_BOTELV);str.Format(_T("%d,"), m_Combo_BOTELV);CString m_Combo_JIAOYANWEI, m_Combo_SHUJUWEI, m_Combo_TINGZHIWEI;GetDlgItemText(IDC_COMBO_JIAOYANWEI, m_Combo_JIAOYANWEI);GetDlgItemText(IDC_COMBO_SHUJUWEI, m_Combo_SHUJUWEI);GetDlgItemText(IDC_COMBO_TINGZHIWEI, m_Combo_TINGZHIWEI);str = str + m_Combo_JIAOYANWEI+_T(",")+ m_Combo_SHUJUWEI+_T(",")+ m_Combo_TINGZHIWEI;m_cComm.put_Settings(str);//波特率,无校验,个数据位,个停止位//m_cComm.put_Settings(TEXT("9600,n,8,1"));//波特率,无校验,个数据位,个停止位if (!m_cComm.get_PortOpen()){m_cComm.put_PortOpen(TRUE); //打开串口m_cComm.put_RThreshold(16); //每当接收缓冲区有个字符则接收串口数据m_cComm.put_InputLen(0); //设置当前缓冲区长度为0m_cComm.get_Input(); //预读缓冲区以清除残留数据AfxMessageBox(_T("串口打开成功!"));}elseAfxMessageBox("打开端口失败!", MB_ICONSTOP, 0);}
红色标注部分为更改参数得代码,都是些简单的语句,就不做介绍了。
每次接收16个字节,最后两位为CRC16校验位,由单片机中发送的。
3、接收到数据的处理
void CfuzhikejiDlg::OnComm(){// TODO: 在此处添加消息处理程序代码//从串口接收数据并显示在编辑框中VARIANT variant_inp;COleSafeArray safearray_inp;long len, k;byte rxdata[512]; //设置BYTE数组CString strtemp;unsigned short CRC16 = 0;short temp[4];short temp1[3];float temp_y_axis[4];if (m_cComm.get_CommEvent() == 2) //值为表示接收缓冲区内有字符{variant_inp = m_cComm.get_Input(); //读缓冲区消息safearray_inp = variant_inp; //变量转换len = safearray_inp.GetOneDimSize(); //得到有效的数据长度for (k = 0; k < len; k++)safearray_inp.GetElement(&k, rxdata + k);CRC16 = CRC_CHECK(rxdata, len);//CRC16校验if (CRC16 == 0&& View_Flag ==TRUE){for (k = 0; k < 4; k++) //将数组转换为CString型变量,不包含校验位{temp[k] = (short)((rxdata[2 * k + 1] << 8 )| (rxdata[2 * k]));temp_y_axis[k] = (float)temp[k];m_plot.AddNewPoint(m_time, temp_y_axis[k], k);}m_time += 0.20f;}if (CRC16 == 0){temp1[0] = (short)((rxdata[9] << 8) | (rxdata[8]));temp1[1] = (short)((rxdata[11] << 8) | (rxdata[10]));temp1[2] = (short)((rxdata[13] << 8) | (rxdata[12]));m_OpenGL.m_xAngle = temp1[1] / 10;m_OpenGL.m_yAngle = -temp1[2] / 10;m_OpenGL.m_zAngle = temp1[0] / 10;m_OpenGL.InvalidateRect(NULL, FALSE);}for (k = 0; k < len; k++) //将数组转换为CString型变量{if (k == len - 1){char bt = *(char*)(rxdata + k); //字符型strtemp.Format("%c", bt); //将字符送入临时变量strtemp存放m_strRecvData += strtemp; //加入接收编辑框对应字符串}}}SetDlgItemText(IDC_EDIT_RECV, m_strRecvData);//UpdateData(FALSE); //更新编辑框内容m_strRecvData.Empty();}
黄色背景处代码为:绘制动态曲线的添加点的代码,红色背景为显示陀螺仪三维欧拉角的代码。
16个8位数据储存内容为,第1-8个8位数据为4个16字节绘制动态曲线的数据,一共可绘制四条,第9-14个8位数据为3个16字节陀螺仪三维欧拉角的数据,对应翻滚角,俯仰角和偏航角。
4、绘制动态曲线
主要是参考这篇博文编的http://blog.csdn.net/nuaazdh/article/details/7857223
自己加入按住右键拖动,方向键左右移动,滚动鼠标中键放大缩小等功能。
void CPlot::OnMouseMove(UINT nFlags, CPoint point){if (LBTNDOWN_FLAG){LBTNMOWE_FLAG = TRUE;m_midPoint = point;OnPaint();//重绘}if (RBTNDOWN_FLAG){m_RendPoint = point;m_XLwLmt_Trace -= (m_RendPoint.x - m_RstartPoint.x)*m_vppXAxis;m_XUpLmt_Trace -= (m_RendPoint.x - m_RstartPoint.x)*m_vppXAxis;m_YLwLmt_Trace += (m_RendPoint.y - m_RstartPoint.y)*m_vppYAxis;m_YUpLmt_Trace += (m_RendPoint.y - m_RstartPoint.y)*m_vppYAxis;m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);OnPaint();m_RstartPoint = m_RendPoint;

}}void CPlot::OnLButtonUp(UINT nFlag,CPoint point){LBTNDOWN_FLAG = FALSE;LBTNMOWE_FLAG = FALSE;m_endPoint = point;ScaleProcess();// 缩放处理OnPaint(); // 重绘TRACE("Left Button Up.Point Coordinate:x=%d,y=%d.\n",point.x,point.y);CStatic::OnLButtonUp(nFlag,point);}

void CPlot::OnLButtonDblClk( UINT nFlags, CPoint point ){m_bAdjustable = TRUE;// 重新进行自调整m_axisX.SetAxisRange(m_originXLwLmt,m_originXUpLmt);m_axisY.SetAxisRange(m_originYLwLmt,m_originYUpLmt);m_XLwLmt_Trace = m_originXLwLmt;m_XUpLmt_Trace = m_originXUpLmt;m_YLwLmt_Trace = m_originYLwLmt;m_YUpLmt_Trace = m_originYUpLmt;OnPaint(); // 重绘CStatic::OnLButtonDblClk(nFlags,point);}BOOL CPlot::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt){// TODO: Add your message handler code here and/or call defaultfloat proportion=(m_rectPlot.right- m_rectPlot.left)/(m_rectPlot.bottom- m_rectPlot.top);m_XLwLmt_Trace -= 2.0*zDelta / 120;m_XUpLmt_Trace += 2.0*zDelta / 120;m_YLwLmt_Trace -= 2.0* proportion*zDelta / 120;m_YUpLmt_Trace += 2.0* proportion*zDelta / 120;m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);OnPaint();//InvalidateRect(NULL, FALSE);//效果一样return CStatic::OnMouseWheel(nFlags, zDelta, pt);}BOOL CPlot::PreTranslateMessage(MSG* pMsg){// TODO: 在此添加专用代码和/或调用基类float proportion = (m_rectPlot.right - m_rectPlot.left) / (m_rectPlot.bottom - m_rectPlot.top);if (pMsg->message == WM_KEYDOWN){switch (pMsg->wParam){case VK_UP:     m_YLwLmt_Trace -= 2.0* proportion;m_YUpLmt_Trace -= 2.0* proportion;m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);OnPaint();return TRUE;break;case VK_DOWN:   m_YLwLmt_Trace += 2.0* proportion;m_YUpLmt_Trace += 2.0* proportion;m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);OnPaint();return TRUE;break;case VK_LEFT:   m_XLwLmt_Trace += 2.0;m_XUpLmt_Trace += 2.0;m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);OnPaint();return TRUE;break;case VK_RIGHT:  m_XLwLmt_Trace -= 2.0;m_XUpLmt_Trace -= 2.0;m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);OnPaint();return TRUE;break;default:        MessageBox("Press the arrow keys only");return TRUE;break;}}return FALSE;}void CPlot::OnRButtonDown(UINT nFlags, CPoint point){// TODO: 在此添加消息处理程序代码和/或调用默认值m_RstartPoint = point;RBTNDOWN_FLAG = TRUE;CStatic::OnRButtonDown(nFlags, point);}

void CPlot::OnRButtonUp(UINT nFlags, CPoint point){// TODO: 在此添加消息处理程序代码和/或调用默认值RBTNDOWN_FLAG = FALSE;CStatic::OnRButtonUp(nFlags, point);}
5、OPENGL绘制三维图
参考绘制代码下载:http://download.csdn.net/download/qian365013263/2276152
我主要是基于以上的绘制方法改动得到自己的绘制结果的,因为上面是单文档程序需要我们转成对话框程序,转换并不难但是记得最后调用析构函数去除野指针:
重载函数如下:
OpenGLView::~OpenGLView(){if (::wglMakeCurrent(0, 0) == FALSE)MessageBox("Could not make RC non-current");if (::wglDeleteContext(m_hRC) == FALSE)MessageBox("Could not delete RC");if (m_pDC)delete m_pDC;m_pDC = NULL;}
 
 
最后经过我的各种融合,总算是完成了这个工程,虽然不是所有代码都是自己编的,但是也没有看到相关方面的工程,姑且算个原创吧!
链接: http://pan.baidu.com/s/1bnINhxl 密码: w4z2
我的工程文件105M,为什么这么大啊,求解??--------------------- 作者:博博有个大大大的Dream 来源:CSDN 原文:https://blog.csdn.net/qq_17783559/article/details/50516228 版权声明:本文为博主原创文章,转载请附上博文链接!

VS2015编写的MFC上位机,波特率可调,可动态显示曲线,可显示三维

标签:har   缓冲区   form   介绍   动态   enum   教学   com   vpp   

原文地址:https://www.cnblogs.com/tianqiang/p/9982684.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!