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

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

2016年01月14日 11:40:28 博博有个大大大的Dream 阅读数:9375

版权声明:本文为博主原创文章,未经博主允许不得转载。 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 版权声明:本文为博主原创文章,转载请附上博文链接!

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

时间: 2024-10-09 16:09:43

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

VC++编写简单串口上位机程序

转载: http://blog.sina.com.cn/s/articlelist_1809084904_0_1.html VC++编写简单串口上位机程序 串口通信,MCU跟PC通信经常用到的一种通信方式,做界面.写上位机程序的编程语言.编译环境等不少,VB.C#.LABVIEW等等,我会的语言很 少,C语言用得比较多,但是还没有找到如何用C语言来写串口通信上位机程序的资料,在图书管理找到了用VC++编写串口上位机的资料,参考书籍,用自己相 当蹩脚的C++写出了一个简单的串口上位机程序,分享一下

VS2015 编写USB通信上位机时,改变net框架导致DLL调用失败的问题解决方法

最近在写USB通信的上位机,调用了windows里的DLL,开发环境:64位WIN7 .VS2015.NET4.5.2:开发完成后在自己的电脑可用,在32位电脑.NET其他版本以及WIN10的环境下不可用,检测发现问题在于DLL的调用不成功,为了解决这个问题,查阅了几天的资料,现在终于解决了,记录下来以便忘记. 具体方法如下: 1.修改项目属性里的NET框架为4.0 2.修改配置管理器为X86 然后重新生成程序,问题解决.造成这个问题的原因主要有两个原因:1.NET版本过高,低版本不兼容:2.不

C#做一个简单的进行串口通信的上位机

C#做一个简单的进行串口通信的上位机 1.上位机与下位机 上位机相当于一个软件系统,可以用于接收数据.控制数据.即可以对接收到的数据直接发送操控命令来操作数据.上位机可以接收下位机的信号.下位机是一个控制器,是直接控制设备获取设备状况的计算机.上位机发出的命令首先给下位机,下位机再根据此命令解释成相应时序信号直接控制相应设备.下位机不时读取设备状态数据(一般为模拟量),转换成数字信号反馈给上位机.上位机不可以单独使用,而下位机可以单独使用. 2.串口通信 串口相当于硬件类型的接口.比如无线传感节

用LabVIEW编写上位机

用LabVIEW编写上位机 1.下载.安装LabVIEW 现在网上搜,能搜出来一大推LabVIEW下载和安装以及破解教程,因此这里不做详细介绍.请自行百度~~.另外,提醒一下,下载LabVIEW时尽量下载那种带注册机,因为如果不对LabVIEW进行破解,很多的基本功能都用不了的. 这里给一个我的云盘的链接,里面含有注册机哦: http://pan.baidu.com/s/1mgqqr1m 2.下载安装VISA VISA(Virtual Instrument Software Architectu

2018最新mfc作为上位机接收硬件端USB或串口数据显示成图片 解决串口接收数据丢字节丢包问题

本文用的是VS2013MFC写串口数据接收: 第一步:首先建立一个MFC工程,成功后会跳出一个对话框,直接在对话框上点击右键->点击插入ACTIVAE控件->选择MicrosoftCommunications Control, version 6.0 成功后会显示一个电话的图标在对话框上,运行起来不会显示的 不用担心这个美观问题.如果没有这个插件的话,可能是版本太低  可以自己下载一个补上 第二步:大概的窗体搞好:   那个显示图片的大框是PICTURE控件变量 然后就要项目->类向导中

STM32_IAP详解(有代码,有上位机)

Iap,全名为in applacation programming,即在应用编程,与之相对应的叫做isp,in system programming,在系统编程,两者的不同是isp需要依靠烧写器在单片机复位离线的情况下编程,需要人工的干预,而iap则是用户自己的程序在运行过程中对User Flash 的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级.在工程应用中经常会出现我们的产品被安装在某个特定的机械结构中,更新程序的时候拆机很不方便,使用ia

C#学习与上位机开发之串口通信模块介绍

串口通信模块(SerialPort) (1)模块简介 使用此模块需要首先包含一些文件IO相关文件 using System.IO;using System.IO.Ports; 图标如下图1所示,将其拖拽到面板.会显示在最下方,其参数有如下: BaudRate 波特率 DataBits 数据位 Parity 奇偶校验位 PortName 端口号 StopBits 停止位 ByteToRead 获取输入缓冲区的 IsOpen 获取是否开启串口         以上是我们做串口通信上位机需要用到的(如

串口操作包括 java上位机 嵌入式c下位机

一环境 1.1 Keil uVision4 http://pan.baidu.com/s/1o6A331w 1.2 STC http://pan.baidu.com/s/1jGpCUTC 1.3 Myeclipse 8.5 http://pan.baidu.com/s/1jGABEaM 1.4 需导入的jar包RXTX http://pan.baidu.com/s/1ntwsvRr 首先把rxtxParallel.dll和rxtxSerial.dll复制到jdk目录的bin目录下面 然后把RXT

USB工业摄像头设计之上位机

在工业相机中对摄像头要求较高,且采集的图像数据要求是源数据,未经过任何处理. 为了兼容xp.win7(32bit 64bit) 程序采用VS2008  MFC编制,参考网上一些应用. CYUSB驱动与CYAPI开发包以前68013上位机程序的编写过程中,应用程序端通过调用DeviceIoControl() API或CREATEPIPE() API与驱动进行交互,继而读写控制硬件设备,在新的68013A的驱动中采用了两种新的调用方法:第一种是继续使用DeviceIoControl()函数读写,不同