步进电机的应用非常广泛,在各种设备中经常会遇到,而步进电机的驱动则是使用步进电机必不可少的部分,可以有多种方式来实现步进电机的驱动,在这里我们来考虑一下基于TMC2660驱动芯片的步进电机驱动。

1、功能概述

TMC2660是德国TRINAMIC公司产的步进电机驱动芯片。TMC2660驱动器提供了业界领先的功能集,包括高分辨率微步、无传感器机械负载测量、负载自适应功率优化和低共振斩波操作。拥有标准SPI和STEP/DIR两种接口模式。集成功率MOSFET处理电机电流高达2.2A。集成的保护和诊断功能支持稳健和可靠的运行。其结构图如下:

TMC2660的参数配置通过SPI接口来实现。TMC2660具有5个配置和控制寄存器,通过SPI端口来访问这些寄存器。这些寄存器的结构定义如下所示:

所有的寄存器都是20位,在最高的2位或3位表示的是寄存器地址也称为操作码。根据具体的寄存器我们选择不同的操作码实现对寄存器的写操作。每一个写操作都会有一个20位的数据返回。而返回数据的内容可以通过修改配置寄存器来定义。具体的格式如下图所示:

2、驱动设计于实现

我们已经了解了TMC2660步进电机驱动芯片的基本技术参数,接下来我们就需要据此来实现TMC2660步进电机驱动芯片的驱动程序的设计与实现。

2.1、对象定义

我们依然是居于对象来实现相关的操作。所以我们首先要定义对象,出于适用性考虑,我们要定义对象的类型并将具体的对象实例化,接下来我们就来抽象对象类型和实例化对象的操作。

2.1.1、对象的抽象

对于一个对象最主要包括属性与操作两方面内容,所以我们先来考虑TMC2660对象具有哪些属性和操作,并抽象出较为通用的TMC2660对象类型。

对于步进电机的驱动都具有哪些属性呢?我们考虑到一台步进电机至少具备启停控制命令、方向控制命令、速度设定以及运行状态等,这些对于每一台步进电机来说,在不同的设置下代表不同的状态,所以我们将其作为其属性来处理。此外,与具体的电机相关的参数如固有步距角、微步设置及当前脉冲频率等。以及与TMC2660相关的状态、寄存器的值、速度规划等都与具体的应用需求相关、用以记录其运行和配置状态,所以我们将其作为属性。

然后再来看一看TMC2660对象需要实现的操作。对于TMC2660对象来说,我们要操作它,需要向其发送和读取数据,需要操作片选信号和使能信号,而这些行为依赖于具体的操作平台,所以我们将其作为对象的操作来设定。TMC2660可以工作在SPI模式或者SD模式,而在SD模式时,存在脉冲和方向的控制,这同样依赖于具体的软硬件操作平台,所以我们也将其作为对象的操作来实现。更具以上的分析我们可以抽象出TMC2660对象类型如下:

/*定义TMC2660对象类型*/
typedef struct TMC2660Object {float microStep; //微步设置float stepAngle; //固有步进角float frequency;    //运行频率uint16_t *pStartStop;   //启停操作命令uint16_t *pDirection;   //方向控制uint16_t *pRotateSet;   //转速设定uint16_t *pMotorState;  //电机状态uint32_t status;        //TMC通讯返回状态uint32_t Register[5];    //寄存器void (*WriteRead)(uint8_t *wData,uint16_t wSize,uint8_t *rData,uint16_t rSize);void (*ChipSelcet)(TMC2660CSType cs);   //片选信号void (*StartStop)(TMC2660SSType ss);    //启停操作函数void (*Direct)(TMC2660DIRType dir);     //方向操作函数void (*Enable)(TMC2660ENNType enn);     //使能操作函数CurveObjectType curve;          //电机调速曲线
}TMC2660ObjectType;

2.1.2、对象初始化

