1. 程式人生 > >VS2015編寫的MFC上位機,波特率可調,可動態顯示曲線,可顯示三維

VS2015編寫的MFC上位機,波特率可調,可動態顯示曲線,可顯示三維

coo app all hold content flow hid har oid

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 版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

VS2015編寫的MFC上位機,波特率可調,可動態顯示曲線,可顯示三維