关于TMC系列的电机驱动芯片的使用(基与F405的spi控制)

这个系列的驱动芯片大多都是有两种控制模式的

一种是spi控制,不用发脉冲,直接通过spi发命令给驱动芯片控制电机

一种是通过step/dir引脚控制,这个之前发过一篇2130的文章,但我觉得发脉冲控制的方式不好用,所以不多赘述

使用spi控制最主要是给驱动芯片配置寄存器,电机上电是不会自锁的,得配置好寄存器后正确配置才能锁住

下面是流程

1:先初始化spi通信脚,芯片使能脚,spi片选脚(本文使用的是多个电机)

注意:(在初始化后需要把使能脚上拉,并且置1,在写入寄存器配置后再拉低使能,不然会出现过流的情况,在另一篇文章有说到)

#define SPI1_CS0 PBout(0)   //第一个的片选引脚
#define SPI1_CS1 PCout(5)   //第二个的片选引脚
#define SPI1_CS2 PCout(4)   //第三个的片选引脚


#define MOTOR_EN3 PAout(0)
#define MOTOR_EN2 PAout(1)      //电机使能信号2    
#define MOTOR_EN1 PAout(2)      //电机使能信号1    
 

        GPIO_InitTypeDef  GPIO_InitStructure;  
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);//使能GPIOB时钟

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_0 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;/
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;//
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//
  GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
    

    MOTOR_EN1 = 1;
    MOTOR_EN2 = 1;
    MOTOR_EN3 = 1;
    
    SPI1_CS0 = 1;
    SPI1_CS1 = 1;
    SPI1_CS2 = 1;

2初始化寄存器

void TMC_5041_Init_aks(Motor_Single_Status *moto,u8 ch)
{
        spi_send_int(TMC5160_GCONF,0x4 , ch);
        delay_ms(10);    
        spi_send_int(TMC5160_CHOPCONF, 0x100c3 , ch);
        delay_ms(10);    
        spi_send_int(TMC5160_IHOLD_IRUN,0x60303, ch);
        delay_ms(10);        
        spi_send_int(TMC5160_TPOWERDOWN, 0xa, ch);
        delay_ms(10);    
        spi_send_int(TMC5160_TPWMTHRS, 0x1f4, ch);
        delay_ms(10);    
        spi_send_int(TMC5160_PWMCONF, 0X401C8,ch);
        delay_ms(10);    
        spi_send_int(TMC5160_A1,0x3e8, ch);
        delay_ms(10);    
        spi_send_int(TMC5160_V1,0xc350, ch);
        delay_ms(10);    
        spi_send_int(TMC5160_AMAX,0x1f4, ch);
        delay_ms(10);    
        spi_send_int(TMC5160_VMAX,0x30d40, ch);
        delay_ms(10);    
        spi_send_int(TMC5160_DMAX,0x2bc, ch);
        delay_ms(10);    
        spi_send_int(TMC5160_D1,0x578, ch);
        delay_ms(10);    
        spi_send_int(TMC5160_VSTOP,0xa, ch);//moto->VSTOP
        delay_ms(10);    
        spi_send_int(TMC5160_RAMPMODE,0x0, ch);
        delay_ms(10);    
        spi_send_int(TMC5160_SWMODE, 0x40f, ch);

        delay_ms(10);  

        spi_send_int(TMC5160_ENCMODE,0X72c);
        delay_ms(10);        
        spi_send_int(TMC5160_ENCCONST,0XFA0);
        delay_ms(10);        
        delay_ms(300);
        switch(ch)
        {
            case 0:
                MOTOR_EN1 = 0;
            break;
            case 1:
                MOTOR_EN2 = 0;
            break;
            case 2:
                MOTOR_EN3 = 0;                    
            break;
        }
        delay_ms(100);
}

//配置是按照推荐配置来的

spi发送函数

多电机的片选,单电机可以去掉

void spi_send_int(u8 addr, int data, u8 ch)
{
    int temp;
    u8 temp1;
    u8 temp2;
    switch(ch)
    {
        case 0:
        {
            SPI1_CS0 = 0;        
        }break;
        
        case 1:
        {
            SPI1_CS1 = 0;        
        }break;
        
        case 2:
        {
            SPI1_CS2 = 0;        
        }break;        
    }

    addr = addr + 0x80;
    SPI1_ReadWriteByte(&temp2,&addr,1);
    for(int i = 0 ;  i < 4 ; i++)
    {
        temp = data & 0xff000000;
        temp1 = temp >> 24;    
        SPI1_ReadWriteByte(&temp2,&temp1,1);
        data = data << 8;
    }
    switch(ch)
    {
        case 0:
        {
            SPI1_CS0 = 1;        
        }break;
        
        case 1:
        {
            SPI1_CS1 = 1;        
        }break;
        
        case 2:
        {
            SPI1_CS2 = 1;        
        }break;        
    }
}