我们定义了对象类型,可以实现基于对象的操作,但定义的对象变量需要进行初始化才能让不同的对象按照我们的配置的方式去运行。所以在开始对象的使用之前我们先对其进行初始化,具体的初始化函数如下:

/*初始化TMC2660对象*/
void Tmc2660Initialization(TMC2660ObjectType *tmc,       //待初始化的TMC对象变量TMC2660SdoffType interface,      //驱动接口类型TMC2660MicroStepType microStep,  //微步设置uint16_t Power,                  //电流量程uint16_t stepAngle,                  //固有步进角uint16_t *pStartStop,            //启停操作命令uint16_t *pDirection,            //方向控制uint16_t *pRotateSet,            //转速设定uint16_t *pMotorState,           //电机状态TMC2660WriteReadType writeRead,  //读写函数指针TMC2660ChipSelcetType cs,        //片选操作函数指针TMC2660StartStopType startStop,  //启停操作函数指针TMC2660DirectType direct,        //方向设置函数指针TMC2660EnableType enable         //使能控制函数指针)
{uint32_t MicroStep[9]={0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00};uint16_t MicroStepNum[9]={1,2,4,8,16,32,64,128,256};if((tmc==NULL)||(writeRead==NULL)||(cs==NULL)||(enable==NULL)){return;}tmc->WriteRead=writeRead;tmc->ChipSelcet=cs;tmc->StartStop=startStop;tmc->Direct=direct;tmc->Enable=enable;tmc->pStartStop=pStartStop;tmc->pDirection=pDirection;tmc->pRotateSet=pRotateSet;tmc->pMotorState=pMotorState;tmc->microStep=MicroStepNum[microStep];tmc->stepAngle=(float)stepAngle/10.0;tmc->curve.stepSpeed=0.02;tmc->curve.currentSpeed=0;tmc->curve.startSpeed=0;tmc->curve.speedMax=300;tmc->curve.speedMin=1.0;tmc->curve.curveMode=CURVE_SPTA;tmc->curve.flexible=10.0;tmc->Register[Reg_DRVCTRL]=DRVCTRL;tmc->Register[Reg_CHOPCONF]=CHOPCONF;tmc->Register[Reg_SMARTEN]=SMARTEN;tmc->Register[Reg_SGCSCONF]=SGCSCONF;tmc->Register[Reg_DRVCONF]=DRVCONF;tmc->Register[Reg_CHOPCONF]=tmc->Register[Reg_CHOPCONF]|0x1B1;tmc->Register[Reg_SMARTEN]=tmc->Register[Reg_SMARTEN]|0x202;tmc->Register[Reg_SGCSCONF]=tmc->Register[Reg_SGCSCONF]|0x10000;WriteReadTmc2660Register(tmc,Reg_CHOPCONF);WriteReadTmc2660Register(tmc,Reg_SGCSCONF);if(interface==TMC2660_SPI){tmc->Register[Reg_DRVCONF]=tmc->Register[Reg_DRVCONF]|0xA190;WriteReadTmc2660Register(tmc,Reg_DRVCONF);}else{tmc->Register[Reg_DRVCONF]=tmc->Register[Reg_DRVCONF]|0xA140;WriteReadTmc2660Register(tmc,Reg_DRVCONF);tmc->Register[Reg_DRVCTRL]=tmc->Register[Reg_DRVCTRL]|0x100|MicroStep[microStep];WriteReadTmc2660Register(tmc,Reg_DRVCTRL);}WriteReadTmc2660Register(tmc,Reg_SMARTEN);SetMotorPower(tmc,Power);
}

2.2、对象操作

接下来我们考虑对TMC2660进行的操作问题。我们已经知道TMC2660拥有5个寄存器,而对TMC2660的各种配置都是通过这5个寄存器来实现的。即使使用SD模式来实现电机驱动也是通过寄存器配置才能实现,所以对TMC2660基本的操作则是读写TMC2660寄存器。至于SD模式下,输入脉冲和方向信号依赖于具体平台,我们已将其定义为对象的回调函数。

/*读写寄存器*/
static void WriteReadTmc2660Register(TMC2660ObjectType *tmc,TMC2660RegType reg)
{uint8_t wData[3];uint8_t rData[3];uint32_t status=0;uint32_t regValue;tmc->ChipSelcet(TMC2660CS_Enable);regValue=tmc->Register[reg]&0xFFFFF;wData[0]=(uint8_t)(regValue>>16);wData[1]=(uint8_t)(regValue>>8);wData[2]=(uint8_t)regValue;tmc->WriteRead(wData,3,rData,3);status=rData[0];status=(status<<8)+rData[1];status=(status<<8)+rData[2];tmc->status= status;tmc->ChipSelcet(TMC2660CS_Disable);
}

3、驱动的应用

我们已经设计并实现了TMC2660步进电机驱动芯片的驱动程序,接下来我们实现一个实例来验证这一驱动设定是否符合要求。

3.1、声明并初始化对象

在开始一切操作之前,首先我们需要一个对象。前面的设计中,我们已经定义了一个TMC2660对象类型,所以我们使用它定义一个对象变量。

TMC2660ObjectType tmc;

定义了tmc对象变量之后,还没有办法使用,因为我们需要对其进行初始化。前面我们已经设计了对象初始化函数,我们需要使用它来初始化tmc对象变量。初始化函数需要如下参数:

TMC2660ObjectType *tmc,          //待初始化的TMC对象变量

TMC2660SdoffType interface,      //驱动接口类型

TMC2660MicroStepType microStep,  //微步设置

uint16_t Power,                  //电流量程

uint16_t stepAngle,               //固有步进角

uint16_t *pStartStop,            //启停操作命令

uint16_t *pDirection,            //方向控制

uint16_t *pRotateSet,            //转速设定

uint16_t *pMotorState,           //电机状态

TMC2660WriteReadType writeRead,  //读写函数指针

TMC2660ChipSelcetType cs,        //片选操作函数指针

TMC2660StartStopType startStop,  //启停操作函数指针

TMC2660DirectType direct,        //方向设置函数指针

TMC2660EnableType enable         //使能控制函数指针

在这些参数中,操作变量将具体的变量指针传入即可,而其它参数如接口类型,步距角等则根据具体的应用情况输入即可。需要注意的是,5歌操作函数指针,其函数原型定义如下:

typedef void (*TMC2660WriteReadType)(uint8_t *wData,uint16_t wSize,uint8_t *rData,uint16_t rSize);
typedef void (*TMC2660ChipSelcetType)(TMC2660CSType cs);     //片选信号
typedef void (*TMC2660StartStopType)(TMC2660SSType ss);        //启停操作函数
typedef void (*TMC2660DirectType)(TMC2660DIRType dir);     //方向操作函数
typedef void (*TMC2660EnableType)(TMC2660ENNType enn);     //使能操作函数

这些操作函数依赖于具体的操作平台,我们采用的是已于STM32F103CBT6和HAL库函数的操作平台,所以根据函数原型定义来收集这些函数如下:

/*TMC2660片选操作函数*/
static void TMC2660ChipSelcet(TMC2660CSType cs)
{if(cs==TMC2660CS_Enable){TMC_CSN_ENABLE();}else{TMC_CSN_DISABLE();}
}/*启停操作函数*/
static void MotorStartStop(TMC2660SSType ss)
{if(ss==TMC2660SS_Start){if(HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3) != HAL_OK){}}else{if(HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3) != HAL_OK){}}
}/*方向操作函数*/
static void MotorDirect(TMC2660DIRType dir)
{if(dir==TMC2660DIR_CCW){TMC_DIR_DISABLE();}else{TMC_DIR_ENABLE();}
}/*使能操作函数*/
static void TMC2660Enable(TMC2660ENNType enn)
{if(enn==TMC2660ENN_Enable){TMC_ENN_ENABLE();}else{TMC_ENN_DISABLE();}
}/*通过SPI2端口读写数据*/
static void WriteReadBySPI2(uint8_t *wData,uint16_t wSize,uint8_t *rData,uint16_t rSize)
{HAL_SPI_TransmitReceive (&hspi2, wData, rData, wSize, 1000);
}

