terencechang 发表于 2012-4-26 17:05:02

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

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



const unsigned char OCRnA_Val =
{
    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;   //左线圈电流
               
      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;
    }
    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_R++;
      if(OCRnA_Num_R>=13) coil_2B_ON();
      if(OCRnA_Num_R>23)
      {
         OCRnA_Num_R=0;
         coil_2B_CLE();   
      }
      OCR0B=OCRnA_Val;
   }
}

terencechang 发表于 2012-4-26 17:05:52

SF SF SF SF SF

ZJSXHWL000000 发表于 2014-2-5 10:31:54

还有下文码

suifeng1009 发表于 2014-2-6 20:47:14

顶一个!期待下文!

zl_123 发表于 2014-2-8 19:41:05

谢谢                  

ainiyifei 发表于 2014-3-6 23:24:25

顶一下,谢谢分享

guiliang110 发表于 2014-3-6 23:30:11

怎么没有下文了呀

ZJSXHWL000000 发表于 2014-4-21 05:56:03

怎么没有下文了呀

terencechang 发表于 2014-4-21 11:42:09

ZJSXHWL000000 发表于 2014-4-21 05:56
怎么没有下文了呀

思路,程序也都有啦。完结啦!

xuanfong1 发表于 2014-4-21 12:13:27

我来看看,别在意。

ZYBing 发表于 2014-4-21 13:32:27

mark,谢谢分享

kevinliu_wei 发表于 2014-4-21 17:07:07

顶一下

terencechang 发表于 2014-4-22 08:58:39

还有一个台达步进电机的256细分程序。搞过仪表的人懂的。好像网上基本查不到台达步进电机细分驱动的相关知识。
有需要的人说下。共享之。

shelaoda 发表于 2014-4-22 09:42:59

不错~~~~~~~

ZJSXHWL000000 发表于 2014-4-25 09:03:45

能上的,能不能把台达的驱动也讲一下。

ZJSXHWL000000 发表于 2014-4-27 15:49:35

我用您的程序做实验,反转可以。正转细分不动。
还有噪声太大了。
还不如不细分。是不是PWM输出需要H桥驱动伟力的仪表用步进电机。

terencechang 发表于 2014-4-28 16:17:37

ZJSXHWL000000 发表于 2014-4-27 15:49
我用您的程序做实验,反转可以。正转细分不动。
还有噪声太大了。
还不如不细分。是不是PWM输出需要H桥驱动 ...

不用上面的程序 是量产的代码 都做货几年啦。

hejiang177 发表于 2014-4-28 23:33:01

电机表示不会,还要学习

ZJSXHWL000000 发表于 2014-4-29 05:24:39

我想问:是不是PWM输出需要H桥驱动伟力的仪表用步进电机。
因为直接驱动仪表的M9S12HY内部都带,而通用单片机一般都有外部专用芯片。没有PWM直接驱动的。

terencechang 发表于 2014-4-29 08:53:22

ZJSXHWL000000 发表于 2014-4-29 05:24
我想问:是不是PWM输出需要H桥驱动伟力的仪表用步进电机。
因为直接驱动仪表的M9S12HY内部都带,而通用单片 ...

不是的。看我上面代码应该就知道。一个电机需要2个PWM 跟两个普通IO驱动,不需要专用IC 。我用瑞萨8路PWM的同时驱动4个电机做仪表盘 ,效果妥妥的。
如果你用飞思卡尔的 仪表专用 芯片 就不需要驱动了啊,他内部带驱动的。

ZJSXHWL000000 发表于 2014-4-29 17:18:53

楼上是汽车仪表的专家,我用ATMEL 16的两路PWM驱动都有问题。PWM电流驱动小于10ma.而步进电机为17ma,无法正常驱动。
噪声也太大。
瑞萨8路PWM没用过。
我看网上有加与门74HC08驱动。
还有楼上怎么联系。

terencechang 发表于 2014-5-4 08:33:04

ZJSXHWL000000 发表于 2014-4-29 17:18
楼上是汽车仪表的专家,我用ATMEL 16的两路PWM驱动都有问题。PWM电流驱动小于10ma.而步进电机为17ma,无法 ...

