?? talktocardlg.cpp
字號:
// TalkToCarDlg.cpp : implementation file
//
#include "stdafx.h"
#include "TalkToCar.h"
#include "TalkToCarDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// 符號化常數定義:
// 小車通訊協議中的收、發方地址
const BYTE CAR_ADDR = 0x01; // 暫定的小車地址
const BYTE PC_ADDR = 0xFE; // PC機的地址,0xFF留作廣播地址
// 小車通訊協議中的命令字
const BYTE READ_MEMORY = 1; // 讀內存命令字
const BYTE WRITE_MEMORY = 2; // 寫內存命令字
const BYTE MOTOR_PWM_CTRL = 3; // 電機PWM控制
const BYTE RUN_STRAIGHT = 4; // 走直線
const BYTE RUN_ON_LINE = 5; // 走軌跡
const BYTE HOLD_GAP = 6; // 保持距離
// PC程序中自己用的命令代號
const int READ_BYTE = 1; // 讀一個字節命令
const int WRITE_BYTE = 2; // 寫一個字節命令
const int MOTOR_PWM = 3; // 電機PWM控制
const int RUN_STR = 4; // 走直線測試
const int READ_SAMPLE = 5; // 讀取軌跡采樣數據
const int READ_DIS = 6; // 讀取距離值
// 接收處理狀態
const int NO_RCV = 0;
const int WAIT_FRAME_END = 1;
// 電機控制選項
const int FORWARD = 0; // 對應下拉選項的定義
const int BACKWARD = 1;
const int FLOAT_C = 2;
const int BRAKE_C = 3;
// 特殊PWM 控制值定義
const BYTE FLOAT_PWM = 255;
const BYTE BRAKE_PWM =0;
// 讀內存的內容說明 (因為需要用讀內存命令處理多種需求)
const int GENERAL_DATA = 0; // 無特殊意義的數據
const int SAMPLE_DATA = 1; // 軌跡采樣數據
const int DIS_DATA = 2; // 距離數據
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTalkToCarDlg dialog
CTalkToCarDlg::CTalkToCarDlg(CWnd* pParent /*=NULL*/)
: CDialog(CTalkToCarDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CTalkToCarDlg)
m_ucWriteData = 0;
m_ucMotorL_PWM = 0;
m_ucMotorR_PWM = 0;
m_ucBase_PWM = 0;
m_uiLeftRunNum = 0;
m_iReadData = 0;
m_szDataAddr = _T("");
m_ucSampleVal1 = 0;
m_ucSampleVal2 = 0;
m_ucSampleVal3 = 0;
m_ucSampleVal4 = 0;
m_ucSensorStat = 0;
m_szSampleAddr = _T("");
m_szCommandBack = _T("");
m_szDisValAddr = _T("");
m_uiGap2Object = 0;
m_ucDisMeanVal = 0;
m_ucDisVal1 = 0;
m_ucDisVal2 = 0;
m_ucDisVal3 = 0;
m_ucDisVal4 = 0;
m_ucDisVal5 = 0;
m_ucDisVal6 = 0;
m_ucDisVal7 = 0;
m_ucDisVal8 = 0;
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CTalkToCarDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTalkToCarDlg)
DDX_Control(pDX, IDC_RUN_MODE, m_ctrlRunMode);
DDX_Control(pDX, IDC_DATA_TYPE, m_ctrlDataType);
DDX_Control(pDX, IDC_RUN_DIR, m_ctrlRunDir);
DDX_Control(pDX, IDC_MOTORR_CTRL, m_ctrlMotor_R);
DDX_Control(pDX, IDC_MOTORL_CTRL, m_ctrlMotor_L);
DDX_Control(pDX, IDC_SEL_COMMPORT, m_ctrlSelCommPort);
DDX_Control(pDX, IDC_MSCOMM1, m_ctrlCommToCar);
DDX_Text(pDX, IDC_WRITE_DATA, m_ucWriteData);
DDX_Text(pDX, IDC_MOTORL_PWM, m_ucMotorL_PWM);
DDV_MinMaxByte(pDX, m_ucMotorL_PWM, 0, 250);
DDX_Text(pDX, IDC_MOTORR_PWM, m_ucMotorR_PWM);
DDV_MinMaxByte(pDX, m_ucMotorR_PWM, 0, 250);
DDX_Text(pDX, IDC_BASE_PWM, m_ucBase_PWM);
DDX_Text(pDX, IDC_LEFT_RUN_NUM, m_uiLeftRunNum);
DDV_MinMaxUInt(pDX, m_uiLeftRunNum, 0, 65535);
DDX_Text(pDX, IDC_READ_DATA, m_iReadData);
DDX_Text(pDX, IDC_DATA_ADDR, m_szDataAddr);
DDX_Text(pDX, IDC_SAMPLE_VAL1, m_ucSampleVal1);
DDX_Text(pDX, IDC_SAMPLE_VAL2, m_ucSampleVal2);
DDX_Text(pDX, IDC_SAMPLE_VAL3, m_ucSampleVal3);
DDX_Text(pDX, IDC_SAMPLE_VAL4, m_ucSampleVal4);
DDX_Text(pDX, IDC_SENSOR_STAT, m_ucSensorStat);
DDX_Text(pDX, IDC_SAMPLE_ADDR, m_szSampleAddr);
DDX_Text(pDX, IDC_COMMAND_BACK, m_szCommandBack);
DDX_Text(pDX, IDC_DISVAL_ADDR, m_szDisValAddr);
DDX_Text(pDX, IDC_GAP2OBJECT, m_uiGap2Object);
DDX_Text(pDX, IDC_DIS_MEAN_VAL, m_ucDisMeanVal);
DDX_Text(pDX, IDC_DIS_VAL1, m_ucDisVal1);
DDX_Text(pDX, IDC_DIS_VAL2, m_ucDisVal2);
DDX_Text(pDX, IDC_DIS_VAL3, m_ucDisVal3);
DDX_Text(pDX, IDC_DIS_VAL4, m_ucDisVal4);
DDX_Text(pDX, IDC_DIS_VAL5, m_ucDisVal5);
DDX_Text(pDX, IDC_DIS_VAL6, m_ucDisVal6);
DDX_Text(pDX, IDC_DIS_VAL7, m_ucDisVal7);
DDX_Text(pDX, IDC_DIS_VAL8, m_ucDisVal8);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CTalkToCarDlg, CDialog)
//{{AFX_MSG_MAP(CTalkToCarDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_CBN_SELCHANGE(IDC_SEL_COMMPORT, OnSelCommPort)
ON_BN_CLICKED(IDC_READ, OnRead)
ON_BN_CLICKED(IDC_WRITE, OnWrite)
ON_BN_CLICKED(IDC_PWM_OUT, OnPWM_Out)
ON_BN_CLICKED(IDC_BRAKE, OnBrake)
ON_BN_CLICKED(IDC_FLOAT, OnFloat)
ON_BN_CLICKED(IDC_RUN_STRAIGHT, OnRunStraight)
ON_BN_CLICKED(IDC_READ_SAMPLE, OnReadSample)
ON_BN_CLICKED(IDC_READ_DIS, OnReadDis)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTalkToCarDlg message handlers
BOOL CTalkToCarDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
GetDlgItem(IDC_READ) -> EnableWindow(false); // 初始化時將兩個按鈕禁止,等串口有效后再允許。
GetDlgItem(IDC_WRITE) -> EnableWindow(false);
GetDlgItem(IDC_FLOAT) -> EnableWindow(false);
GetDlgItem(IDC_BRAKE) -> EnableWindow(false);
GetDlgItem(IDC_PWM_OUT) -> EnableWindow(false);
GetDlgItem(IDC_RUN_STRAIGHT) -> EnableWindow(false);
GetDlgItem(IDC_READ_SAMPLE) -> EnableWindow(false);
GetDlgItem(IDC_READ_DIS) -> EnableWindow(false);
m_ucGetBack = 0;
m_ucSaveBack = 0; // 初始化存取數指針,等效于緩沖區為空
return TRUE; // return TRUE unless you set the focus to a control
}
void CTalkToCarDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CTalkToCarDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
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;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CTalkToCarDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
// 選擇串口處理,測試所選擇的串口是否存在、可用,使用時再打開。
void CTalkToCarDlg::OnSelCommPort()
{
// TODO: Add your control notification handler code here
int PortNo;
if(m_ctrlCommToCar.GetPortOpen()) //如果串口開著
{
m_ctrlCommToCar.SetPortOpen(false);
}
PortNo = m_ctrlSelCommPort.GetCurSel() + 1;
m_ctrlCommToCar.SetCommPort(PortNo); //打開串口
if(!m_ctrlCommToCar.GetPortOpen()) //判斷打開是否成功,不成功的話系統會自動彈出錯誤信息
{
m_ctrlCommToCar.SetPortOpen(true);
}
GetDlgItem(IDC_READ) -> EnableWindow(true);
GetDlgItem(IDC_WRITE) -> EnableWindow(true);
GetDlgItem(IDC_FLOAT) -> EnableWindow(true);
GetDlgItem(IDC_BRAKE) -> EnableWindow(true);
GetDlgItem(IDC_PWM_OUT) -> EnableWindow(true);
GetDlgItem(IDC_RUN_STRAIGHT) -> EnableWindow(true);
GetDlgItem(IDC_READ_SAMPLE) -> EnableWindow(true);
GetDlgItem(IDC_READ_DIS) -> EnableWindow(true);
m_ctrlCommToCar.SetPortOpen(false); // 此處只是確認一下口是否可用,到實際用時再打開!
}
BEGIN_EVENTSINK_MAP(CTalkToCarDlg, CDialog)
//{{AFX_EVENTSINK_MAP(CTalkToCarDlg)
ON_EVENT(CTalkToCarDlg, IDC_MSCOMM1, 1 /* OnComm */, OnData_T_R, VTS_NONE)
//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()
// 串口收到數據處理
void CTalkToCarDlg::OnData_T_R()
{
// TODO: Add your control notification handler code here
VARIANT rcv_temp;
COleSafeArray rcv_temp1;
long len,k;
union
{
UINT all;
BYTE b[4];
}uitemp;
int iCommand;
if(m_ctrlCommToCar.GetCommEvent() == 2)
{
// 收到數據
rcv_temp = m_ctrlCommToCar.GetInput();
rcv_temp1 = rcv_temp; // 轉換類型
len = rcv_temp1.GetOneDimSize(); // 得到接收的字節數
for(k=0;k<len;k++) // 將數據復制到接收緩沖區
{
rcv_temp1.GetElement(&k,&m_ucBackBuf[m_ucSaveBack]);
m_ucSaveBack++;
}
iCommand = DataFrame_OK(); // 檢測是否為有效幀,
if(iCommand != -1)
{
m_szCommandBack = "成功"; // 增加此顯示以便判斷小車是否有返回幀
switch(iCommand) // 因為現在命令較少,故直接在此處理
{
case READ_MEMORY:
{
uitemp.all = 0;
uitemp.b[0] = m_ucBackBuf[m_ucStartPtr+1];
uitemp.b[1] = m_ucBackBuf[m_ucStartPtr+2];
switch(m_iReadMemContent)
{
case GENERAL_DATA:
{
gatGeneralData();
break;
}
case SAMPLE_DATA:
{
getSampleData();
break;
}
case DIS_DATA:
{
getDisData();
break;
}
default: break;
}
break;
}
case WRITE_MEMORY:
{
uitemp.all = 0;
uitemp.b[0] = m_ucBackBuf[m_ucStartPtr+1];
uitemp.b[1] = m_ucBackBuf[m_ucStartPtr+2];
if(m_ucBackBuf[m_ucStartPtr+3] == 0)
{
m_ucWriteData = 0xFF; // 如果寫失敗,則將寫數據顯示為 255
}
break;
}
default: break;
}
this->UpdateData(false); // s刷新顯示
}
}
}
// 檢測接收緩沖區中是否收到有效幀,如果是,則返回幀中的命令字;
// 沒有收到合法幀, 則返回“0”;
// 收到檢驗和錯誤幀則返回 “-1”。
// 幀格式:
// 幀頭(2字節) 接收方地址(1字節) 發送方地址(1字節) 幀長(1字節)
// 命令(1字節) 數據域(N字節) 校驗和(1字節)
// 校驗和 -- 數據幀中從命令開始到數據域結束所有字節的算術和,取最低字節的反碼。
int CTalkToCarDlg::DataFrame_OK()
{
int returnval = 0;
int rcv_chk,i;
BYTE sum,j;
while(m_ucGetBack != m_ucSaveBack)
{
switch (m_iRcvStat)
{
case NO_RCV:
{
// 檢測幀頭
rcv_chk = 0;
if(m_ucBackBuf[m_ucGetBack-5] == 0x55)
{
rcv_chk++;
}
if(m_ucBackBuf[m_ucGetBack-4] == 0xAA)
{
rcv_chk++;
}
if(m_ucBackBuf[m_ucGetBack-3] == PC_ADDR)
{
rcv_chk++;
}
if(rcv_chk == 3)
{
m_ucStartPtr = m_ucGetBack;
m_ucEndPtr = m_ucGetBack + m_ucBackBuf[m_ucGetBack-1];
m_iRcvStat = WAIT_FRAME_END;
}
break;
}
case WAIT_FRAME_END:
{
if(m_ucEndPtr == m_ucGetBack)
{
m_iRcvStat = NO_RCV; // 恢復初始狀態
sum =0; // 檢查校驗和
j=m_ucStartPtr;
for(i=0;i<m_ucBackBuf[m_ucStartPtr-1];i++)
{
sum +=m_ucBackBuf[j];
j++;
}
sum = ~sum;
if(sum == m_ucBackBuf[j])
{
returnval = m_ucBackBuf[m_ucStartPtr]; // 返回命令字
}
else
{
returnval = -1;
}
m_ctrlCommToCar.SetPortOpen(false); // 收完數據幀后關閉串口,釋放設備。
}
break;
}
default: break;
}
m_ucGetBack++;
}
return(returnval);
}
// 讀按鈕操作,打開串口,構建命令幀,啟動發送
void CTalkToCarDlg::OnRead()
{
// TODO: Add your control notification handler code here
this->UpdateData(true); // 將對話框中的地址等數據取回
if(open_CommPort())
{
m_iReadMemContent = GENERAL_DATA;
makeSendFrame(READ_BYTE, &m_baSendFrame); // 構建發送幀
m_iRcvStat = NO_RCV; // 初始化接收狀態
m_ctrlCommToCar.SetOutput((COleVariant)m_baSendFrame); // 啟動發送
m_baSendFrame.RemoveAll();
}
else
{
m_ctrlCommToCar.SetPortOpen(false);
}
}
// 寫按鈕操作,打開串口,構建命令幀,啟動發送
void CTalkToCarDlg::OnWrite()
{
// TODO: Add your control notification handler code here
this->UpdateData(true); // 將對話框中的地址等數據取回
if(open_CommPort())
{
makeSendFrame(WRITE_BYTE, &m_baSendFrame); // 構建發送幀
m_iRcvStat = NO_RCV; // 初始化接收狀態
m_ctrlCommToCar.SetOutput((COleVariant)m_baSendFrame); // 啟動發送
m_baSendFrame.RemoveAll();
}
else
{
m_ctrlCommToCar.SetPortOpen(false);
}
}
// 這是一個自己添加的函數,用鼠標選中類“CTalkToCarDlg”,
// 右鍵中選擇“Add Member Function..."即可
// 函數功能:打開 m_ctrlSelCommPort 中所選的串口,成功返回真。
bool CTalkToCarDlg::open_CommPort()
{
CString CommConfig;
int PortNo;
this->UpdateData(true);
if(m_ctrlCommToCar.GetPortOpen()) //如果串口開著
{
m_ctrlCommToCar.SetPortOpen(false);
}
PortNo = m_ctrlSelCommPort.GetCurSel() + 1;
m_ctrlCommToCar.SetCommPort(PortNo); //打開串口
if(!m_ctrlCommToCar.GetPortOpen()) //判斷打開是否成功,不成功的話系統會自動彈出錯誤信息
{
m_ctrlCommToCar.SetPortOpen(true);
}
CommConfig = _T("19200,N,8,1"); //傳輸率,無校驗,8個數據位,1個停止位
m_ctrlCommToCar.SetSettings(CommConfig); //設置串口
//參數1表示接收緩沖中有1個或多于1個字符時,引發一個接收數據的OnComm事件
m_ctrlCommToCar.SetRThreshold(1);
m_ctrlCommToCar.SetRTSEnable(true); // 設置RTS為可以發送
m_ctrlCommToCar.SetInputMode(1); // 0 表示以文本格式接收,1表示以二進制方式接收
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -