以我手上的三角洲3D打印机为例,讨论一下限位开关在marlin中的几个应用场景,
3个导轨上方和挤出机各安装了一个限位开关。
在执行G28指令让电机xyz归零时,三个导轨上的电机带动滑块向上运动,直到碰到限位块后停止;
在自动调平时,会利用挤出机上的限位开关来探测是否接触到打印平面了;
在正常打印最下面的几层时,如果调平没有做的很好的话,可能出现打印头移动过程中会触碰到打印平面。marlin对于这种情况的处理是只要碰到打印平面则立即放弃当前gcode指令,转而执行下一条gcode指令。
现在来看marlin源码,读取限位开关状态的函数是update_endstops(),其中定义了一个宏UPDATE_ENDSTOP(AXIS,MINMAX),这是函数update_endstops()的要点,其它的是各种编译宏为了兼容各种3d打印机而设置的,这里重点分析宏UPDATE_ENDSTOP(AXIS,MINMAX),源码如下
// Check endstops - Called from ISR!
inline void update_endstops() {
#if ENABLED(Z_DUAL_ENDSTOPS)
uint16_t
#else
byte
#endif
current_endstop_bits = 0;
#define _ENDSTOP_PIN(AXIS, MINMAX) AXIS ##_## MINMAX ##_PIN
#define _ENDSTOP_INVERTING(AXIS, MINMAX) AXIS ##_## MINMAX ##_ENDSTOP_INVERTING
#define _AXIS(AXIS) AXIS ##_AXIS
#define _ENDSTOP_HIT(AXIS) SBI(endstop_hit_bits, _ENDSTOP(AXIS, MIN))
#define _ENDSTOP(AXIS, MINMAX) AXIS ##_## MINMAX
// SET_ENDSTOP_BIT: set the current endstop bits for an endstop to its status
#define SET_ENDSTOP_BIT(AXIS, MINMAX) SET_BIT(current_endstop_bits, _ENDSTOP(AXIS, MINMAX), (READ(_ENDSTOP_PIN(AXIS, MINMAX)) != _ENDSTOP_INVERTING(AXIS, MINMAX)))
// COPY_BIT: copy the value of COPY_BIT to BIT in bits
#define COPY_BIT(bits, COPY_BIT, BIT) SET_BIT(bits, BIT, TEST(bits, COPY_BIT))
// TEST_ENDSTOP: test the old and the current status of an endstop
#define TEST_ENDSTOP(ENDSTOP) (TEST(current_endstop_bits, ENDSTOP) && TEST(old_endstop_bits, ENDSTOP))
#if ENABLED(COREXY) || ENABLED(COREXZ)
#define _SET_TRIGSTEPS(AXIS) do { \
float axis_pos = count_position[_AXIS(AXIS)]; \
if (_AXIS(AXIS) == A_AXIS) \
axis_pos = (axis_pos + count_position[CORE_AXIS_2]) / 2; \
else if (_AXIS(AXIS) == CORE_AXIS_2) \
axis_pos = (count_position[A_AXIS] - axis_pos) / 2; \
endstops_trigsteps[_AXIS(AXIS)] = axis_pos; \
} while(0)
#else
#define _SET_TRIGSTEPS(AXIS) endstops_trigsteps[_AXIS(AXIS)] = count_position[_AXIS(AXIS)]
#endif // COREXY || COREXZ
#define UPDATE_ENDSTOP(AXIS,MINMAX) do { \
SET_ENDSTOP_BIT(AXIS, MINMAX); \
if (TEST_ENDSTOP(_ENDSTOP(AXIS, MINMAX)) && current_block->steps[_AXIS(AXIS)] > 0) { \
_SET_TRIGSTEPS(AXIS); \
_ENDSTOP_HIT(AXIS); \
step_events_completed = current_block->step_event_count; \
} \
} while(0)
步进电机定时中断中调用update_endstops()的代码如下
if (current_block != NULL) {
// Update endstops state, if enabled
#if ENABLED(HAS_Z_MIN_PROBE)
if (check_endstops || z_probe_is_active) update_endstops();
#else
if (check_endstops) update_endstops();
#endif
好了,理解了这些,分析指令G28应该不成问题。