AVR直接驱动 电流不是问题。具体数据 我忘记了。可以很负责的告诉 你 。avr MEGA88P 直接驱动 我出货 N多。
瑞萨,357c这个 型号 的单片机 有加一个门电路 去驱动。但是门电路 仅仅是 扩充 IO 电流而已!

terencechang 发表于 2014-5-4 08:35:18

/**************************************************************
步进电机速度控制函数
***************************************************************/
void Speed_Control(void)
{
           unsigned int angle_difference = 0;
        unsigned int Speed_control_temp = 0;
        if(current_angle == set_angle)
        {
               Speed_control_Val = 50;
               return;
        }
        else
        {
          if(direction_flag==CCW)
                angle_difference = current_angle - set_angle;
      else if(direction_flag==CW)
                 angle_difference = set_angle - current_angle;
                if(angle_difference>=100) //>=9
                {
                     if(angle_difference>=1080)             //>90
                        Speed_control_temp=1;       
                       else if(angle_difference>=720)         //60
                              Speed_control_temp=2;
                       else if(angle_difference>=540)         //>45
                              Speed_control_temp=3;
                 else
                      Speed_control_temp=2160/angle_difference;    //根据当前误差求出速度
                                  if(Speed_control_temp>=20) Speed_control_temp = 20;
                     if(Speed_control_Val>Speed_control_temp)   //加速
                     {
                                  Speed_control_Val -= 1;
                              if(Speed_control_Val<=Speed_control_temp)
                                  {
                                     Speed_control_Val = Speed_control_temp;       
                                  }
                     }
                       else                                 
                       {
                             if(angle_difference<=120&&Speed_control_Val<=4)         //<10   减速
                                   {
                                          Speed_control_Val += 1;
                                   }       
                       }               
                }
        }       
}

terencechang 发表于 2014-5-4 08:36:17

本帖最后由 terencechang 于 2014-5-4 08:37 编辑

加减速控制 。梯形加减速。
const unsigned char add_speed_val= {0xac,0xcc,0xdb,0xde,0xe2,0xe5,0xe7};//,0xe9};//,0xea};//加速曲线672,417,324,276,244,221,204,190.--us
//一个全步之后换一次速度。回零最佳曲线。

terencechang 发表于 2014-5-4 08:39:41

ZJSXHWL000000 发表于 2014-4-29 17:18
楼上是汽车仪表的专家,我用ATMEL 16的两路PWM驱动都有问题。PWM电流驱动小于10ma.而步进电机为17ma,无法 ...

顺便说说 伟利的步进 电机噪音确实不小。想要噪音小,推荐台达步进电机。内部没有任何齿轮的。噪音基本为零。
抄小日本的技术。据说日系车上大部分用的都是这种电机。
噪音小,寿命厂。

ZJSXHWL000000 发表于 2014-5-4 18:58:43

楼上的,真心感谢您的指导,我的不细分没问题,一细分,就抖的很厉害。
细分时实验的代码。请您指导一下。
//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)


unsignedchar OCRnA_Num_L ,OCRnA_Num_R ;