至此,我们已经明白了初始化函数所需要的全部参数,我们可以使用改初始换函数初始化tmc对象变量如下:

/*初始化TMC2660对象*/Tmc2660Initialization(&tmc,TMC2660_SD,MicroStep_256,aPara.phyPara.sm42PowerRange,aPara.phyPara.sm42StepAngle,&aPara.phyPara.sm42StartStop,&aPara.phyPara.sm42Direction,&aPara.phyPara.sm42RotateSet,&aPara.phyPara.sm42RunStatus,WriteReadBySPI2,TMC2660ChipSelcet,MotorStartStop,MotorDirect,TMC2660Enable);

3.2、基于对象进行操作

初始化之后,我们就可以使用该对象来事项我们想要的操作了。我们设计一个应用函数调用相关驱动实现操作,并判断速度的设定是否改变来决定是否调整电机的运行速度。

/* 步进电机驱动控制处理函数 */
void SM42Tmc2660Driver(void)
{float temp=0;if(aPara.phyPara.sm42RotateSet<=0){//return;aPara.phyPara.sm42StartStop=0;}Tmc2660ControlBySD(&tmc);SpeedSet(tmc.frequency);//计算转速temp=tmc.frequency*((float)aPara.phyPara.sm42StepAngle);temp=temp/((float)aPara.phyPara.sm42MicroStep);aPara.phyPara.sm42RotateSpeed=(uint16_t)(temp*100/30.0);
}/* 速度调整函数 */
static void SpeedSet(float freq)
{uint16_t period=0;float temp=24000000;if(freq>0){temp=temp/freq;period=(uint16_t)temp;if((2<=period)&&(period<65535)){__HAL_TIM_SET_AUTORELOAD(&htim1,period-1);__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,period/2-1);}}else{__HAL_TIM_SET_AUTORELOAD(&htim1,0);__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,0);}
}

