#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
// 输出脉冲。中断程序中是先控制脉冲端口输出,再计