在研一项目过程中,接触到雷赛公司的控制器电机系列,采用PC上位机VC驱动电机运转,这里对过程中的程序进行详解,因为以前没有接触过MFC,也是对MFC的一个很好补充,在实战中学习MFC。前面的例程后序补充。现在对一个例程的程序执行过程进行分析。
可以仔细看中间注释代码,供同样的MFC菜鸟理解。
// SMC_ExampleDlg.cpp : implementation file
//
#include "stdafx.h"
#include "SMC_Example.h"
#include "SMC_ExampleDlg.h"
//如果生成调试版本,要指示当前文件的名称。__FILE__是一个宏,在编译器编译过程中给它赋值为当前正在编译的文件名称
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };//只是表明About对话框的模板ID是IDD。
//}}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()和END_MESSAGE_MAP()之间添加你的消息响应函数,为每个消息处理函数加入一个入口
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CSMC_ExampleDlg dialog
CSMC_ExampleDlg::CSMC_ExampleDlg(CWnd* pParent /*=NULL*/) //对话框构造函数
: CDialog(CSMC_ExampleDlg::IDD, pParent) //一个继承类的构造函数 ,初始化数据
{ //pParent定义?
//{{AFX_DATA_INIT(CSMC_ExampleDlg)
m_iAxisNum = 0;
m_iReturnMode = 0;//返回,模式
m_iSpeedMode = 0;
m_iOriginDir = 0;//回零方向
m_iConnectNum = 0; //链接号
m_fBeginSpeed = 100;
m_fDecTime = 0.1;//减速时间
m_iRunDistance = 2000;//运动距离
m_fAccTime = 0.1;
m_fStopSpeed = 100;//停止速度
m_fRunSpeed = 300;
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); //图标句柄
}
void CSMC_ExampleDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX); //数据交换
//{{AFX_DATA_MAP(CSMC_ExampleDlg)
DDX_Radio(pDX, IDC_RADIO_XAXIS, m_iAxisNum); //对话数据交换函数
DDX_Radio(pDX, IDC_RADIO_RETURNMODE, m_iReturnMode);
DDX_Radio(pDX, IDC_RADIO_SPEED, m_iSpeedMode);
DDX_Radio(pDX, IDC_RADIO_DIR, m_iOriginDir);
DDX_Text(pDX, IDC_EDIT_BEGINSPEED, m_fBeginSpeed);
DDX_Text(pDX, IDC_EDIT_DECTIME, m_fDecTime);
DDX_Text(pDX, IDC_EDIT_RUNDISTANCE, m_iRunDistance);
DDX_Text(pDX, IDC_EDIT_ACCTIME, m_fAccTime);
DDX_Text(pDX, IDC_EDIT_RUNSPEED, m_fRunSpeed);
DDX_Text(pDX, IDC_EDIT_STOPSPEED, m_fStopSpeed);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CSMC_ExampleDlg, CDialog) //使用BEGIN_MESSAGE_MAP宏开始你的消息映射的定义
//{{AFX_MSG_MAP(CSMC_ExampleDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_TIMER()
ON_BN_CLICKED(IDC_BUTTON_START, OnButtonStart)//开始
ON_BN_CLICKED(IDC_BUTTON_CLEARPOS, OnButtonClearpos)
ON_BN_CLICKED(IDC_BUTTON_SLOWDOWN, OnButtonSlowdown)
ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
ON_BN_CLICKED(IDC_BUTTON_EXIT, OnButtonExit)
ON_BN_CLICKED(IDC_BUTTON_RETURN, OnButtonReturn)
//}}AFX_MSG_MAP
ON_STN_CLICKED(IDC_STATIC_POSITION, &CSMC_ExampleDlg::OnStnClickedStaticPosition)
ON_BN_CLICKED(IDC_RADIO_RETURNMODE, &CSMC_ExampleDlg::OnBnClickedRadioReturnmode)
ON_BN_CLICKED(IDC_BUTTON1, &CSMC_ExampleDlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_RADIO_DIR, &CSMC_ExampleDlg::OnBnClickedRadioDir)
ON_BN_CLICKED(IDC_RADIO3, &CSMC_ExampleDlg::OnBnClickedRadio3)
ON_BN_CLICKED(IDC_RADIO_XAXIS, &CSMC_ExampleDlg::OnBnClickedRadioXaxis)
ON_STN_CLICKED(IDC_STATIC_RUNSTATE, &CSMC_ExampleDlg::OnStnClickedStaticRunstate)
ON_BN_CLICKED(IDC_RADIO_SPEED, &CSMC_ExampleDlg::OnBnClickedRadioSpeed)
ON_BN_CLICKED(IDC_RADIO10, &CSMC_ExampleDlg::OnBnClickedRadio10)
ON_BN_CLICKED(IDC_RADIO8, &CSMC_ExampleDlg::OnBnClickedRadio8)
ON_EN_CHANGE(IDC_EDIT_ACCTIME, &CSMC_ExampleDlg::OnEnChangeEditAcctime)
ON_EN_CHANGE(IDC_EDIT_STOPSPEED, &CSMC_ExampleDlg::OnEnChangeEditStopspeed)
ON_EN_CHANGE(IDC_EDIT_BEGINSPEED, &CSMC_ExampleDlg::OnEnChangeEditBeginspeed)
ON_BN_CLICKED(IDC_RADIO_YAXIS, &CSMC_ExampleDlg::OnBnClickedRadioYaxis)
//ON_BN_CLICKED(IDC_RADIO_UAXIS, &CSMC_ExampleDlg::OnBnClickedRadioUaxis)
ON_BN_CLICKED(IDC_RADIO_ZAXIS, &CSMC_ExampleDlg::OnBnClickedRadioZaxis)
ON_BN_CLICKED(IDC_RADIO4, &CSMC_ExampleDlg::OnBnClickedRadio4)
ON_BN_CLICKED(IDC_RADIO5, &CSMC_ExampleDlg::OnBnClickedRadio5)
ON_BN_CLICKED(IDC_RADIO6, &CSMC_ExampleDlg::OnBnClickedRadio6)
ON_EN_CHANGE(IDC_EDIT_RUNDISTANCE, &CSMC_ExampleDlg::OnEnChangeEditRundistance)
ON_EN_CHANGE(IDC_EDIT_DECTIME, &CSMC_ExampleDlg::OnEnChangeEditDectime)
ON_EN_CHANGE(IDC_EDIT_RUNSPEED, &CSMC_ExampleDlg::OnEnChangeEditRunspeed)
END_MESSAGE_MAP()
/
// CSMC_ExampleDlg message handlers
BOOL CSMC_ExampleDlg::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); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: Add extra initialization here
UINT ret = smc_board_init(m_iConnectNum,1,"COM3",115200);//控制器 链接初始化函数,分配系统资源
//正确连接的返回值是0,下面是错误提示
if(ret!=0)
{
MessageBox("连接失败,请进入代码重设对应的连接参数!");
return TRUE;
}
SetTimer(0,200,NULL);
return TRUE; // return TRUE unless you set the focus to a control
}
void CSMC_ExampleDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX) //判断ID或者地址是不是 IDM_ABOUTBOX 这个ID或者他的地址
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
void CSMC_ExampleDlg::OnPaint() //事件发生时执行画图程序
{
if (IsIconic()) //对话窗窗体是否最小化发生
{
CPaintDC dc(this); // 声明DC class 对象 dc, 并构建,用于画图
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);//给窗口发送发送消息,立即调用方式
//发送消息 WM_ICONERASEBKGND (图标背景删除)
// 下面语句是把图标(icon)放到客户区中心位置。
int cxIcon = GetSystemMetrics(SM_CXICON);//声明cxIcon,初始化GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);//声明cyIcon,初始化GetSystemMetrics(SM_CYICON);
CRect rect; // 声明矩形class rect,
GetClientRect(&rect); // 取得客户区 矩形大小
//下面声明 x,y, 计算 x,y 坐标。用dc.DrawIcon 画 图标,还是对话框的操作
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
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 CSMC_ExampleDlg::OnQueryDragIcon()//这个函数是系统获取你的鼠标图标的,
//比如你要换掉系统默认的鼠标箭头图标,
//就在构造函数中加载鼠标箭头的图标。
//默认是返回系统的鼠标图标。HCURSOR
{
return (HCURSOR) m_hIcon;
}
void CSMC_ExampleDlg::OnTimer(UINT nIDEvent) //我们只是重载OnTimer;其实内部还有很多要处理的,
//我们只是重载一下,处理想做的事情,再让它按原流程继续处理
//相当于在中间加入了一些我们需要处理的事件
{
// TODO: Add your message handler code here and/or call default
switch(nIDEvent)
{
case 0: //当计时器(ID=0)到时间: 动作
{
double lPos ;
smc_get_position_unit(m_iConnectNum,m_iAxisNum,&lPos);//读取当前指令位置计数器值,轴号 ,pos为当前返回值
CString csPos;
csPos.Format(_T("%f"),lPos);
GetDlgItem(IDC_STATIC_POSITION)->SetWindowText(csPos);//得到静态文本框(IDC-STATIC)的ID(POSITION),
//然后向这个文本框写入文本csPos所代表的内容
short iRunState = smc_check_done(m_iConnectNum,m_iAxisNum);
if(iRunState)
{
GetDlgItem(IDC_STATIC_RUNSTATE)->SetWindowText(_T("停止"));
}
else
{
GetDlgItem(IDC_STATIC_RUNSTATE)->SetWindowText(_T("运行中"));
}
}
break;
default:
break;
}
CDialog::OnTimer(nIDEvent);
}
//控制面板操作,这里对对话框的操作控件具体如何执行进行解释。
//启动
void CSMC_ExampleDlg::OnButtonStart() //点位运动
{
// TODO: Add your control notification handler code here
UpdateData();
//smc_set_equiv(m_iConnectNum,m_iAxisNum,1000); //返回脉冲当量值设置
smc_set_pulse_outmode(m_iConnectNum,m_iAxisNum,0);
smc_set_s_profile(m_iConnectNum,m_iAxisNum,0,0.01);//设置单轴速度曲线 S 段参数值
smc_set_profile_unit(m_iConnectNum,m_iAxisNum,m_fBeginSpeed,m_fRunSpeed,m_fAccTime,m_fDecTime,m_fStopSpeed);//设置单轴运动速度曲线
smc_pmove_unit(m_iConnectNum,m_iAxisNum,m_iRunDistance,0); //定长运动,加/减速度恒定
//本来脉冲数决定了运动的距离,这里直接封装,设置脉冲当量就行
//若未设置的话,脉冲当量默认值为100
}
//复位
void CSMC_ExampleDlg::OnButtonReturn() //回原点运动
{
// TODO: Add your control notification handler code here
UpdateData();
smc_set_home_pin_logic(m_iConnectNum,m_iAxisNum,0,0);//设置 ORG 原点信号,信号ORG低电平有效
smc_set_homemode(m_iConnectNum,m_iAxisNum,m_iOriginDir,m_iSpeedMode,m_iReturnMode,0);//设置回原点模式,默认低速回零
smc_home_move(m_iConnectNum,m_iAxisNum);//回原点运动
while(smc_check_done(m_iConnectNum,m_iAxisNum) == 0 )//检测指定轴的运动状态
{
AfxGetApp()->PumpMessage();
}
smc_set_position_unit(m_iConnectNum,m_iAxisNum,0);//设置当前指令位置计数器值
}
//位置清零
void CSMC_ExampleDlg::OnButtonClearpos()
{
// TODO: Add your control notification handler code here
UpdateData(); //更新数据在对话框的显示
smc_set_position_unit(m_iConnectNum,m_iAxisNum,0);//设置当前指令位置计数器值
}
//减速停止
void CSMC_ExampleDlg::OnButtonSlowdown()
{
// TODO: Add your control notification handler code here
smc_stop(m_iConnectNum,m_iAxisNum,0);//指定轴停止运动
}
//立即停止
void CSMC_ExampleDlg::OnButtonStop()
{
// TODO: Add your control notification handler code here
smc_stop(m_iConnectNum,m_iAxisNum,1);//指定轴停止运动
}
//退出
void CSMC_ExampleDlg::OnButtonExit()
{
// TODO: Add your control notification handler code here
smc_board_close(m_iConnectNum);//控制器关闭函数,释放系统资源
this->DestroyWindow();
}
//坐标位置
void CSMC_ExampleDlg::OnStnClickedStaticPosition()
{
// TODO: 在此添加控件通知处理程序代码
}
//一次回零
void CSMC_ExampleDlg::OnBnClickedRadioReturnmode()//点击静态位置
{
// TODO: 在此添加控件通知处理程序代码
}
void CSMC_ExampleDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
//smc_set_position_unit(m_iConnectNum,m_iAxisNum,0);
}
//回原点方向 正向
void CSMC_ExampleDlg::OnBnClickedRadioDir()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData();
m_iOriginDir = 1;
}
//一次回零加反找
void CSMC_ExampleDlg::OnBnClickedRadio3()
{
// TODO: 在此添加控件通知处理程序代码
}
//运动轴 x轴
void CSMC_ExampleDlg::OnBnClickedRadioXaxis()
{
// TODO: 在此添加控件通知处理程序代码
}
//运动轴 y轴
void CSMC_ExampleDlg::OnBnClickedRadioYaxis()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_iAxisNum = 1;
}
//运动轴 z轴
void CSMC_ExampleDlg::OnBnClickedRadioZaxis()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData();
m_iAxisNum = 2;
}
//void CSMC_ExampleDlg::OnBnClickedRadioUaxis()
//{
// TODO: 在此添加控件通知处理程序代码
//}
//运动状态
void CSMC_ExampleDlg::OnStnClickedStaticRunstate()
{
// TODO: 在此添加控件通知处理程序代码
}
//低速回原点
void CSMC_ExampleDlg::OnBnClickedRadioSpeed()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData();
m_iSpeedMode = 0;
}
//高速回原点
void CSMC_ExampleDlg::OnBnClickedRadio10()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData();
m_iSpeedMode = 1;
}
//反向回原点模式
void CSMC_ExampleDlg::OnBnClickedRadio8()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData();
m_iOriginDir = 0;
}
//加速时间
void CSMC_ExampleDlg::OnEnChangeEditAcctime()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialog::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
//#1015
// TODO: 在此添加控件通知处理程序代码
}
//停止时间
void CSMC_ExampleDlg::OnEnChangeEditStopspeed()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialog::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
//#1015
// TODO: 在此添加控件通知处理程序代码
}
//起始速度
void CSMC_ExampleDlg::OnEnChangeEditBeginspeed()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialog::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
//#1015
// TODO: 在此添加控件通知处理程序代码
}
//两次回零
void CSMC_ExampleDlg::OnBnClickedRadio4()
{
// TODO: 在此添加控件通知处理程序代码
}
//一次回零加EZ
void CSMC_ExampleDlg::OnBnClickedRadio5()
{
// TODO: 在此添加控件通知处理程序代码
}
//EZ
void CSMC_ExampleDlg::OnBnClickedRadio6()
{
// TODO: 在此添加控件通知处理程序代码
}
//运动距离
void CSMC_ExampleDlg::OnEnChangeEditRundistance()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialog::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
//#1015
// TODO: 在此添加控件通知处理程序代码
}
//减速时间
void CSMC_ExampleDlg::OnEnChangeEditDectime()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialog::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
//#1015
// TODO: 在此添加控件通知处理程序代码
}
//运动速度
void CSMC_ExampleDlg::OnEnChangeEditRunspeed()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialog::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
//#1015
// TODO: 在此添加控件通知处理程序代码
}
制作出来的对话框如图:
即可以对电机的各种运行模式进行操作。待深究改进该程序。