游名科技:基于STM32F103+TMC2160:86步进电机和驱动一体原理...
本帖最后由 mmuuss586 于 2020-8-16 13:21 编辑基于STM32F103+TMC2160:86步进电机和驱动一体原理图/PCB图/教程/源码/数据手册等开源分享资料下载见附件,电脑登入
CUBE界面引脚配置:
定时器1的PWM输出通道1设置:
一、概述TMC2160是一款带脉冲/ 方向接口和SPI接口的高功率步进电机驱动器IC。它能够在从NEMA23到NEMA34及更高级别的步进电机中获得最佳性能。它采用业界最先进的步进电机驱动器,具有简单的Step/Dir接口。使用外部MOS管,可实现高动态,高扭矩驱动。基于TRINAMIC先进的SpreadCycle和StealthChop斩波器,该驱动器可确保绝对无噪音运行,并具有最高效率和最佳电机扭矩。 高集成度,高能效和小外形尺寸使小型化和可扩展的系统成为经济高效的解决方案。硬件完全兼容的TMC5160提供额外的运动控制器,使步进电机控制更轻松。 参数及特点:2相步进电机,线圈电流高达20A(外部MOSFET)带微步插值microPlyer的Step / Dir接口电压范围8 … 60V DCSPI接口最高分辨率每步完成256微步stealthChop2,运行安静,运动平稳共振衰减中频共振spreadCycle高动态电机控制斩波器dcStep负载相关的速度控制stallGuard2高精度无传感器电机负载检测coolStep电流控制,节能高达75%被动制动和续流模式全面保护和诊断紧凑尺寸9x9mm 2 TQFP48封装 应用
1、机器人和工业驱动器
2、纺织、缝纫机
3、包装机械
4、工厂和实验室自动化
5、高速 3D 打印机
6、液体处理
7、医疗
8、办公自动化
9、有线闭路电视
10、自动取款机、现金回收
11、泵和阀门
二、硬件设计
电机驱动主芯片采用TMC2160
TMC2160和5160区别:5160带UART控制及智能定位控制(如速度控制、位置控制);
TMC2160和TMC260 TMC262区别:以前版本需要通过SPI接口设置细分、电流等,新的TMC2160可通过拨码开关设置;
原理图如下图所示:
补充说明:光耦隔离接口如下图所示:
有条件的输入输出最好加些滤波和保护,输出加脉冲整形(比如加74HC14)
拨码开关电路如下图所示:后面开关设置说明详见第三部分;
电源接口如下图所示:
母线电容CE1选择:一般是1A对应100uF左右(有条件的尽可能大);电源保护:有条件的最好加防反接、TVS保护、以及保险丝等;电机接口:如果对EMC要求较高的,最好加些滤波和保护,参考电路如下图
主芯片电路如下图所示:
具体不做阐述,可以参考TMC5160的中文手册;
关于VCC_IO和VCC电源,有条件的可以外加一个DCDC电源芯片或LDO供电,减少芯片发热;
PCB参考设计(最好是4层板):
补充说明:
芯片底部最好不要走其它线,保证地平面完整及散热;
电流取样电阻: 2160外部MOS,要差分采样(开尔文接法);
差分采样走线参考:
3D显示效果:
三、拨码开关设置
拨码开关ON:设置为高电平1,反之低电平0
细分设置:CFG1、CFG0
CFG1、CFG0:
11:64细分
10:32细分
01:16细分
00:8细分
运行电流设置:CFG4、CFG3、CFG2
CFG4、CFG3、CFG2:
111:IRUN=31
110:IRUN=28
101:IRUN=26
100:IRUN=24
011:IRUN=22
010:IRUN=20
001:IRUN=18
000:IRUN=16
Irms=Vfs/(IRUN/32)/(Rsense*1.414);
Vfs =325mV,Rsense为0.05欧时,则最大电流为4.5A左右;
斩波模式选择:CFG5
CFG5:
1:SpreadCyle模式,低速、低平稳运行模式
0:SpreadCyle模式,高速、高运动稳定模式
保持电流设置:CFG6
CFG6:
1:保持电流=运行电流/2
0:保持电流=运行电流
四、软件说明
DIR+STEP接口模式位置控制(无需SPI接口)
COM端:接24V或12V或5V
DRV_ENN、STER、DIR:接集电极开路输出
为测试方便:
COM端:接3.3V
DRV_ENN:使能,接PB14
DIR:方向, PB15
STEP:脉冲,PA8
初始化程序如下参考:
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_TIM1_Init();
STEPMOTOR_TIMx_Init(); /定时器输出初始化
/* USER CODE BEGIN 2 */
STEPMOTOR_OUTPUT_DISABLE(); //TMC2160禁止使能
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
STEPMOTOR_AxisMoveRel(6400*-2, 5000 , 5000 , 1200); //控制TMC2160驱动步进电机反转2圈(32细分,1.8度则一圈需要6400个脉冲)
LedOnOff(); //LED闪烁处理
STEPMOTOR_AxisMoveRel(6400*2, 5000 , 5000 , 1200); //控制TMC2160驱动步进电机反转2圈(32细分,1.8度则一圈需要6400个脉冲)
LedOnOff(); //LED闪烁处理
/* USER CODE BEGIN 3 */
}
//相对位置移动参考(参考硬石的电机开发板资料)
/**
* 函数功能: 相对位置运动:运动给定的步数
* 输入参数: step:移动的步数 (正数为顺时针,负数为逆时针).
accel加速度,实际值为accel*0.1*rad/sec^2
decel减速度,实际值为decel*0.1*rad/sec^2
speed最大速度,实际值为speed*0.1*rad/sec
* 返 回 值: 无
* 说 明: 以给定的步数移动步进电机,先加速到最大速度,然后在合适位置开始
* 减速至停止,使得整个运动距离为指定的步数。如果加减速阶段很短并且
* 速度很慢,那还没达到最大速度就要开始减速
*/
void STEPMOTOR_AxisMoveRel(__IO int32_t step, __IO uint32_t accel, __IO uint32_t decel, __IO uint32_t speed)
{
__IO uint16_t tim_count;
// 达到最大速度时的步数
__IO uint32_t max_s_lim;
// 必须要开始减速的步数(如果加速没有达到最大速度)
__IO uint32_t accel_lim;
if(step < 0) // 步数为负数
{
srd.dir = CCW; // 逆时针方向旋转
STEPMOTOR_DIR_REVERSAL();
step =-step; // 获取步数绝对值
}
else
{
srd.dir = CW; // 顺时针方向旋转
STEPMOTOR_DIR_FORWARD();
}
if(step == 1) // 步数为1
{
srd.accel_count = -1; // 只移动一步
srd.run_state = DECEL;// 减速状态.
srd.step_delay = 1000; // 短延时
}
else if(step != 0)// 如果目标运动步数不为0
{
// 我们的驱动器用户手册有详细的计算及推导过程
// 设置最大速度极限, 计算得到min_delay用于定时器的计数器的值。
// min_delay = (alpha / tt)/ w
srd.min_delay = (int32_t)(A_T_x10/speed);
// 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为0.1rad/sec^2
// step_delay = 1/tt * sqrt(2*alpha/accel)
// step_delay = ( tfreq*0.676/10 )*10 * sqrt( (2*alpha*100000) / (accel*10) )/100
srd.step_delay = (int32_t)((T1_FREQ_148 * sqrt(A_SQ / accel))/10);
// 计算多少步之后达到最大速度的限制
// max_s_lim = speed^2 / (2*alpha*accel)
max_s_lim = (uint32_t)(speed*speed/(A_x200*accel/10));
// 如果达到最大速度小于0.5步,我们将四舍五入为0
// 但实际我们必须移动至少一步才能达到想要的速度
if(max_s_lim == 0){
max_s_lim = 1;
}
// 计算多少步之后我们必须开始减速
// n1 = (n1+n2)decel / (accel + decel)
accel_lim = (uint32_t)(step*decel/(accel+decel));
// 我们必须加速至少1步才能才能开始减速.
if(accel_lim == 0){
accel_lim = 1;
}
// 使用限制条件我们可以计算出减速阶段步数
if(accel_lim <= max_s_lim){
srd.decel_val = accel_lim - step;
}
else{
srd.decel_val = -(max_s_lim*accel/decel);
}
// 当只剩下一步我们必须减速
if(srd.decel_val == 0){
srd.decel_val = -1;
}
// 计算开始减速时的步数
srd.decel_start = step + srd.decel_val;
// 如果最大速度很慢,我们就不需要进行加速运动
if(srd.step_delay <= srd.min_delay){
srd.step_delay = srd.min_delay;
srd.run_state = RUN;
}
else{
srd.run_state = ACCEL;
}
// 复位加速度计数值
srd.accel_count = 0;
}
MotionStatus = 1; // 电机为运动状态
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay); // 设置定时器比较值
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_ENABLE); // 使能定时器通道
STEPMOTOR_OUTPUT_ENABLE();
}
//定时器中断函数参考
/**
* 函数功能: 定时器中断服务函数
* 输入参数: 无
* 返 回 值: 无
* 说 明: 实现加减速过程
*/
void STEPMOTOR_TIMx_IRQHandler(void)//定时器中断处理
{
__IO uint16_t tim_count=0;
// 保存新(下)一个延时周期
uint16_t new_step_delay=0;
// 加速过程中最后一次延时(脉冲周期).
__IO static uint16_t last_accel_delay=0;
// 总移动步数计数器
__IO static uint32_t step_count = 0;
// 记录new_step_delay中的余数,提高下一步计算的精度
__IO static int32_t rest = 0;
//定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲
__IO static uint8_t i=0;
if(__HAL_TIM_GET_IT_SOURCE(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx) !=RESET)
{
// 清楚定时器中断
__HAL_TIM_CLEAR_IT(&htimx_STEPMOTOR, STEPMOTOR_TIM_IT_CCx);
// 设置比较值
tim_count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tim_count+srd.step_delay);
i++; // 定时器中断次数计数值
if(i==2) // 2次,说明已经输出一个完整脉冲
{
i=0; // 清零定时器中断次数计数值
switch(srd.run_state) // 加减速曲线阶段
{
case STOP:
step_count = 0;// 清零步数计数器
rest = 0; // 清零余值
// 关闭通道
TIM_CCxChannelCmd(STEPMOTOR_TIMx, STEPMOTOR_TIM_CHANNEL_x, TIM_CCx_DISABLE);
__HAL_TIM_CLEAR_FLAG(&htimx_STEPMOTOR, STEPMOTOR_TIM_FLAG_CCx);
STEPMOTOR_OUTPUT_DISABLE();
MotionStatus = 0;//电机为停止状态
break;
case ACCEL:
step_count++; // 步数加1
if(srd.dir==CW)
{
step_position++; // 绝对位置加1
}
else
{
step_position--; // 绝对位置减1
}
srd.accel_count++; // 加速计数值加1
new_step_delay = srd.step_delay - (((2 *srd.step_delay) + rest)/(4 * srd.accel_count + 1));//计算新(下)一步脉冲周期(时间间隔)
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
if(step_count >= srd.decel_start)// 检查是够应该开始减速
{
srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值
srd.run_state = DECEL; // 下个脉冲进入减速阶段
}
else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度
{
last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
rest = 0; // 清零余值
srd.run_state = RUN; // 设置为匀速运行状态
}
break;
case RUN:
step_count++;// 步数加1
if(srd.dir==CW)
{
step_position++; // 绝对位置加1
}
else
{
step_position--; // 绝对位置减1
}
new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
if(step_count >= srd.decel_start) // 需要开始减速
{
srd.accel_count = srd.decel_val;// 减速步数做为加速计数值
new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)
srd.run_state = DECEL; // 状态改变为减速
}
break;
case DECEL:
step_count++;// 步数加1
if(srd.dir==CW)
{
step_position++; // 绝对位置加1
}
else
{
step_position--; // 绝对位置减1
}
srd.accel_count++;
new_step_delay = srd.step_delay - (((2 * srd.step_delay) + rest)/(4 * srd.accel_count + 1)); //计算新(下)一步脉冲周期(时间间隔)
rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
//检查是否为最后一步
if(srd.accel_count >= 0)
{
srd.run_state = STOP;
}
break;
}
srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
}
}
}
五、开源补充说明
如果确实需要原理图和PCB的用户,请联系我们的客服或管理员私下索取谢谢!