分享:步进电机细分驱动思路及程序

2019-12-13 18:21发布

微步驱动原理:
     细分驱动,把加在线圈上的电压 从最大到最小的过程,分四次给完,产生四个中间
         状态,即四细分。伟力电机内部转子一个分步角度为60度。四细分之后,就变成
     15度。外部指针则转1/12度。
细分方法:
     根据电流等分,得到四个电压点,根据这四个电压点,预先计算出四个PWM值。
         于是一个过程就需要24个点。
         单片机需要处理的就是电流的方向控制。由伟力电机时序图,可以分析出每一个相的
         电流方向。有四种情况。
         正相增大,正相减小,反向增大,反向减小。



const unsigned char OCRnA_Val[24] =
{
    5,48,94,163,220,247,250,247,220,163,94,48,5,207,161,92,34,8,5,8,34,92,161,207
}; //微步码 两个线圈中电流相位是60度,


void step_moto_control(void)
{
    if(direction_flag)  //正转  
    {   
        if(OCRnA_Num_L==0)
        {
            OCRnA_Num_L = 23;
            coil_1B_ON();     
        }
        else
              OCRnA_Num_L--;                  
        if(OCRnA_Num_L<=12) coil_1B_CLE();  
        OCR0A  =  OCRnA_Val[OCRnA_Num_L];   //左线圈电流
               
        if(OCRnA_Num_R==0)
        {
             OCRnA_Num_R = 23;
             coil_2B_ON();   
        }
        else
          OCRnA_Num_R--;
        if(OCRnA_Num_R<=12) coil_2B_CLE();
        OCR0B  =  OCRnA_Val[OCRnA_Num_R];
    }
    else  //反转
    {
        OCRnA_Num_L++;
        if(OCRnA_Num_L>=13) coil_1B_ON();  
        if(OCRnA_Num_L>23)
        {
           OCRnA_Num_L=0;
           coil_1B_CLE();     
        }
        OCR0A  =  OCRnA_Val[OCRnA_Num_L];  
        OCRnA_Num_R++;
        if(OCRnA_Num_R>=13) coil_2B_ON();
        if(OCRnA_Num_R>23)
        {
           OCRnA_Num_R=0;
           coil_2B_CLE();   
        }
        OCR0B  =  OCRnA_Val[OCRnA_Num_R];
     }
}  
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
49条回答
ZJSXHWL000000
1楼-- · 2019-12-16 11:32
楼上的,真心感谢您的指导,我的不细分没问题,一细分,就抖的很厉害。
细分时实验的代码。请您指导一下。
//ICC-AVR application builder : 2014-2-4 9:18:54
// Target : M16
// Crystal: 8.0000Mhz

#include <iom16v.h>
#include <macros.h>
# define unint unsigned int
# define uchar unsigned char

#define SET_BIT(io ,bit) (  io |=  (1<<bit) )
//置位: SET_BIT(PORTA,0);SET_BIT(DDRA,0);
#define CLR_BIT(io ,bit) (  io &= ~(1<<bit) )
//清0: CLR_BIT(PORTA,0);CLR_BIT(DDRA,0);
#define GET_BIT(pin,bit) ( pin &   (1<<bit) )
//读位: GET_BIT(PINA,0);
#define SET_IN( dir,bit) ( dir &= ~(1<<bit) )
//端口方向输入: SET_IN(DDRA,0);
#define SET_OUT(dir,bit) ( dir |=  (1<<bit) )
//端口方向输出: SET_OUT(DDRA,0);
#define INVBIT(io,bit)   ( io ^=   (1<<bit) )
//反转方向
//
#define STEPPER_LN_1 SET_BIT(PORTB ,0)
#define STEPPER_LN_0 CLR_BIT(PORTB ,0)
//
#define STEPPER_RN_1 SET_BIT(PORTB ,1)
#define STEPPER_RN_0 CLR_BIT(PORTB ,1)

#define STEPPER_LR_1 SET_BIT(PORTD ,4)
#define STEPPER_LR_0 CLR_BIT(PORTD ,4)

#define STEPPER_RL_1 SET_BIT(PORTD ,5)
#define STEPPER_RL_0 CLR_BIT(PORTD ,5)

#define STEP_LN_1 SET_BIT(PORTA ,6)
#define STEP_LN_0 CLR_BIT(PORTA ,6)
#define STEP_RN_1 SET_BIT(PORTA ,4)
#define STEP_RN_0 CLR_BIT(PORTA ,4)

#define STEP_LR_1 SET_BIT(PORTA ,5)
#define STEP_RL_1 SET_BIT(PORTA ,5)

#define STEP_LR_0 CLR_BIT(PORTA ,5)
#define STEP_RL_0 CLR_BIT(PORTA ,5)


unsigned  char OCRnA_Num_L ,OCRnA_Num_R ;

unsigned char direction_flag = 1;
const unsigned char OCRnA_Val[24] =
{
5,48,94,163,220,247,250,247,220,163,94,48,5,207,161,92,34,8,5,8,34,92,161,207

//0,65,127,180,221,246,255,246,221,180,127,65,0,190,128,75,34,9,0,9,34,75,128,190
}; //微步码 两个线圈中电流相位是60度,


void delay_1us(void)                 //1us延时函数
  {
   asm("nop");
  }