4、应用总结

在本篇中,我们设计并实现了TMC2660的驱动程序,并基于驱动程序设计了一个验证程序,测试结果良好。事实上,该驱动已经使用到我们的多个项目之中,运行效果目前还是不错的。

在使用驱动程序时需要注意,片选信号并非必须实现。因为有些时候我们可能需要在硬件上直接将其选中,此时添加片选操作函数是没有什么意义的,我们可以在初始化时传入NULL来完成。

在配置TMC2660的寄存器时,一定要仔细根据自己的应用需求来配置,如电流保护、波形输出等这些参数的配置对力矩以及电机的运行噪声有很大关系,所以需要特别注意。

欢迎关注:

步进电机驱动技术1:基于TMC2660的步进电机驱动相关推荐

  1. 基于matlab的步进电机转速控制仿真,基于matlab的步进电机转速控制仿真

    基于matlab的步进电机转速控制仿真 摘 要 一般电动机都是连续旋转,而步进电动却是一步一步转动的,故叫步进电动机.每输入一个冲信号,该电动机就转过一定的角度(有的步进电动机可以直接输出线位移,称为 ...

  2. 基于单片机的步进电机驱动电路设计

    基于单片机的步进电机驱动电路设计 步进电机在控制系统中具有广泛的应用.它可以把脉冲信号转换成角位移,并且可用作电磁制动轮.电磁差分器.或角位移发生器等. 有时从一些旧设备上拆下的步进电机(这种电机一般 ...

  3. 单片机控制两个步进电机画圆_基于单片机的步进电机转速控制设计详解(附程序)...

    步进电机是将电脉冲信号转变为角位移或线位移的开环控制元件.在非超载的情况下,电机的转速.停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,即给电机加一个脉冲信号,电机则转过一个步距角.这 ...

  4. 新能源汽车800V电机驱动技术分析

    新能源汽车800V电机驱动技术分析 资料来自:驱动视界.网络.百度百科.搜狐 1.电驱系统发展趋势 2.800V电驱系统分析 3.面临的问题 1.电驱系统发展趋势 <节能与新能源汽车技术路线图2 ...

  5. 百度母婴技术团队—基于Reactjs实现webapp #1

    百度母婴技术团队-基于Reactjs实现webapp #1 Open my-fe opened this Issue 2 days ago · 16 comments Labels None yet ...

  6. linux升级ipv6协议栈,IPv6技术及基于Linux平台IPv6协议栈的实现

    IPv6技术及基于Linux平台IPv6协议栈的实现 简单介绍了 IPv6的基本原理和特征 ,重点探讨了 IPv6技术在 L inux环境中的应用 :对支持 IPv6协 (本文共5页) 阅读全文> ...

  7. 属性加密技术及基于属性的ABE算法的访问控制技术介绍

    属性加密技术 基于身份的加密体制简介 基于身份的加密体制可以看作一种特殊的公钥加密,它有如下特点:系统中用户的公钥可以由任意的字符串组成.这些字符串可以是用户在现实中的身份信息,如:身份证号码.用户姓 ...

  8. Spring AOP技术(基于AspectJ)的Annotation开发

    Spring AOP技术(基于AspectJ)的Annotation开发 @(Spring)[aop, spring, xml, Spring, annotation, aspectJ] Spring ...

  9. Spring AOP技术(基于AspectJ)的XML开发

    Spring AOP技术(基于AspectJ)的XML开发 @(Spring)[aop, spring, xml, Spring, annotation, aspectJ] Spring AOP技术基 ...

  10. 技术干货 | 基于MindSpore更好的理解Focal Loss

    [本期推荐专题]物联网从业人员必读:华为云专家为你详细解读LiteOS各模块开发及其实现原理. 摘要:Focal Loss的两个性质算是核心,其实就是用一个合适的函数去度量难分类和易分类样本对总的损失 ...

最新文章

  1. 看漫画学python 豆瓣_看漫画就能学好python?
  2. oracle 12c 自动任务,Oracle job自动任务实用指南
  3. python -- join()
  4. 作者:李海昌(1984-),男,中国科学院软件研究所助理研究员
  5. 如何理解 Spring AOP 以及使用 AspectJ?
  6. app商城源码_海量的SpringBoot和SSM项目【附带源码+视频教程】快速成为全栈
  7. 高德地图 map.setcenter 动画_娄底三维动画制作公司价格2020行情-立艺数字
  8. 104规约 scada
  9. matlab 搜索 nan,MATLAB NaN详解
  10. 单位dB和dBm的区别
  11. 20172328 2018-2019《Java软件结构与数据结构》第六周学习总结
  12. 涉密计算机用户登录密码多久换一次,涉密计算机口令应根据其密级进行设置并定期更换,秘密级计算机口令更换周期不得超过30天,机密级计算机口令更换周期不得超过10天 - 作业在线问答...
  13. 【控制工程】啥是控制工程?拉开控制工程的帷幕
  14. jQuery学习理解(详细)
  15. AD账号属性的 PwdLastSet 和 PasswordLastSet 有什么区别?
  16. Sentinel整合Dubbo限流实战
  17. unity中mathf.Lerp的运用
  18. 第十一课_编程语言发展史
  19. 【C语言】英文文章出现次数最多的单词
  20. 教师在初中数学课堂该如何有效提问(内有示例)

热门文章

  1. 微型计算机独立显卡,计算机显卡分为哪几类?有什么特点是?
  2. STATA画图命令(一)
  3. 交互技术基础(复习)
  4. 上海市城镇生育保险办法
  5. 80286微处理器和80386的优缺点
  6. 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323
  7. NO32、把数组排成最小的数(很好的一道题)
  8. arcgis调整图框线宽
  9. MATLAB命令窗口与帮助系统
  10. 硬件工程师成长之路(4)——元件焊接