unsigned char direction_flag = 1;
const unsigned char OCRnA_Val =
{
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;   //左线圈电流
      OCR1AH = 0x00;   
                  
      if(OCRnA_Num_R==0)
      {OCRnA_Num_R = 23;STEPPER_RN_1; }//正负端右接1。
      elseOCRnA_Num_R--;
      if(OCRnA_Num_R <= 12) STEPPER_RN_0;//正负端右接0。
      OCR1BL   =OCRnA_Val;//右线圈电流
                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;
                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;
      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 发表于 2014-5-4 20:31:16

原理图如附件

ZJSXHWL000000 发表于 2014-5-4 20:36:25

您的程序的中间大括号有忘记,         
Speed_control_temp=3;
}
         else
             {

xuer3652 发表于 2014-5-6 10:04:44

请问楼主的驱动表不是最优化驱动吧?

ZJSXHWL000000 发表于 2014-5-10 05:46:13

能不能请楼主讲一下:
梯形加减速。
一个全步之后换一次速度。回零最佳曲线。
是什么意思。

fengyunyu 发表于 2014-5-10 06:49:57

ZJSXHWL000000 发表于 2014-4-27 15:49
我用您的程序做实验,反转可以。正转细分不动。
还有噪声太大了。
还不如不细分。是不是PWM输出需要H桥驱动 ...

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

ZJSXHWL000000 发表于 2014-5-10 11:31:33

是楼主留了一手。

fengyunyu 发表于 2014-5-10 11:40:14

ZJSXHWL000000 发表于 2014-5-10 11:31
是楼主留了一手。

LZ的程序不完整么?真是不完整的话,LZ应该明确说明。

dengchengmi 发表于 2014-5-11 10:53:54

学习学习!

terencechang 发表于 2014-5-12 10:38:03

fengyunyu 发表于 2014-5-10 11:40
LZ的程序不完整么?真是不完整的话,LZ应该明确说明。

绝对是驱动部分完整的。量产过的。以前上班公司资料考不出来,发这个帖子目的,1纪念一下。2.把资料考出来。你懂的!!

ZJSXHWL000000 发表于 2014-5-13 13:35:02

请楼主把加速和台达电机的细分讲一下,搞技术的不要买关子。
说过:还有一个台达步进电机的256细分程序。搞过仪表的人懂的。好像网上基本查不到台达步进电机细分驱动的相关知识。
有需要的人说下。共享之。

terencechang 发表于 2014-5-14 08:29:42

ZJSXHWL000000 发表于 2014-5-13 13:35
请楼主把加速和台达电机的细分讲一下,搞技术的不要买关子。
说过:还有一个台达步进电机的256细分程序。搞 ...

/**********************************************************************************************
名称:
   
       台达步进电机细分驱动:256细分
       
程序思想:

   本电机为2相8拍5度步进电机 ,8个节拍为一个循环。本驱动,将两个节拍分为一个象限切换状态。按照
       
       正弦波的变换方式变换
       
       y
       |
       |
       |---.---.---
       |         |
       |------------------------------------------------------> x   A-相电压波形
       |                |            |
       |               ---.---.---.
       |
       |---.                     ---.---.
       |   |                  |
       |------------------------------------------------------> x   B-相电压波形
       |       |         |
       |      ---.---.---.   
       |
       |
       |
       |    分步驱动时序
       
           P1 0-------   |-------0 P2
                         $   |$
          A               $   |$      B
                               $   |$
                               $   |$
           P3 0-------   |-------0P4    电机接线图
          
             A             B                  细分电流变化
           P1 = 1;      P2 = 1;
           P3 = 0;      P4 = 0;    一拍
                                           A --> PWM 正向变高    B --> PWM 正向变低   
           P1 = 1;      P2 = 0;
           P3 = 0;      P4 = 0;    二拍
          
           P1 = 1;      P2 = 0;
           P3 = 0;      P4 = 1;    三拍
                                           A --> PWM 正向变低    B --> PWM 反向变高
           P1 = 0;      P2 = 0;
           P3 = 0;      P4 = 1;    四拍
          
           P1 = 0;      P2 = 0;
           P3 = 1;      P4 = 1;    五拍
                                           A --> PWM 反向变高   B --> PWM 反向变低
           P1 = 0;      P2 = 0;
           P3 = 1;      P4 = 0;    六拍
          
           P1 = 0;      P2 = 1;
           P3 = 1;      P4 = 0;    七拍
                                           A --> PWM反向变低B --> PWM 正向变高
           P1 = 0;      P2 = 1;
           P3 = 0;      P4 = 0;    八拍
          
***********************************************************************************************/
void step_moto_control(void)
{
    switch(moto_state)
        {
          case 0://第一象限矢量方向+x +y
                {
                       coliL_A_Clr();
                       coliL_B_On();
                       coliR_A_On();
                       coliR_B_Clr();
                       OCR0B=mirco_table-1;   // 0 --->1
                       OCR0A=mirco_table-1;//1---->0
                     break;
                }
                case 1://第二象限矢量方向-x +y
                {
                       coliL_B_Clr();
                       coliL_A_On();
                       coliR_B_Clr();
                       coliR_A_On();
                       OCR0A=mirco_table-1;   
                       OCR0B=mirco_table-1;   
                     break;
                }
                case 2://第三象限矢量方向-x -y
                {
                       coliL_B_Clr();
                       coliL_A_On();
                       coliR_A_Clr();
                       coliR_B_On();
                       OCR0B=mirco_table-1;
                       OCR0A=mirco_table-1;                  
                     break;
                }
                case 3://第四象限矢量方向+x -y
                {   
                 coliR_A_Clr();            
                     coliR_B_On();
                       coliL_A_Clr();
                       coliL_B_On();        
                       OCR0A=mirco_table-1;
                       OCR0B=mirco_table-1;      
                     break;
                }
                default : break;
        }
}

terencechang 发表于 2014-5-14 08:32:47

以上驱动,我在全网都搜索过,这个绝对是首发,因为台达步进电机在国内仪表上应用非常非常少。对比VID方式的步进电机。这个电机太多优势啦
1.噪音只有VID方式的步进电机几十分之一。
2.寿命长。由于不存在齿轮结构,所以理论寿命是VID方式的N倍
3.价格便宜。
4.响应速度快。

terencechang 发表于 2014-5-14 08:36:13

个人认为分享程序只丢一堆代码,不是真正的分享。只有把程序思想跟设计过程写得清清楚楚 才是真正意义上的分享。

ZJSXHWL000000 发表于 2014-5-14 10:42:19

请楼主好人做到底,再讲一下加减速控制思路。

ZJSXHWL000000 发表于 2014-5-14 12:55:13

步进电机速度控制函数中换方向如何办。

yanglei920509 发表于 2014-5-14 13:10:58

mark。。。。。。。。。。。。。。。

xz199264 发表于 2014-6-6 00:09:43

terencechang 发表于 2014-5-14 08:29
/**********************************************************************************************
名 ...

请问楼主:      coliL_A_Clr();
                        coliL_B_On();
                        coliR_A_On();
                        coliR_B_Clr();
这几个函数具体是什么意思,象位设定么?不怎么明白,可否解释一下?

ZJSXHWL000000 发表于 2014-6-8 18:41:07

一端用PWM驱动,一端左边线圈置位,右边线圈清0。
我的程序实验会失步。

ZJSXHWL000000 发表于 2014-6-10 09:06:27

请问楼主:PWM采用快速,相位修正,还是相频修正。

xz199264 发表于 2014-6-21 12:44:10


最近在捣鼓42步进电机细分的时候遇到一个问题难以理解,请大侠帮忙答疑解惑。
步进电机在取细分表的时候,是应该取π/2的弧度还是π的弧度?在网上看到大家都是取π弧度的,对此十分的疑惑。比如8细分的正余弦细分表如下:
u16sin_8_X_buf[]=   //8 PWM正弦细分表
{                  
   0,1534,2896,3770,
   4096,3797,2896,1600,
};         
u16cos_8_X_buf[]=             //8 PWM余弦细分表
{                     
   4096,3797,2896,1600,   
0,1534,2896,3770,
};

从图片中可以看出,每相的电流变化都是按正相增大,正相减小,反向增大,反向减小的方式去变化。
如果按π弧度取细分表的话,那不是每走π/2弧度就得换相么?在下一相的时候再重新读取细分表,这样就相当于4细分。8细分是如何得到的呢?

jiafulu 发表于 2014-8-18 10:19:49

好东西,正需要。

end2000 发表于 2014-10-12 23:45:24

步进电机。代码

pango 发表于 2015-9-24 15:59:58

楼主,请问用表计算得到的PWM值控制相电流,如果达不到要比较的DA输出的值的话,或者高于DA输出的值的话,怎么处理?是斩波电流自动处理吗?还是需要调整PWM的数值?

ck213168 发表于 2019-3-1 16:27:32

正在研究步进电机,学习了
页: [1]
查看完整版本: 分享:步进电机细分驱动思路及程序