tmc2209+esp32驱动42步进电机
一、tmc2209芯片
我是从优信电子购买的tmc2209芯片(红色排针),优信电子淘宝商店有不同的型号,引脚和人性能落有不同,但都大差不差,我这里主要介绍红色排针型号的。
1.tmc2209性能介绍
核心技术亮点
-
StealthChop2™ (静音技术):这是它最核心的卖点。通过一种精密的电压斩波算法,能几乎完全消除电机在低速运转时产生的可听噪音和振动。
-
SpreadCycle™ (高性能斩波):当电机需要高速运转时,可以切换到这种模式。它提供了极其精准的电流控制,保证电机在高动态运动下也能有出色的性能和稳定性。
-
StallGuard4™ (无传感器堵转检测):这是一个非常实用的功能。它可以根据电机内部的电磁场变化,在不依赖外部机械限位开关的情况下,精准检测到电机是否发生了堵转或负载过重。这常用于实现“无传感器归零”。
-
CoolStep™ (节能技术):它能根据电机的实际负载,自动、动态地调整驱动电流。在轻负载时自动降低电流,最高可节约75%的能量,并显著减少芯片发热。
-
MicroPlyer™ (微步插值):即使您的微控制器发送的是较低分辨率的脉冲(比如只支持1/16步),它也能内部自动将这些粗糙的步进“插值”平滑为1/256微步,从而获得更顺滑的运动效果。
两种工作模式
独立模式 (Standalone)(DIR/STEP控制)
-
配置方式:通过硬件引脚(MS1, MS2)设置细分,通过电位器(VREF)调节电流。
-
优点:简单,无需编程,可以快速上手,直接替换A4988等传统驱动器。
-
缺点:无法使用StallGuard4、CoolStep等高级功能,配置后无法动态更改。
UART模式 (Serial)
-
配置方式:通过UART_TX/UART_RX引脚与主控通信,通过软件配置寄存器来设置所有参数。
-
优点:功能全开,可以动态调整电流、细分、工作模式,并能读取芯片状态(如堵转报警)。
-
缺点:需要编写或移植通信代码,连接和配置稍复杂。
这里我们介绍的是独立工作模式。
2.引脚图

引脚简要介绍:
| EN | 芯片使能引脚,接低电平时使能芯片 |
| MS1/MS2 | 控制电机细分,具体后面会说 |
| USART | 用于usart模式 |
| CLK | 时钟线,如果使用内部时钟需要接地 |
| STEP | 给脉冲驱动电机 |
| DIR | 控制电机正转和反转, |
| VM | 给电机的电压,5到24V都可以,但是电压低可能会丢步 |
| M1B/M1A | 电机线圈绕组1,接A+/A- 或者 B+/B- |
| M2B/M2A | 电机线圈绕组2,接A+/A- 或者 B+/B- |
| VIO | 给tmc2209芯片的电压,一般给3.3V或5V即可 |
3.细分介绍

原本42步进电机一个完整脉冲电机转动1.8度。
8细分控制精度=1.8°/8=0.225°,电机转一周需要1600个脉冲。
16细分控制精度=1.8°/16=0.1125°,电机转一周需要3200个脉冲。
32细分控制精度=1.8°/32=0.05625°,电机转一周需要6400个脉冲。
64细分控制精度=1.8°/64=0.0140625°,电机转一周需要12800个脉冲。
细分越细,精度越高,但是可能力矩会不够,看需求使用
二、步进电机介绍