spi接收函数

int spi_rec_data(u8 addr, int ch)
{
    unsigned char InputBuf[5]={0x00};
    unsigned char OutputBuf[5]={0x00};
    
    int data = 0;
    switch(ch)
    {
        case 0:
        {
            SPI1_CS0 = 0;        
        }break;
        
        case 1:
        {
            SPI1_CS1 = 0;        
        }break;
        
        case 2:
        {
            SPI1_CS2 = 0;        
        }break;        
        
    }
    
    OutputBuf[0] = addr;
    SPI1_ReadWriteByte(InputBuf, OutputBuf ,5);
    data = InputBuf[1];
    data = data<<8 | InputBuf[2];
    data = data<<8 | InputBuf[3];
    data = data<<8 | InputBuf[4];
    
    switch(ch)
    {
        case 0:
        {
            SPI1_CS0 = 1;        
        }break;
        
        case 1:
        {
            SPI1_CS1 = 1;        
        }break;
        
        case 2:
        {
            SPI1_CS2 = 1;        
        }break;            
    }
    
    return data;
}
 

spi读写字节
void SPI1_ReadWriteByte(uint8_t *InputBuffer,uint8_t *OutputBuffer,uint8_t NoOfBytes)
{           
  u32 Byte;
    unsigned char Register;
    
  for(Byte=0;Byte<NoOfBytes;Byte++)
    {
        Register=*OutputBuffer;
        SPI_I2S_SendData(SPI1,Register);
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
        
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    *InputBuffer=SPI_I2S_ReceiveData(SPI1);
    OutputBuffer++;
    InputBuffer++;        
  }
}

 下面是使用比如绝对运动

                        //设置为定位模式
                        spi_send_int(TMC5160_RAMPMODE, 0X0, 轴号);
                        //设置速度
                        spi_send_int(TMC5160_VMAX, 0xc350, 轴号);
                        //设置目标位置
                        spi_send_int(TMC5160_XTARGET, 0xc800, 轴号);
 

还有就是读取寄存器的时候需要先读一遍丢弃,再读一遍获取比如

                unused_data = spi_rec_data(TMC5160_XTARGET, 1);丢弃
                motor1.xtarget = spi_rec_data(TMC5160_XTARGET, 1);存入值


                unused_data = spi_rec_data(TMC5160_XACTUAL, 1);丢弃
                motor1.xactual = spi_rec_data(TMC5160_XACTUAL, 1);存入值


                unused_data = spi_rec_data(TMC5160_VACTUAL, 1);
                motor1.vactual = spi_rec_data(TMC5160_VACTUAL, 1);

有一个闭环代码,可以看看,不知道能不能用,可以自己调试一下

                unused_data = spi_rec_data(TMC5130_XENC);
                motor.xenc = spi_rec_data(TMC5130_XENC);读取编码器位置
                En_code = motor.xenc * 32;

//根据编码器的返回值计算脉冲,大概调到跟发送的脉冲一样就行,这里用1000线编码器,分辨率设置为4000,在前面的TMC5160_ENCCONST寄存器

                one = motor.xactual;
                err_code = one - En_code;计算误差
                
                if(err_code > MAX_err || (-1) * err_code > MAX_err)//判断是否需要闭环
                {
                    
                    loop_flag = 2;
                }
                
                //判断是否到位
                if(motor.ex_place_flag == 1 && loop_flag == 2)开始闭环   
                {        
                    //将编码器放回的值锁存到实际电机位置,
                        spi_send_int(TMC5130_XACTUAL, En_code);
                        delay_ms(100);
                        unused_data = spi_rec_data(TMC5130_XACTUAL);
                        two = spi_rec_data(TMC5130_XACTUAL);    查看有没有写进去


                  //  在运动一个目标位置
                    delay_ms(100);
                    spi_send_int(TMC5130_VMAX, 0x0);
                    //设置为定位模式
                    spi_send_int(TMC5130_RAMPMODE, 0X0);
                    //设置速度
                    spi_send_int(TMC5130_VMAX, 0x1388);//检查这些电机参数的最优配置
                    //设置目标值
                    spi_send_int(TMC5130_XTARGET, one);目标位置
                    
                    loop_flag = 0;
             

   }

加油搞,拼拼凑凑挺简单的,不懂就留言,我会就解答,点个赞谢谢哦
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值