stepper.c

本文档详细介绍了使用C语言实现的步进电机插补算法,包括分段管理、速度控制和中断处理。代码中定义了常量、结构体和函数,用于计算步进电机的脉冲、速度和方向,以及在中断服务程序中的实际步进信号输出。此外,文档还涵盖了加速、巡航和减速阶段的处理,以及适应性多轴步进平滑功能。
摘要由CSDN通过智能技术生成

#define DT_SEGMENT (1.0/(ACCELERATION_TICKS_PER_SECOND*60.0)) // min/segment 一个分段是多长时间(分钟)

#define REQ_MM_INCREMENT_SCALAR 1.25 //如果小于1.25倍的脉冲当量,不发出脉冲

#define RAMP_ACCEL 0  //加速阶段

#define RAMP_CRUISE 1 //巡航阶段

#define RAMP_DECEL 2 //减速阶段

#define RAMP_DECEL_OVERRIDE 3

#define PREP_FLAG_RECALCULATE bit(0)  //优化计算

#define PREP_FLAG_HOLD_PARTIAL_BLOCK bit(1) 

#define PREP_FLAG_PARKING bit(2)  //

#define PREP_FLAG_DECEL_OVERRIDE bit(3) //

#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING

  #define MAX_AMASS_LEVEL 3

  #define AMASS_LEVEL1 (F_CPU/8000)

  #define AMASS_LEVEL2 (F_CPU/4000)

  #define AMASS_LEVEL3 (F_CPU/2000)

  #if MAX_AMASS_LEVEL <= 0

    error "AMASS must have 1 or more levels to operate correctly."

  #endif

#endif

 //本结构保存块数据,一个段数据是块数据的分解。在段数据插补时需要其所在块的信息

typedef struct {

  uint32_t steps[N_AXIS];

  uint32_t step_event_count;

  uint8_t direction_bits;

  #ifdef ENABLE_DUAL_AXIS

    uint8_t direction_bits_dual;

  #endif

  #ifdef VARIABLE_SPINDLE

    uint8_t is_pwm_rate_adjusted; // Tracks motions that require constant laser power/rate

  #endif

} st_block_t;

static st_block_t st_block_buffer[SEGMENT_BUFFER_SIZE-1];

// 段数据结构

typedef struct {

  uint16_t n_step;           // 本段的脉冲数

  uint16_t cycles_per_tick;  // 本段的中断周期

  uint8_t  st_block_index;   // 本段所在块的索引.

  #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING

    uint8_t amass_level;    // Indicates AMASS level for the ISR to execute this segment

  #else

    uint8_t prescaler;      // Without AMASS, a prescaler is required to adjust for slow timing.

  #endif

  #ifdef VARIABLE_SPINDLE

    uint8_t spindle_pwm;

  #endif

} segment_t;

static segment_t segment_buffer[SEGMENT_BUFFER_SIZE];

// 本结构用于在中断函数中,将段数据和块数据联系起来

typedef struct {

  // Used by the bresenham line algorithm

  uint32_t counter_x,        // 各轴发送脉冲的计数器

           counter_y,

           counter_z;

  #ifdef STEP_PULSE_DELAY

    uint8_t step_bits;  //

  #endif

  uint8_t execute_step;     // 没有使用

  uint8_t step_pulse_time;  // 方向设置后延迟多少时间发送步进信号

  uint8_t step_outbits;         // 保存各轴步进端口的状态,以备下个中断发送出去

  uint8_t dir_outbits;

  #ifdef ENABLE_DUAL_AXIS

    uint8_t step_outbits_dual;

    uint8_t dir_outbits_dual;

  #endif

  #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING

    uint32_t steps[N_AXIS];

  #endif

  uint16_t step_count;       // 本段的脉冲数

  uint8_t exec_block_index; // 指向块数据索引.

  st_block_t *exec_block;   //指向块数据

  segment_t *exec_segment;  // 指向段数据

} stepper_t;

static stepper_t st;

static volatile uint8_t segment_buffer_tail; //段缓存器的尾部索引

static uint8_t segment_buffer_head; //段缓存器的首部索引

static uint8_t segment_next_head; //段缓存器的首部的下一个索引