基本的步距角为1.8度。
一般红线和蓝线是A相,绿色和黑色是B相
三、驱动代码
#define GPIO_PIN_RESET 0
#define GPIO_PIN_SET 1
#define DIR_Pin GPIO_NUM_1
#define STEP_Pin GPIO_NUM_2
#define EN_Pin GPIO_NUM_40
#define MS1_Pin GPIO_NUM_0
#define MS2_Pin GPIO_NUM_0
选择细分模式
uint8_t tmc_set_subdivision(uint8_t i)
{
uint8_t subdevision_value = i;
//电机使能
gpio_set_level(EN_Pin, GPIO_PIN_RESET);
if(i==8)
{
gpio_set_level(MS2_Pin, GPIO_PIN_RESET);
gpio_set_level(MS1_Pin, GPIO_PIN_RESET);
}
else if(i==32)
{
gpio_set_level(MS2_Pin, GPIO_PIN_RESET);
gpio_set_level(MS1_Pin, GPIO_PIN_SET);
}
else if(i==64)
{
gpio_set_level(MS2_Pin, GPIO_PIN_SET);
gpio_set_level(MS1_Pin, GPIO_PIN_RESET);
}
else if ( i== 128)
{
gpio_set_level(MS2_Pin, GPIO_PIN_SET);
gpio_set_level(MS1_Pin, GPIO_PIN_SET);
}
//电机非使能
gpio_set_level(EN_Pin, GPIO_PIN_SET);
return subdevision_value;
}
电机pwm初始化
void tmc_pwm_init() {
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE, //配置低速模式
.duty_resolution = LEDC_TIMER_10_BIT, //选择10位分辨率,即切分为1024个切片
.timer_num = LEDC_TIMER_1, //配置定时器
.freq_hz = 100, //配置频率
.clk_cfg = LEDC_AUTO_CLK, //配置时钟源
};
ledc_timer_config(&ledc_timer);
ledc_channel_config_t ledc_channel = {
.channel = LEDC_CHANNEL_1, //设置pwm输出通道(就是从把个通道中选择一个)
.duty = 0, //设置高电平所占的切块数量(控制占空比)
.flags.output_invert = 0, //配置pwm脉冲的高低电平是否翻转,对应pwm生成器的选择器1,
.gpio_num = STEP_Pin, //选择输出的引脚
.hpoint = 0, //设置hpoint
.intr_type = LEDC_INTR_DISABLE, //是否设置中断
.speed_mode = LEDC_LOW_SPEED_MODE, //pwm的输出模式,和上一结构体一致
.timer_sel = LEDC_TIMER_1, //设置pwm生成器的定时器
};
ledc_channel_config(&ledc_channel);
}
其他引脚初始化
void tmc_gpio_init() {
//配置DIR引脚和STEP引脚
gpio_config_t gpio_Config_1 = {
.intr_type = GPIO_INTR_DISABLE,
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = (1ull <<DIR_Pin) | (1ull <<STEP_Pin ) ,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.pull_up_en = GPIO_PULLUP_DISABLE,
};
gpio_config(&gpio_Config_1);
//配置EN引脚,先拉高,失能芯片
gpio_config_t gpio_Config_2 = {
.intr_type = GPIO_INTR_DISABLE,
.mode = GPIO_MODE_INPUT_OUTPUT,
.pin_bit_mask = 1ull << EN_Pin,
.pull_down_en = GPIO_PULLDOWN_ENABLE,
.pull_up_en = GPIO_PULLUP_DISABLE,
};
gpio_config(&gpio_Config_2);
gpio_set_level(EN_Pin, GPIO_PIN_SET);
//配置MS1与MS2引脚,默认先八细分
gpio_config_t gpio_Config_3 = {
.intr_type = GPIO_INTR_DISABLE,
.mode = GPIO_MODE_INPUT_OUTPUT,
.pin_bit_mask = (1ull << MS1_Pin)|(1ull<MS2_Pin),
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.pull_up_en = GPIO_PULLUP_DISABLE,
};
gpio_config(&gpio_Config_3);
}
设置转动角度:
void tmc_set_angle(uint8_t DIR,uint8_t subdevision_value,float angle) {
//电机使能
gpio_set_level(EN_Pin, GPIO_PIN_RESET);
//设置方向
if(DIR){
gpio_set_level(DIR_Pin, GPIO_PIN_SET);//正转
}
else{
gpio_set_level(DIR_Pin, GPIO_PIN_RESET); //反转
}
float per_angle = 1.8 / subdevision_value; //计算细分后没个脉冲所运动的角度
uint64_t pluse_num = (uint64_t) ( angle / per_angle ); //需要的脉冲数
uint32_t speed_hz = ledc_get_freq(LEDC_LOW_SPEED_MODE, LEDC_TIMER_1);
uint64_t time = ( (float)pluse_num * 1000 ) / speed_hz ; //计算需要等待的时间
//开始发送脉冲
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 1024/2);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1);
//延时直达相应的脉冲发送完毕
vTaskDelay(pdMS_TO_TICKS(time));
//停止发送脉冲
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1);
//电机非使能
gpio_set_level(EN_Pin, GPIO_PIN_SET);
}
demo
void app_main(void) {
tmc_init();
while(1) {
//MoveStep(1,12800*10); //正转一圈
uint8_t subdivision_value = tmc_set_subdivision(8);
tmc_set_angle(1,subdivision_value ,180);
vTaskDelay(50); //延时2S
//MoveStep(0,12800*10); //反转一圈
tmc_set_angle(0,subdivision_value ,180);
vTaskDelay(50); //延时2S
}
}
更多推荐

所有评论(0)