void delay_nus(unsigned short int n)       //N us延时函数
  {
   unsigned short int i=0;
   for (i=0;i<n;i++)
   delay_1us();
  }

void Delay_1ms(void)                 //1ms延时函数
  {
   unsigned short int i;
   for (i=0;i<(unsigned short int)(8*143-2);i++);
  }

void Delay_nms(unint n)                //n*1mS延时子函数
{
unint i=0;
   while(i<n)
   {
    Delay_1ms();
    i++;
   }
}




void port_init(void)
{
PORTA = 0xFF;
DDRA  = 0xFF;
PORTB = 0x0f;
DDRB  = 0xFF;
PORTC = 0x0f; //m103 output only
DDRC  = 0xFF;
PORTD = 0xff;
DDRD  = 0xff;
}

//TIMER0 initialize - prescale:8
// WGM: Normal
// desired value: 255uSec
// actual value: 255.000uSec (0.0%)
void timer0_init(void)
{
TCCR0 = 0x00; //stop
TCNT0 = 0x01; //set count
OCR0  = 0xFF;  //set compare
TCCR0 = 0x01; //start timer
}


//TIMER1 initialize - prescale:8
void timer1_init(void)
{
TCCR1B = 0x00;
//OCR1AH = 0x01;
OCR1AL = 0xF4;
//OCR1BH = 0x01;
OCR1BL = 0xF4;
TCCR1A = 0x61;
TCCR1B = 0x02; //start Timer
}


//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
//timer0_init();
timer1_init();

MCUCR = 0x00;
GICR  = 0x00;
//TIMSK = 0x01; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}

void step_moto_control(void)
{
  
   if(direction_flag)    //反转
    {   

        if(OCRnA_Num_L==0) { OCRnA_Num_L = 23;STEPPER_LN_0;}//正负端左接1。
        else OCRnA_Num_L--;                  
        if(OCRnA_Num_L <= 12) STEPPER_LN_1;   //正负端左接0。         
        OCR1AL  =  OCRnA_Val[OCRnA_Num_L];   //左线圈电流
        OCR1AH = 0x00;   
                    
        if(OCRnA_Num_R==0)
        {OCRnA_Num_R = 23;STEPPER_RN_1; }//正负端右接1。
        else  OCRnA_Num_R--;
        if(OCRnA_Num_R <= 12) STEPPER_RN_0;  //正负端右接0。
        OCR1BL   =  OCRnA_Val[OCRnA_Num_R];//右线圈电流
                OCR1BH = 0x00;

    }
       
    else //正转
    {

       
                if(OCRnA_Num_L>23)  {OCRnA_Num_L=0;STEPPER_LN_0;} //正负端左接0。  
        else {OCRnA_Num_L++;}
        if(OCRnA_Num_L>12) STEPPER_LN_1;//正负端左接1。   
        OCR1AL  =  OCRnA_Val[OCRnA_Num_L];  
                OCR1AH = 0x00;
               
            if(OCRnA_Num_R>23) {OCRnA_Num_R=0;STEPPER_RN_0;}  //正负端右接1。           
        else OCRnA_Num_R++;
        if(OCRnA_Num_R>12) STEPPER_RN_1;//正负端右接1。
        OCR1BL  =  OCRnA_Val[OCRnA_Num_R];
        OCR1BH = 0x00;
      
     }
}

/*
1个脉冲转子转60,指针转1/3度。
1/3度*90(1个周期6个脉冲)=180  (个脉冲)*6/180减速比
*/
//24*90

void main(void)
{
unint k = 2250;
init_devices();
direction_flag = 0;
  
        //逆时针
            STEPPER_LN_0;
                STEPPER_RN_0;
                OCRnA_Num_L = 6;
                OCRnA_Num_R = 10;
               
       
   //  顺时
        STEPPER_LN_0;
                STEPPER_RN_0;
                OCRnA_Num_L = 4;
                OCRnA_Num_R = 0;
       

while(1)
{

     delay_nus(255);
     step_moto_control();
  }
}

#pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF
void timer1_ovf_isr(void)
{
TCNT1H = 0xFF;
TCNT1L = 0x00;
//step_moto_control();
}


#pragma interrupt_handler timer0_ovf_isr:iv_TIM0_OVF
void timer0_ovf_isr(void)
{
TCNT0 = 0x00; //reload counter value
//step_moto_control();
}
ZJSXHWL000000
2楼-- · 2019-12-16 12:09
 精彩回答 2  元偷偷看……
ZJSXHWL000000
3楼-- · 2019-12-16 12:55
您的程序的中间大括号有忘记,         
Speed_control_temp  =  3;
}
         else
             {
xuer3652
4楼-- · 2019-12-16 16:22
请问楼主的驱动表不是最优化驱动吧?
ZJSXHWL000000
5楼-- · 2019-12-16 21:33
能不能请楼主讲一下:
梯形加减速。
一个全步之后换一次速度。回零最佳曲线。
是什么意思。
fengyunyu
6楼-- · 2019-12-17 01:42
ZJSXHWL000000 发表于 2014-4-27 15:49
我用您的程序做实验,反转可以。正转细分不动。
还有噪声太大了。
还不如不细分。是不是PWM输出需要H桥驱动 ...

没看懂。你描述的问题,是LZ程序的问题,还是你没有用好?

一周热门 更多>