static uint8_t step_port_invert_mask;

static uint8_t dir_port_invert_mask;

#ifdef ENABLE_DUAL_AXIS

  static uint8_t step_port_invert_mask_dual;

  static uint8_t dir_port_invert_mask_dual;

#endif

static plan_block_t *pl_block;     // 指向规划缓存区的尾部块

static st_block_t *st_prep_block;  // 指向段多对应的块数据

// 本结构用于计算段数据.

typedef struct {

  uint8_t st_block_index;  // Index of stepper common data block being prepped

  uint8_t recalculate_flag;

  float dt_remainder;

  float steps_remaining;

  float step_per_mm;

  float req_mm_increment;

  #ifdef PARKING_ENABLE

    uint8_t last_st_block_index;

    float last_steps_remaining;

    float last_step_per_mm;

    float last_dt_remainder;

  #endif

  uint8_t ramp_type;      // Current segment ramp state

  float mm_complete;      // End of velocity profile from end of current planner block in (mm).

  float current_speed;    // Current speed at the end of the segment buffer (mm/min)

  float maximum_speed;    // Maximum speed of executing block. Not always nominal speed. (mm/min)

  float exit_speed;       // Exit speed of executing block (mm/min)

  float accelerate_until; // Acceleration ramp end measured from end of block (mm)

  float decelerate_after; // Deceleration ramp start measured from end of block (mm)

  #ifdef VARIABLE_SPINDLE

    float inv_rate;    // Used by PWM laser mode to speed up segment calculations.

    uint8_t current_spindle_pwm;

  #endif

} st_prep_t;

static st_prep_t prep;

// 开定时器

void st_wake_up()

{

  // 驱动器使能.

  if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT); }

  else { STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT); }

  // 初始化步进输出位,以确保第一个ISR调用不会步进.

  st.step_outbits = step_port_invert_mask;

  //从设置中初始化步骤脉冲计时。在此确保重新写入后的更新.

  #ifdef STEP_PULSE_DELAY

    // 设置方向后的总步进脉冲时间。

    st.step_pulse_time = -(((settings.pulse_microseconds+STEP_PULSE_DELAY-2)*TICKS_PER_MICROSECOND) >> 3);

    //设置方向引脚和步进脉冲之间的延迟

    OCR0A = -(((settings.pulse_microseconds)*TICKS_PER_MICROSECOND) >> 3);

  #else // Normal operation

    //设置步进脉冲时间。使用二进制补码.

    st.step_pulse_time = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3);

  #endif

  // 开定时器

  TIMSK1 |= (1<<OCIE1A);

}

//插补器进入空闲

void st_go_idle()

{

  TIMSK1 &= ~(1<<OCIE1A); // 关闭定时器

  TCCR1B = (TCCR1B & ~((1<<CS12) | (1<<CS11))) | (1<<CS10); // 恢复定时初值.

  busy = false;

  bool pin_state = false; // Keep enabled.

  if (((settings.stepper_idle_lock_time != 0xff) || sys_rt_exec_alarm || sys.state == STATE_SLEEP) && sys.state != STATE_HOMING) {

    // 强制步进停留,将轴锁定在规定的时间内,以确保轴完全停止,而不是在最后一次运动结束时因残留的惯性力而漂移。.

    delay_ms(settings.stepper_idle_lock_time);

    pin_state = true; // 禁用插补器

  }

  if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { pin_state = !pin_state; } // 反置

  if (pin_state) { STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT); }

  else { STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT); }//关闭端口

}

// 插补定时器中断

ISR(TIMER1_COMPA_vect)

{

  if (busy) { return; } // 防止没有处理完,再次进入中断

  //设置方向

  DIRECTION_PORT = (DIRECTION_PORT & ~DIRECTION_MASK) | (st.dir_outbits & DIRECTION_MASK);

  #ifdef ENABLE_DUAL_AXIS

    DIRECTION_PORT_DUAL = (DIRECTION_PORT_DUAL & ~DIRECTION_MASK_DUAL) | (st.dir_outbits_dual & DIRECTION_MASK_DUAL);

  #endif

  // 输出脉冲。中断程序中是先控制脉冲端口输出,再计

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值