Arduino + нестандартный драйвер шагового двигателя

sirik
Offline
Зарегистрирован: 10.11.2012

Всем доброго дня

В наличие имеется пару собранных драйверов (вот линк на спецификацию: http://www.silniki.pl/download/smc62_instr.pdf, правда на польском языке).

Суть в чем: надо управлять шаговым двигателем через Arduino с помощью это драйвера. Упраляеться как я понял так:

- чтобы включить (дать питание) двигатель: посадить на землю выход "EN" (в инструкции он почему-то LUZ);

- чтобы повернуть на определенный угол: посадить на землю выход "CLK", причем не просто посадить, а коротко временно посадить. Использую analogWrite...

Вот тут и вопрос: допустим я использую полный шаг и включаю двигатель на полную (analogWrite (pin, 1000)) и надо повернуть двигатель на 30град. Откуда мне знать когда надо его выключать?

На ум приходит только самому рассчитать при какой паузе на сколько он поворачивается, но это имхо бред. Так как, даже если это и получится, то в самой программе надо будет делать паузы в виде delay, а это недопустимо, так как программа не должна останавливаться.

Как быть в таком случае, ибо походих библиотек я не видел. Может у кого-то есть какие-либо идеи?

Спасибо

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Это обычный STEP-DIR.....(KIER это DIR )

Скорее всего контроллер подобный  TB6560 .... ищите

https://www.cnc-box.ru/forum/viewtopic.php?f=41&p=116090

Это не  просто мотор. С шаговиками так не работают.

Побаловаться- возьмите энкодер, подключите (с привязкой на 5Вольт) STEP-DIR и покрутите.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013
analogWrite (pin, 1000)

офигенно. шим уже 16 битный похоже стал в ардуине))

не может быть больше 255

sirik
Offline
Зарегистрирован: 10.11.2012

Делаю поправку: при записи analogWrite любым значением мотор крутится на максимуме. Наверное прийдется делать конструкцию:



        digitalWrite(led, HIGH);
        delay(100);
        digitalWrite(led, LOW); 
        delay(100);

где 100, некоторая пауза

Но тогда такой вопрос (я просто никогда не ставливался с шаговыми двигателями): это нормально что немного подергивается? Видел видео, где даже при малых скоростях он просто плавно работал

 

ps: тут STEP нет такого выхода, скорей всего он CLK. С ним и играюсь.

Выхода М1 и М2 пока не трогаю, закоротил их на самой плате = т.е. сейчас полный шаг

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

наверно видел самый дешевый китайский в котором редуктор стоит

http://www.youtube.com/watch?v=etx24iFMilg   первое что попалось

а вообще он шаговый. и по определению не может крутится плавно. он дергается. просто это можно не увидеть

trembo уже написал, и скорее всего так и есть. просто dir управляет направлением. step делает шаг. там вроде джамперы есть чтобы установить микрошаг например 1/2 1/8. один раз подали на step двигатель повернулся на 1 шаг

у двигателя есть характеристика либо сколько градусов на шаг, либо сколько шагов на оборот. высчитываешь сколько нужно шагов сделать чтобы повернутся на 30градусов и подаешь это количество импульсов на step

какие пины dir step у поляков хз

а вообще нафига нужно было покупать поляцкое гавно. лучше уж китайское, там хоть надписи на английском и понятно сразу как с ним работать

sirik
Offline
Зарегистрирован: 10.11.2012

Спасибо. Но есть еще вопрос: с какой частотой подавать импульсы на STEP?

И так понял, что подергивание на малых оборотах это нормально?

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

конечно нормально. ведь шаговый двигатель двигается по шагам. если сделать микрошаг то макс. скорость упадет но будет более плавное вращение

импульсы подавать с частотой не выше чем та на которую поддерживает двигатель. можно превысить конечно немного но мощность от этого сильно падает, если еще быстрее подать двигатель будет просто пищать но крутится не будет

sirik
Offline
Зарегистрирован: 10.11.2012

Сделал такую вот процедурку:

    for (int i = 0; i < 200; i++){
        digitalWrite(motor_LCK, HIGH);
        delay(1);
        digitalWrite(motor_LCK, LOW); 
        delay(1);
    }

где, 1 - пауза для максимальных оборотах

200 - количество импульсов на полный оборот

Прикол в том, что я опытным путем нашел это число, только потом прочитал даташит)

Вроде бы разобрался, спасибо!

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

)) пожалуйста

sirik
Offline
Зарегистрирован: 10.11.2012

Еще один вопрос: как бысть с паузами?

Хотелось бы не тормозить программу ибо мне надо управлять не один, а несколькими двигателями.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

я твоя не понимать) какие паузы?

sirik
Offline
Зарегистрирован: 10.11.2012

Вот пример: мне надо повернуть двигатель на 90 градусов при скорости 30%. Я вызываю процедуру поворота и примерно поворот займет 5 секунд. При это вся программа останавливается и выполняется только поворот (процедура поворота)

 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

какой ужас. вот если бы программа могла по прерываниям сама крутить двигатель не останавливая основную

есть такая библиотека TimerOne, кажется так называется. в ней много чего можно сделать

leshak
Offline
Зарегистрирован: 29.09.2011

sirik пишет:

Еще один вопрос: как бысть с паузами?

Мигаем светодиодом без delay()

sirik
Offline
Зарегистрирован: 10.11.2012

Видимо без минимальной паузы (в теле самой процедуру, т.е. вкл/выкл импульс) не обойтись.

Буду пробовать.  Спасибо

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

jeka_tm пишет:

.....импульсы подавать с частотой не выше чем та на которую поддерживает двигатель.....

А если шаговик имеет приличную нагрузку на валу то может и не стронутся с места без плавного разгона...

http://www.airspayce.com/mikem/arduino/AccelStepper/

  • Supports acceleration and deceleration
  • Supports multiple simultaneous steppers, with independent concurrent stepping on each stepper
jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

не надо было говорить. узнали бы что тс там двигает

может от пулементную точку собирает и поставляет на украину

sirik
Offline
Зарегистрирован: 10.11.2012

Шаговик довольно мощный да и нагрузка плевая)

Я живу в Украине ;)

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

))) а зачем мощный шаговик ставить на плевую нагрузку? чтобы игнорировать инерцию и без задержек поворачивать или перемещать нагрузку

и моторов несколько

да и драйвер у него польский

как то это подозрительно

sirik
Offline
Зарегистрирован: 10.11.2012

Просто это все добро есть в наличае, для теста и знакомста в шаговиками самое то. Мб позже перейду на что-нубудь по проще

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

ракетные установки?)))

шучу. а то подумаете

vvadim
Offline
Зарегистрирован: 23.05.2012

Для знакомства надо взять драйвер, на который куча примеров разжёванных , где всё по полочкам разложено.

art100
Offline
Зарегистрирован: 09.03.2014

vvadim пишет:

Для знакомства надо взять драйвер, на который куча примеров разжёванных , где всё по полочкам разложено.

расслабся 

тут классический DIR STEP

все литературным польским языком для детей разжевано

ТС просто любит садо-мазо

 

 

Вот почему у меня всегда все получается?

Что я делаю не так?

 

sirik
Offline
Зарегистрирован: 10.11.2012

Кстати, у меня все получилось) Прадва пока что с одним шаговиком, будет чуть больше времени, буду пробовать с 3

art100
Offline
Зарегистрирован: 09.03.2014

sirik пишет:

Кстати, у меня все получилось) Прадва пока что с одним шаговиком, будет чуть больше времени, буду пробовать с 3

ну славо богу Clock в Шаги в STEP перевел, а Dir-ектора не трогал по умолчанию, да и Енабле ци не Енабле определился плюсом землей или вооще лучше не енаблировать enabl-тое по умолчанию.

Схемы до сих пор нет. 

Нам хоть расскажи

Как оно?

Продолжаем телепатические сеансы. :)

 

 

sirik
Offline
Зарегистрирован: 10.11.2012

В смысле перевел?) CLK = STEP, DIR = DIR, EN = вкл мотор, с М1 и М2 итак понятно. Причем все управляющие выходы сажу на землю через npn транзистор.

У меня самая большая проблемма была в том, что я не думал (да и сейчас не хочу) что процедура поворота на опеределенный градус будет "тормозить" главную процедуру. А драйвер оказался почти стандартным)

art100
Offline
Зарегистрирован: 09.03.2014

сирик пишет:

В смысле перевел?) CLK = STEP, DIR = DIR, EN = вкл мотор, с М1 и М2 итак понятно. Причем все управляющие выходы сажу на землю через npn транзистор.

У меня самая большая проблемма была в том, что я не думал (да и сейчас не хочу) что процедура поворота на опеределенный градус будет "тормозить" главную процедуру. А драйвер оказался почти стандартным)

а когда классический ЧПУ с 4-мя моторами через прерывания пишется

0236
void st_wake_up() {
0237
// TCNT1 = 0;
0238
ENABLE_STEPPER_DRIVER_INTERRUPT();
0239
}

ну вот с живого станка

/*
stepper.c - драйвер шагового двигателя: выполняет движения планы с помощью шаговых двигателей
Часть Grbl

Copyright (c) 2009-2011 Simen Svale Skogsrud

Grbl является свободным программным обеспечением: вы можете распространять и/или модифицировать
it under the terms of the GNU General Public License, опубликованной
Free Software Foundation, либо версии 3 лицензии, или
(по вашему выбору) любой более поздней версии.

Grbl распространяется в надежде что она будет полезной,
но без всякой гарантии; даже без подразумеваемой гарантии
Пригодности для продажи или пригодности для конкретной цели.  См.
GNU General Public License для более подробной информации.

Вы должны были получить копию GNU General Public License
вместе с Grbl. Если нет, см. <http://www.gnu.org/licenses/>.
*/

/* Таймер расчетах данного модуля сообщил " RepRap декартовых прошивки " Зак Смит
и Филипп Tiefenbacher. */

#include "Marlin.h"
#include "stepper.h"
#include "planner.h"
#include "temperature.h"
#include "ultralcd.h"
#include "language.h"
#include "cardreader.h"
#include "speed_lookuptable.h"
#if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
#include <SPI.h>
#endif


//===========================================================================
//=============================общие переменные============================
//===========================================================================
block_t *current_block; // указатель на блок, в настоящее время прослеживается


//===========================================================================
//=============================private переменные============================
//===========================================================================
//статические делает его немыслима называться из-за пределов этого файла extern.!

// Переменные, используемые шаговый драйвер прерываний
static unsigned char out_bits; // следующий степпинг-бит выход
статические долго counter_x, // переменных-счетчиков для bresenham line tracer
counter_y,
counter_z,
counter_e;
volatile static unsigned long step_events_completed; // номер шага мероприятий, выполненных в текущем блоке
#ifdef заранее
static long advance_rate, заранее, final_advance = 0;
static long old_advance = 0;
static long e_steps[3];
#endif
static long acceleration_time, deceleration_time;
//static unsigned long accelerate_until, decelerate_after, acceleration_rate, initial_rate, final_rate, nominal_rate;
static unsigned short acc_step_rate; // необходимые для deccelaration начальную точку
static char step_loops;
static unsigned short OCR1A_nominal;
static unsigned short step_loops_nominal;

volatile long endstops_trigsteps[3]={0,0,0};
volatile long endstops_stepsTotal,endstops_stepsDone;
static volatile bool endstop_x_hit=false;
static volatile bool endstop_y_hit=false;
static volatile bool endstop_z_hit=false;
#ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED
bool abort_on_endstop_hit = false;
#endif
#ifdef MOTOR_CURRENT_PWM_XY_PIN
int motor_current_setting[3] = DEFAULT_PWM_MOTOR_CURRENT;
#endif

static bool old_x_min_endstop=false;
static boolold_x_max_endstop=false;
static bool old_y_min_endstop=false;
static bool old_y_max_endstop=false;
static bool old_z_min_endstop=false;
static bool old_z_max_endstop=false;

static bool check_endstops = true;

volatile long count_position[NUM_AXIS] = { 0, 0, 0, 0};
volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1};

//===========================================================================
//=============================функции============================
//===========================================================================

#define CHECK_ENDSTOPS if(check_endstops)

// intRes = intIn1 * intIn2 >> 16
// использует:
// r26 для хранения 0
// r27 для хранения байт 1 из 24-битный результат
#define MultiU16X8toH16(intRes, charIn1, intIn2) \
asm volatile ( \
"clr r26 \n\t" \
"mul %A1 %B2 \n\t" \
"movw %A0, r0 \n\t" \
"mul %A1 %A2 \n\t" \
"добавить %A0, r1 \n\t" \
"adc %B0, r26 \n\t" \
"lsr r0 \n\t" \
"adc %A0, r26 \n\t" \
"adc %B0, r26 \n\t" \
"clr r1 \n\t" \
: \
"=&r" (intRes) \
: \
"d" (charIn1), \
"d" (intIn2) \
: \
"r26" \
)

// intRes = longIn1 * longIn2 >> 24
// использует:
// r26 для хранения 0
// r27 для хранения байт 1 из 48 бит на результат
#define MultiU24X24toH16(intRes, longIn1, longIn2) \
asm volatile ( \
"clr r26 \n\t" \
"mul %A1 %B2 \n\t" \
"mov r27, r1 \n\t" \
"mul %B1 %C2 \n\t" \
"movw %A0, r0 \n\t" \
"mul %C1 %C2 \n\t" \
"добавить %B0, r0 \n\t" \
"mul %C1 %B2 \n\t" \
"добавить %A0, r0 \n\t" \
"adc %B0 r1 \n\t" \
"mul %A1 %C2 \n\t" \
"добавить r27, r0 \n\t" \
"adc %A0, r1 \n\t" \
"adc %B0, r26 \n\t" \
"mul %B1 %B2 \n\t" \
"добавить r27, r0 \n\t" \
"adc %A0, r1 \n\t" \
"adc %B0, r26 \n\t" \
"mul %C1 %A2 \n\t" \
"добавить r27, r0 \n\t" \
"adc %A0, r1 \n\t" \
"adc %B0, r26 \n\t" \
"mul %B1 %A2 \n\t" \
"добавить r27, r1 \n\t" \
"adc %A0, r26 \n\t" \
"adc %B0, r26 \n\t" \
"ЛСР r27 \n\t" \
"adc %A0, r26 \n\t" \
"adc %B0, r26 \n\t" \
"clr r1 \n\t" \
: \
"=&r" (intRes) \
: \
"d" (longIn1), \
"d" (longIn2) \
: \
"r26" , "r27" \
)

// Некоторые полезные константы

#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1<<OCIE1A)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 &= ~(1<<OCIE1A)


void checkHitEndstops()
{
если( endstop_x_hit || endstop_y_hit || endstop_z_hit) {
SERIAL_ECHO_START;
SERIAL_ECHOPGM(MSG_ENDSTOPS_HIT);
если(endstop_x_hit) {
SERIAL_ECHOPAIR(" X:",(float)endstops_trigsteps[X_AXIS]/axis_steps_per_unit[X_AXIS]);
LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "X");
}
если(endstop_y_hit) {
SERIAL_ECHOPAIR(" Y:",(float)endstops_trigsteps[Y_AXIS]/axis_steps_per_unit[Y_AXIS]);
LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "Y");
}
если(endstop_z_hit) {
SERIAL_ECHOPAIR(" Z:",(float)endstops_trigsteps[Z_AXIS]/axis_steps_per_unit[Z_AXIS]);
LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "Z");
}
SERIAL_ECHOLN("");
endstop_x_hit=false;
endstop_y_hit=false;
endstop_z_hit=false;
#ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED
если (abort_on_endstop_hit)
{
card.sdprinting = false;
card.closefile();
quickStop();
setTargetHotend0(0);
setTargetHotend1(0);
setTargetHotend2(0);
}
#endif
}
}

void endstops_hit_on_purpose()
{
endstop_x_hit=false;
endstop_y_hit=false;
endstop_z_hit=false;
}

void enable_endstops(bool check)
{
check_endstops = check;
}

// __________________________
// /| |\ _________________ ^
// / | | \ /| |\ |
// / | | \ / | | \ s
// / | | | | | \ p
// / | | | | | \ e
// +-----+------------------------+---+--+---------------+----+ e
// | Блок 1 | блок 2 | d
//
// время ----->
//
// Трапециевидной формы на кривой скорости с течением времени. Она начинается на уровне блок->initial_rate, ускоряет
// первый блок->accelerate_until step_events_completed, затем продолжает двигаться с постоянной скоростью, до тех пор, пока
// step_events_completed достигает block->decelerate_after после чего он тормозит до трапециевидной генератора сброса.
// Склона ускорения рассчитывается с лейб рампы alghorithm.

void st_wake_up() {
// TCNT1 = 0;
ENABLE_STEPPER_DRIVER_INTERRUPT();
}

void step_wait(){
для(int8_t i=0; i < 6; i++){
}
}


FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) {
unsigned short timer;
если(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY;

если(step_rate > 20000) { // если steprate > 20кГц >> Шаг 4 раза
step_rate = (step_rate >> 2)&0x3fff;
step_loops = 4;
}
else if(step_rate > 10000) { // если steprate > 10кгц >> Шаг 2 раз
step_rate = (step_rate >> 1)&0x7fff;
step_loops = 2;
}
else {
step_loops = 1;
}

если(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000);
step_rate -= (F_CPU/500000); // правильно минимальная скорость
если(step_rate>= (8*256)){ // выше частота шагов
unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0];
unsigned char tmp_step_rate = (step_rate & 0x00ff);
unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2);
MultiU16X8toH16(Таймер, tmp_step_rate, прибыль);
timer = (unsigned short)pgm_read_word_near(table_address) - Таймер;
}
else { // шаг ниже цены
unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0];
table_address += ((step_rate)>>1) & 0xfffc;
timer = (unsigned short)pgm_read_word_near(table_address);
Таймер -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3);
}
if(timer < 100) { timer = 100; MYSERIAL.print(MSG_STEPPER_TOO_HIGH); MYSERIAL.println(step_rate); }//(20кГц это никогда не должно произойти)
возврат таймера;
}

// Инициализирует генератор, трапеция, из текущего блока. Вызывается всякий раз, когда новый
// блок начинается.
FORCE_INLINE void trapezoid_generator_reset() {
#ifdef заранее
advance = current_block->initial_advance;
final_advance = current_block->final_advance;
// У E действия + действия заранее
e_steps[current_block->active_extruder] += ((заранее >>8) - old_advance);
old_advance = Advanced (дополнительно) >>8;
#endif
deceleration_time = 0;
// step_rate для таймера интервал
OCR1A_nominal = calc_timer(current_block->nominal_rate);
// запишите число шаг петель, необходимые при номинальной скорости
step_loops_nominal = step_loops;
acc_step_rate = current_block->initial_rate;
acceleration_time = calc_timer(acc_step_rate);
OCR1A = acceleration_time;

// SERIAL_ECHO_START;
// SERIAL_ECHOPGM("заранее");
// SERIAL_ECHO(current_block->advance/256.0);
// SERIAL_ECHOPGM("advance курсу :");
// SERIAL_ECHO(current_block->advance_rate/256.0);
// SERIAL_ECHOPGM("первоначального аванса :");
// SERIAL_ECHO(current_block->initial_advance/256.0);
// SERIAL_ECHOPGM("финал заранее :");
// SERIAL_ECHOLN(current_block->final_advance/256.0);

}

// "Шаговый драйвер Interrupt" - это прерывания таймера рабочая лошадка.
// Соз кварталах от block_buffer и выполняет их с помощью генерирования импульсов шагового контакты надлежащим образом.
ISR(TIMER1_COMPA_vect)
{
// Если нет текущего блока, попытка поп-один из буфера
если (current_block == NULL) {
// Что-нибудь в буфер?
current_block = plan_get_current_block();
если (current_block != NULL) {
current_block->busy = true;
trapezoid_generator_reset();
counter_x = -(current_block->step_event_count >> 1);
counter_y = counter_x;
counter_z = counter_x;
counter_e = counter_x;
step_events_completed = 0;

#ifdef Z_LATE_ENABLE
если(current_block->steps_z > 0) {
enable_z();
OCR1A = 2000; //1ms ждать
return;
}
#endif

// #ifdef заранее
// e_steps[current_block->active_extruder] = 0;
// #endif
}
else {
OCR1A=2000; // 1кгц.
}
}

если (current_block != NULL) {
// Установить направления для этого нужно сделать один раз во время инициализации трапеции. Концевики -> прерывание
out_bits = current_block->direction_bits;


// Установить биты направления X_AXIS=A_AXIS и Y_AXIS=B_AXIS для COREXY)
if((out_bits & (1<<X_AXIS))!=0){
#ifdef DUAL_X_CARRIAGE
если (extruder_duplication_enabled){
WRITE(X_DIR_PIN, INVERT_X_DIR);
WRITE(X2_DIR_PIN, INVERT_X_DIR);
}
else{
если (current_block->active_extruder != 0)
WRITE(X2_DIR_PIN, INVERT_X_DIR);
еще
WRITE(X_DIR_PIN, INVERT_X_DIR);
}
#else
WRITE(X_DIR_PIN, INVERT_X_DIR);
#endif 
count_direction[X_AXIS]=-1;
}
else{
#ifdef DUAL_X_CARRIAGE
если (extruder_duplication_enabled){
WRITE(X_DIR_PIN, !INVERT_X_DIR);
WRITE(X2_DIR_PIN, !INVERT_X_DIR);
}
else{
если (current_block->active_extruder != 0)
WRITE(X2_DIR_PIN, !INVERT_X_DIR);
еще
WRITE(X_DIR_PIN, !INVERT_X_DIR);
}
#else
WRITE(X_DIR_PIN, !INVERT_X_DIR);
#endif 
count_direction[X_AXIS]=1;
}
if((out_bits & (1<<Y_AXIS))!=0){
WRITE(Y_DIR_PIN, INVERT_Y_DIR);

#ifdef Y_DUAL_STEPPER_DRIVERS
WRITE(Y2_DIR_PIN, !(INVERT_Y_DIR == INVERT_Y2_VS_Y_DIR));
#endif

count_direction[Y_AXIS]=-1;
}
else{
WRITE(Y_DIR_PIN, !INVERT_Y_DIR);

#ifdef Y_DUAL_STEPPER_DRIVERS
WRITE(Y2_DIR_PIN, (INVERT_Y_DIR == INVERT_Y2_VS_Y_DIR));
#endif

count_direction[Y_AXIS]=1;
}

// Устанавливаем направление ru проверить концевые выключатели
#ifndef COREXY
if ((out_bits & (1<<X_AXIS)) != 0) { // шаг вдоль оси X
#else
если((((out_bits & (1<<X_AXIS)) != 0)&&(out_bits & (1<<Y_AXIS)) != 0)) { //-событие X происходит-A и-B
#endif
CHECK_ENDSTOPS
{
#ifdef DUAL_X_CARRIAGE
// с 2 x-коляски, концевики проверяются только в самонаведения направлением активного экструдера
if ((current_block->active_extruder == 0 && X_HOME_DIR == -1) 
|| (current_block->active_extruder != 0 && X2_HOME_DIR == -1))
#endif 
{
#if defined(X_MIN_PIN) && X_MIN_PIN > -1
bool x_min_endstop=(READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING);
если(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) {
endstops_trigsteps[X_AXIS] = count_position[X_AXIS];
endstop_x_hit=true;
step_events_completed = current_block->step_event_count;
}
old_x_min_endstop = x_min_endstop;
#endif
}
}
}
else { // +направление
CHECK_ENDSTOPS
{
#ifdef DUAL_X_CARRIAGE
// с 2 x-коляски, концевики проверяются только в самонаведения направлением активного экструдера
if ((current_block->active_extruder == 0 && X_HOME_DIR == 1) 
|| (current_block->active_extruder != 0 && X2_HOME_DIR == 1))
#endif 
{
#if defined(X_MAX_PIN) && X_MAX_PIN > -1
bool x_max_endstop=(READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING);
если(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){
endstops_trigsteps[X_AXIS] = count_position[X_AXIS];
endstop_x_hit=true;
step_events_completed = current_block->step_event_count;
}
old_x_max_endstop = x_max_endstop;
#endif
}
}
}

#ifndef COREXY
if ((out_bits & (1<<Y_AXIS)) != 0) { // -направление
#else
если((((out_bits & (1<<X_AXIS)) != 0)&&(out_bits & (1<<Y_AXIS)) == 0)) { // -Y происходит по-и +B
#endif
CHECK_ENDSTOPS
{
#if defined(Y_MIN_PIN) && Y_MIN_PIN > -1
bool y_min_endstop=(READ(Y_MIN_PIN) != Y_MIN_ENDSTOP_INVERTING);
если(y_min_endstop && old_y_min_endstop && (current_block->steps_y > 0)) {
endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS];
endstop_y_hit=true;
step_events_completed = current_block->step_event_count;
}
old_y_min_endstop = y_min_endstop;
#endif
}
}
else { // +направление
CHECK_ENDSTOPS
{
#if defined(Y_MAX_PIN) && Y_MAX_PIN > -1
bool y_max_endstop=(READ(Y_MAX_PIN) != Y_MAX_ENDSTOP_INVERTING);
если(y_max_endstop && old_y_max_endstop && (current_block->steps_y > 0)){
endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS];
endstop_y_hit=true;
step_events_completed = current_block->step_event_count;
}
old_y_max_endstop = y_max_endstop;
#endif
}
}

if ((out_bits & (1<<Z_AXIS)) != 0) { // -направление
WRITE(Z_DIR_PIN,INVERT_Z_DIR);

#ifdef Z_DUAL_STEPPER_DRIVERS
WRITE(Z2_DIR_PIN,INVERT_Z_DIR);
#endif

count_direction[Z_AXIS]=-1;
CHECK_ENDSTOPS
{
#if defined(Z_MIN_PIN) && Z_MIN_PIN > -1
bool z_min_endstop=(READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING);
если(z_min_endstop && old_z_min_endstop && (current_block->steps_z > 0)) {
endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS];
endstop_z_hit=true;
step_events_completed = current_block->step_event_count;
}
old_z_min_endstop = z_min_endstop;
#endif
}
}
else { // +направление
WRITE(Z_DIR_PIN,!INVERT_Z_DIR);

#ifdef Z_DUAL_STEPPER_DRIVERS
WRITE(Z2_DIR_PIN,!INVERT_Z_DIR);
#endif

count_direction[Z_AXIS]=1;
CHECK_ENDSTOPS
{
#if defined(Z_MAX_PIN) && Z_MAX_PIN > -1
bool z_max_endstop=(READ(Z_MAX_PIN) != Z_MAX_ENDSTOP_INVERTING);
если(z_max_endstop && old_z_max_endstop && (current_block->steps_z > 0)) {
endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS];
endstop_z_hit=true;
step_events_completed = current_block->step_event_count;
}
old_z_max_endstop = z_max_endstop;
#endif
}
}

#ifndef заранее
if ((out_bits & (1<<E_AXIS)) != 0) { // -направление
REV_E_DIR();
count_direction[E_AXIS]=-1;
}
else { // +направление
NORM_E_DIR();
count_direction[E_AXIS]=1;
}
#endif //!Заранее



для(int8_t i=0; i < step_loops; i++) { // сделать несколько шагов в прерывание (для высокой скорости движется)
#ifndef AT90USB
MSerial.checkRx(); // проверить серийный chars.
#endif

#ifdef заранее
counter_e += current_block->steps_e;
если (counter_e > 0) {
counter_e -= current_block->step_event_count;
if ((out_bits & (1<<E_AXIS)) != 0) { // - направление
e_steps[current_block->active_extruder]--;
}
else {
e_steps[current_block->active_extruder]++;
}
}
#endif //ADVANCE

counter_x += current_block->steps_x;
если (counter_x > 0) {
#ifdef DUAL_X_CARRIAGE
если (extruder_duplication_enabled){
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN);
}
else {
если (current_block->active_extruder != 0)
WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN);
еще
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
}
#else
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
#endif 
counter_x -= current_block->step_event_count;
count_position[X_AXIS]+=count_direction[X_AXIS]; 
#ifdef DUAL_X_CARRIAGE
если (extruder_duplication_enabled){
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN);
}
else {
если (current_block->active_extruder != 0)
WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN);
еще
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
}
#else
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
#endif
}

counter_y += current_block->steps_y;
если (counter_y > 0) {
WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN);

#ifdef Y_DUAL_STEPPER_DRIVERS
WRITE(Y2_STEP_PIN, !INVERT_Y_STEP_PIN);
#endif

counter_y -= current_block->step_event_count;
count_position[Y_AXIS]+=count_direction[Y_AXIS];
WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN);

#ifdef Y_DUAL_STEPPER_DRIVERS
WRITE(Y2_STEP_PIN, INVERT_Y_STEP_PIN);
#endif
}

counter_z += current_block->steps_z;
если (counter_z > 0) {
WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN);

#ifdef Z_DUAL_STEPPER_DRIVERS
WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN);
#endif

counter_z -= current_block->step_event_count;
count_position[Z_AXIS]+=count_direction[Z_AXIS];
WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN);

#ifdef Z_DUAL_STEPPER_DRIVERS
WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN);
#endif
}

#ifndef заранее
counter_e += current_block->steps_e;
если (counter_e > 0) {
WRITE_E_STEP(!INVERT_E_STEP_PIN);
counter_e -= current_block->step_event_count;
count_position[E_AXIS]+=count_direction[E_AXIS];
WRITE_E_STEP(INVERT_E_STEP_PIN);
}
#endif //!Заранее
step_events_completed += 1;
если(step_events_completed >= current_block->step_event_count) break;
}
// Calculare новое значение таймера
unsigned short timer;
unsigned short step_rate;
если (step_events_completed <= (unsigned long int)current_block->accelerate_until) {

MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate);
acc_step_rate += current_block->initial_rate;

// верхний предел
если(acc_step_rate > current_block->nominal_rate)
acc_step_rate = current_block->nominal_rate;

// step_rate для таймера интервал
timer = calc_timer(acc_step_rate);
OCR1A = timer;
acceleration_time += timer;
#ifdef заранее
для(int8_t i=0; i < step_loops; i++) {
аванс += advance_rate;
}
//если(заранее > current_block->advance) заранее = current_block->advance;
// У E действия + действия заранее
e_steps[current_block->active_extruder] += ((заранее >>8) - old_advance);
old_advance = Advanced (дополнительно) >>8;

#endif
}
else if (step_events_completed > (unsigned long int)current_block->decelerate_after) {
MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate);

если(step_rate > acc_step_rate) { // Check step_rate остается позитивным
step_rate = current_block->final_rate;
}
else {
step_rate = acc_step_rate - step_rate; // замедление от aceleration конечной точки.
}

// нижний предел
если(step_rate < current_block->final_rate)
step_rate = current_block->final_rate;

// step_rate для таймера интервал
timer = calc_timer(step_rate);
OCR1A = timer;
deceleration_time += timer;
#ifdef заранее
для(int8_t i=0; i < step_loops; i++) {
advance -= advance_rate;
}
если(advance < final_advance) заранее = final_advance;
// У E действия + действия заранее
e_steps[current_block->active_extruder] += ((заранее >>8) - old_advance);
old_advance = Advanced (дополнительно) >>8;
#endif //ADVANCE
}
else {
OCR1A = OCR1A_nominal;
// обеспечения мы бежим на правильный шаг ставки, даже если мы просто отрывались ускорение
step_loops = step_loops_nominal;
}

// Если текущий блок закончен, сброс указателя
если (step_events_completed >= current_block->step_event_count) {
current_block = NULL;
plan_discard_current_block();
}
}
}

#ifdef заранее
unsigned char old_OCR0A;
// Прерывания таймера для E. e_steps Задается в основной программе;
// Таймер 0 используется совместно с millies
ISR(TIMER0_COMPA_vect)
{
old_OCR0A += 52; // ~10кгц прерывания (250000 / 26 = 9615kHz)
OCR0A = old_OCR0A;
// Установить е направление (зависит от E направление + аванс)
for(unsigned char i=0; i<4;i++) {
если (e_steps[0] != 0) {
WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN);
если (e_steps[0] < 0) {
WRITE(E0_DIR_PIN, INVERT_E0_DIR);
e_steps[0]++;
WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN);
}
else if (e_steps[0] > 0) {
WRITE(E0_DIR_PIN, !INVERT_E0_DIR);
e_steps[0]--;
WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN);
}
}
#если ЭКСТРУДЕРЫ > 1
если (e_steps[1] != 0) {
WRITE(E1_STEP_PIN, INVERT_E_STEP_PIN);
если (e_steps[1] < 0) {
WRITE(E1_DIR_PIN, INVERT_E1_DIR);
e_steps[1]++;
WRITE(E1_STEP_PIN, !INVERT_E_STEP_PIN);
}
else if (e_steps[1] > 0) {
WRITE(E1_DIR_PIN, !INVERT_E1_DIR);
e_steps[1]--;
WRITE(E1_STEP_PIN, !INVERT_E_STEP_PIN);
}
}
#endif
#если ЭКСТРУДЕРЫ > 2
если (e_steps[2] != 0) {
WRITE(E2_STEP_PIN, INVERT_E_STEP_PIN);
если (e_steps[2] < 0) {
WRITE(E2_DIR_PIN, INVERT_E2_DIR);
e_steps[2]++;
WRITE(E2_STEP_PIN, !INVERT_E_STEP_PIN);
}
else if (e_steps[2] > 0) {
WRITE(E2_DIR_PIN, !INVERT_E2_DIR);
e_steps[2]--;
WRITE(E2_STEP_PIN, !INVERT_E_STEP_PIN);
}
}
#endif
}
}
#endif // ADVANCE

void st_init()
{
digipot_init(); //Инициализируем Digipot тока двигателя
microstep_init(); //Инициализируем Микрошаговый контакты

//Инициализируем Dir-Пен
#if defined(X_DIR_PIN) && X_DIR_PIN > -1
SET_OUTPUT(X_DIR_PIN);
#endif
#if defined(X2_DIR_PIN) && X2_DIR_PIN > -1
SET_OUTPUT(X2_DIR_PIN);
#endif
#if defined(Y_DIR_PIN) && Y_DIR_PIN > -1
SET_OUTPUT(Y_DIR_PIN);

#если определено(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_DIR_PIN) && (Y2_DIR_PIN > -1)
SET_OUTPUT(Y2_DIR_PIN);
#endif
#endif
#if defined(Z_DIR_PIN) && Z_DIR_PIN > -1
SET_OUTPUT(Z_DIR_PIN);

#if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_DIR_PIN) && (Z2_DIR_PIN > -1)
SET_OUTPUT(Z2_DIR_PIN);
#endif
#endif
#if defined(E0_DIR_PIN) && E0_DIR_PIN > -1
SET_OUTPUT(E0_DIR_PIN);
#endif
#if defined(E1_DIR_PIN) && (E1_DIR_PIN > -1)
SET_OUTPUT(E1_DIR_PIN);
#endif
#if defined(E2_DIR_PIN) && (E2_DIR_PIN > -1)
SET_OUTPUT(E2_DIR_PIN);
#endif

//Инициализируем Включить Пен - степперы по умолчанию отключено.

#if defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1
SET_OUTPUT(X_ENABLE_PIN);
if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,ВЫСОКИЙ);
#endif
#if defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1
SET_OUTPUT(X2_ENABLE_PIN);
if(!X_ENABLE_ON) WRITE(X2_ENABLE_PIN,ВЫСОКИЙ);
#endif
#if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1
SET_OUTPUT(Y_ENABLE_PIN);
if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,ВЫСОКИЙ);

#if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_ENABLE_PIN) && (Y2_ENABLE_PIN > -1)
SET_OUTPUT(Y2_ENABLE_PIN);
if(!Y_ENABLE_ON) WRITE(Y2_ENABLE_PIN,Высокий);
#endif
#endif
#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1
SET_OUTPUT(Z_ENABLE_PIN);
if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,ВЫСОКИЙ);

#if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_ENABLE_PIN) && (Z2_ENABLE_PIN > -1)
SET_OUTPUT(Z2_ENABLE_PIN);
if(!Z_ENABLE_ON) WRITE(Z2_ENABLE_PIN,ВЫСОКИЙ);
#endif
#endif
#if defined(E0_ENABLE_PIN) && (E0_ENABLE_PIN > -1)
SET_OUTPUT(E0_ENABLE_PIN);
if(!E_ENABLE_ON) WRITE(E0_ENABLE_PIN,ВЫСОКИЙ);
#endif
#if defined(E1_ENABLE_PIN) && (E1_ENABLE_PIN > -1)
SET_OUTPUT(E1_ENABLE_PIN);
if(!E_ENABLE_ON) WRITE(E1_ENABLE_PIN,ВЫСОКИЙ);
#endif
#if defined(E2_ENABLE_PIN) && (E2_ENABLE_PIN > -1)
SET_OUTPUT(E2_ENABLE_PIN);
if(!E_ENABLE_ON) WRITE(E2_ENABLE_PIN,ВЫСОКИЙ);
#endif

//концевики и подтягивания

#if defined(X_MIN_PIN) && X_MIN_PIN > -1
SET_INPUT(X_MIN_PIN);
#ifdef ENDSTOPPULLUP_XMIN
WRITE(X_MIN_PIN,ВЫСОКИЙ);
#endif
#endif

#if defined(Y_MIN_PIN) && Y_MIN_PIN > -1
SET_INPUT(Y_MIN_PIN);
#ifdef ENDSTOPPULLUP_YMIN
WRITE(Y_MIN_PIN,ВЫСОКИЙ);
#endif
#endif

#if defined(Z_MIN_PIN) && Z_MIN_PIN > -1
SET_INPUT(Z_MIN_PIN);
#ifdef ENDSTOPPULLUP_ZMIN
WRITE(Z_MIN_PIN,ВЫСОКИЙ);
#endif
#endif

#if defined(X_MAX_PIN) && X_MAX_PIN > -1
SET_INPUT(X_MAX_PIN);
#ifdef ENDSTOPPULLUP_XMAX
WRITE(X_MAX_PIN,ВЫСОКИЙ);
#endif
#endif

#if defined(Y_MAX_PIN) && Y_MAX_PIN > -1
SET_INPUT(Y_MAX_PIN);
#ifdef ENDSTOPPULLUP_YMAX
WRITE(Y_MAX_PIN,ВЫСОКИЙ);
#endif
#endif

#if defined(Z_MAX_PIN) && Z_MAX_PIN > -1
SET_INPUT(Z_MAX_PIN);
#ifdef ENDSTOPPULLUP_ZMAX
WRITE(Z_MAX_PIN,ВЫСОКИЙ);
#endif
#endif


//Инициализируем Шаг Штырей
#if defined(X_STEP_PIN) && (X_STEP_PIN > -1)
SET_OUTPUT(X_STEP_PIN);
WRITE(X_STEP_PIN,INVERT_X_STEP_PIN);
disable_x();
#endif
#if defined(X2_STEP_PIN) && (X2_STEP_PIN > -1)
SET_OUTPUT(X2_STEP_PIN);
WRITE(X2_STEP_PIN,INVERT_X_STEP_PIN);
disable_x();
#endif
#if defined(Y_STEP_PIN) && (Y_STEP_PIN > -1)
SET_OUTPUT(Y_STEP_PIN);
WRITE(Y_STEP_PIN,INVERT_Y_STEP_PIN);
#if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_STEP_PIN) && (Y2_STEP_PIN > -1)
SET_OUTPUT(Y2_STEP_PIN);
WRITE(Y2_STEP_PIN,INVERT_Y_STEP_PIN);
#endif
disable_y();
#endif
#if defined(Z_STEP_PIN) && (Z_STEP_PIN > -1)
SET_OUTPUT(Z_STEP_PIN);
WRITE(Z_STEP_PIN,INVERT_Z_STEP_PIN);
#if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_STEP_PIN) && (Z2_STEP_PIN > -1)
SET_OUTPUT(Z2_STEP_PIN);
WRITE(Z2_STEP_PIN,INVERT_Z_STEP_PIN);
#endif
disable_z();
#endif
#if defined(E0_STEP_PIN) && (E0_STEP_PIN > -1)
SET_OUTPUT(E0_STEP_PIN);
WRITE(E0_STEP_PIN,INVERT_E_STEP_PIN);
disable_e0();
#endif
#if defined(E1_STEP_PIN) && (E1_STEP_PIN > -1)
SET_OUTPUT(E1_STEP_PIN);
WRITE(E1_STEP_PIN,INVERT_E_STEP_PIN);
disable_e1();
#endif
#if defined(E2_STEP_PIN) && (E2_STEP_PIN > -1)
SET_OUTPUT(E2_STEP_PIN);
WRITE(E2_STEP_PIN,INVERT_E_STEP_PIN);
disable_e2();
#endif

// waveform generation = 0100 = CTC
TCCR1B &= ~(1<<WGM13);
TCCR1B |= (1<<WGM12);
TCCR1A &= ~(1<<WGM11);
TCCR1A &= ~(1<<WGM10);

// output mode = 00 (отключен)
TCCR1A &= ~(3<<COM1A0);
TCCR1A &= ~(3<<COM1B0);

// Установить Таймер предварительный скалер
// Как правило, мы используем делитель 8, в результате чего 2MHz Таймер
// частоты на MCU 16MHz. Если вы собираетесь изменить это, быть
// уверен, регенерировать speed_lookuptable.h с
// create_speed_lookuptable.py
TCCR1B = (TCCR1B & ~(0x07<<CS10)) | (2<<CS10);

OCR1A = 0x4000;
TCNT1 = 0;
ENABLE_STEPPER_DRIVER_INTERRUPT();

#ifdef заранее
#if defined(TCCR0A) && defined(WGM01)
TCCR0A &= ~(1<<WGM01);
TCCR0A &= ~(1<<WGM00);
#endif
e_steps[0] = 0;
e_steps[1] = 0;
e_steps[2] = 0;
TIMSK0 |= (1<<OCIE0A);
#endif //ADVANCE

enable_endstops(true); // начать с концевики активным. По возвращении они могут быть отключены
sei();
}


// Блока до тех пор, пока все буферизованные действия выполняются
void st_synchronize()
{
while( blocks_queued()) {
manage_heater();
manage_inactivity();
lcd_update();
}
}

void st_set_position(const long &x, const long &y, const long &z, const long &e)
{
CRITICAL_SECTION_START;
count_position[X_AXIS] = x;
count_position[Y_AXIS] = y;
count_position[Z_AXIS] = z;
count_position[E_AXIS] = e;
CRITICAL_SECTION_END;
}

void st_set_e_position(const long &e)
{
CRITICAL_SECTION_START;
count_position[E_AXIS] = e;
CRITICAL_SECTION_END;
}

долго st_get_position(__u8 оси)
{
долго count_pos;
CRITICAL_SECTION_START;
count_pos = count_position[ось];
CRITICAL_SECTION_END;
возвращение count_pos;
}

#ifdef ENABLE_AUTO_BED_LEVELING
float st_get_position_mm(__u8 оси)
{
float steper_position_in_steps = st_get_position(оси);
возвращение steper_position_in_steps / axis_steps_per_unit[ось];
}
#endif // ENABLE_AUTO_BED_LEVELING

void finishAndDisableSteppers()
{
st_synchronize();
disable_x();
disable_y();
disable_z();
disable_e0();
disable_e1();
disable_e2();
}

void quickStop()
{
DISABLE_STEPPER_DRIVER_INTERRUPT();
while(blocks_queued())
plan_discard_current_block();
current_block = NULL;
ENABLE_STEPPER_DRIVER_INTERRUPT();
}

#ifdef BABYSTEPPING


void babystep(const __u8 оси,const bool direction)
{
//Должна вызываться только ISR, это зависит от того, что никакие другие прерывания ISR этот
//магазина первоначальный pin-членов
switch(оси)
{
случае X_AXIS:
{
enable_x(); 
__u8 old_x_dir_pin= READ(X_DIR_PIN); //если dualzstepper, оба указывают в одно направление.

//установки новый шаг
WRITE(X_DIR_PIN,(INVERT_X_DIR)^направление);
#ifdef DUAL_X_CARRIAGE
WRITE(X2_DIR_PIN,(INVERT_X_DIR)^направление);
#endif

//выполнить шаг 
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); 
#ifdef DUAL_X_CARRIAGE
WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN);
#endif
{
float x=1./float(оси+1)/float(ось+2); //подождать чуть-чуть
}
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
#ifdef DUAL_X_CARRIAGE
WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN);
#endif

//получить старый pin состояние обратно.
WRITE(X_DIR_PIN,old_x_dir_pin);
#ifdef DUAL_X_CARRIAGE
WRITE(X2_DIR_PIN,old_x_dir_pin);
#endif

}
break;
случае Y_AXIS:
{
enable_y(); 
__u8 old_y_dir_pin= READ(Y_DIR_PIN); //если dualzstepper, оба указывают в одном направлении.

//установки новый шаг
WRITE(Y_DIR_PIN,(INVERT_Y_DIR)^направление);
#ifdef DUAL_Y_CARRIAGE
WRITE(Y2_DIR_PIN,(INVERT_Y_DIR)^направление);
#endif

//выполнить шаг 
WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); 
#ifdef DUAL_Y_CARRIAGE
WRITE(Y2_STEP_PIN, !INVERT_Y_STEP_PIN);
#endif
{
float x=1./float(оси+1)/float(ось+2); //подождать чуть-чуть
}
WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN);
#ifdef DUAL_Y_CARRIAGE
WRITE(Y2_STEP_PIN, INVERT_Y_STEP_PIN);
#endif

//получить старый pin состояние обратно.
WRITE(Y_DIR_PIN,old_y_dir_pin);
#ifdef DUAL_Y_CARRIAGE
WRITE(Y2_DIR_PIN,old_y_dir_pin);
#endif

}
break;

#ifndef Дельта
случае Z_AXIS:
{
enable_z();
__u8 old_z_dir_pin= READ(Z_DIR_PIN); //если dualzstepper, оба указывают в одно направление.
//установки новый шаг
WRITE(Z_DIR_PIN,(INVERT_Z_DIR)^направление^BABYSTEP_INVERT_Z);
#ifdef Z_DUAL_STEPPER_DRIVERS
WRITE(Z2_DIR_PIN,(INVERT_Z_DIR)^направление^BABYSTEP_INVERT_Z);
#endif
//выполнить шаг 
WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); 
#ifdef Z_DUAL_STEPPER_DRIVERS
WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN);
#endif
//подождите чуть-чуть
{
float x=1./float(оси+1); //абсолютно бесполезно
}
WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN);
#ifdef Z_DUAL_STEPPER_DRIVERS
WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN);
#endif

//получить старый pin состояние обратно.
WRITE(Z_DIR_PIN,old_z_dir_pin);
#ifdef Z_DUAL_STEPPER_DRIVERS
WRITE(Z2_DIR_PIN,old_z_dir_pin);
#endif

}
break;
#else //Дельта
случае Z_AXIS:
{
enable_x();
enable_y();
enable_z();
__u8 old_x_dir_pin= READ(X_DIR_PIN); 
__u8 old_y_dir_pin= READ(Y_DIR_PIN); 
__u8 old_z_dir_pin= READ(Z_DIR_PIN); 
//установки новый шаг
WRITE(X_DIR_PIN,(INVERT_X_DIR)^направление^BABYSTEP_INVERT_Z);
WRITE(Y_DIR_PIN,(INVERT_Y_DIR)^направление^BABYSTEP_INVERT_Z);
WRITE(Z_DIR_PIN,(INVERT_Z_DIR)^направление^BABYSTEP_INVERT_Z);

//выполнить шаг 
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); 
WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); 
WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); 

//подождите чуть-чуть
{
float x=1./float(оси+1); //абсолютно бесполезно
}
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); 
WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN); 
WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN);

//получить старый pin государственной назад.
WRITE(X_DIR_PIN,old_x_dir_pin);
WRITE(Y_DIR_PIN,old_y_dir_pin);
WRITE(Z_DIR_PIN,old_z_dir_pin);

}
break;
#endif

default: break;
}
}
#endif //BABYSTEPPING

void digitalPotWrite(int address, int value) // от Arduino DigitalPotControl пример
{
#if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
digitalWrite(DIGIPOTSS_PIN,LOW); // взять SS pin low для выбора фишек
SPI.transfer(адрес); // отправить адрес и стоимость по SPI:
SPI.transfer(значение);
digitalWrite(DIGIPOTSS_PIN,HIGH); // взять SS pin high де-выберите фишку:
//delay(10);
#endif
}

void digipot_init() //Инициализируем Digipot тока двигателя
{
#if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
const __u8 digipot_motor_current[] = DIGIPOT_MOTOR_CURRENT;

SPI.begin();
pinMode(DIGIPOTSS_PIN, OUTPUT);
for(int i=0;i<=4;i++)
//digitalPotWrite(digipot_ch[i], digipot_motor_current[i]);
digipot_current(я,digipot_motor_current[i]);
#endif
#ifdef MOTOR_CURRENT_PWM_XY_PIN
pinMode(MOTOR_CURRENT_PWM_XY_PIN, OUTPUT);
pinMode(MOTOR_CURRENT_PWM_Z_PIN, OUTPUT);
pinMode(MOTOR_CURRENT_PWM_E_PIN, OUTPUT);
digipot_current(0, motor_current_setting[0]);
digipot_current(1, motor_current_setting[1]);
digipot_current(2, motor_current_setting[2]);
//Set timer5 к 31khz так ШИМ из мощности двигателя по возможности постоянным. (убирает гудение)
TCCR5B = (TCCR5B & ~(_BV(CS50) | _BV(CS51) | _BV(CS52))) | _BV(CS50);
#endif
}

void digipot_current(__u8 driver, int current)
{
#if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
const __u8 digipot_ch[] = DIGIPOT_CHANNELS;
digitalPotWrite(digipot_ch[driver], текущий);
#endif
#ifdef MOTOR_CURRENT_PWM_XY_PIN
если (driver == 0) analogWrite(MOTOR_CURRENT_PWM_XY_PIN, (длительный)ток * 255L / (long)MOTOR_CURRENT_PWM_RANGE);
если (driver == 1) analogWrite(MOTOR_CURRENT_PWM_Z_PIN, (длительный)ток * 255L / (long)MOTOR_CURRENT_PWM_RANGE);
если (driver == 2) analogWrite(MOTOR_CURRENT_PWM_E_PIN, (длительный)ток * 255L / (long)MOTOR_CURRENT_PWM_RANGE);
#endif
}

void microstep_init()
{
#if defined(X_MS1_PIN) && X_MS1_PIN > -1
const __u8 microstep_modes[] = MICROSTEP_MODES;
pinMode(X_MS2_PIN,OUTPUT);
pinMode(Y_MS2_PIN,OUTPUT);
pinMode(Z_MS2_PIN,OUTPUT);
pinMode(E0_MS2_PIN,OUTPUT);
pinMode(E1_MS2_PIN,OUTPUT);
for(int i=0;i<=4;i++) microstep_mode(я,microstep_modes[i]);
#endif
}

void microstep_ms(__u8 драйвер, int8_t ms1, int8_t, ms2)
{
если(ms1 > -1) переключатель(водитель)
{
case 0: digitalWrite( X_MS1_PIN,ms1); break;
случай 1: digitalWrite( Y_MS1_PIN,ms1); break;
случай 2: digitalWrite( Z_MS1_PIN,ms1); break;
случай 3: digitalWrite(E0_MS1_PIN,ms1); break;
случай 4: digitalWrite(E1_MS1_PIN,ms1); break;
}
если(ms2 > -1) переключатель(водитель)
{
case 0: digitalWrite( X_MS2_PIN,ms2); break;
случай 1: digitalWrite( Y_MS2_PIN,ms2); break;
случай 2: digitalWrite( Z_MS2_PIN,ms2); break;
случай 3: digitalWrite(E0_MS2_PIN,ms2); break;
случай 4: digitalWrite(E1_MS2_PIN,ms2); break;
}
}

void microstep_mode(__u8 драйвер, __u8 stepping_mode)
{
switch(stepping_mode)
{
случай 1: microstep_ms(водитель,MICROSTEP1); break;
случай 2: microstep_ms(водитель,MICROSTEP2); break;
случай 4: microstep_ms(водитель,MICROSTEP4); break;
case 8: microstep_ms(водитель,MICROSTEP8); break;
case 16: microstep_ms(водитель,MICROSTEP16); break;
}
}

void microstep_readings()
{
SERIAL_PROTOCOLPGM("MS1,MS2 контактов\n");
SERIAL_PROTOCOLPGM("X: ");
SERIAL_PROTOCOL( digitalRead(X_MS1_PIN));
SERIAL_PROTOCOLLN( digitalRead(X_MS2_PIN));
SERIAL_PROTOCOLPGM("Y: ");
SERIAL_PROTOCOL( digitalRead(Y_MS1_PIN));
SERIAL_PROTOCOLLN( digitalRead(Y_MS2_PIN));
SERIAL_PROTOCOLPGM("Z: ");
SERIAL_PROTOCOL( digitalRead(Z_MS1_PIN));
SERIAL_PROTOCOLLN( digitalRead(Z_MS2_PIN));
SERIAL_PROTOCOLPGM("E0: ");
SERIAL_PROTOCOL( digitalRead(E0_MS1_PIN));
SERIAL_PROTOCOLLN( digitalRead(E0_MS2_PIN));
SERIAL_PROTOCOLPGM("E1: ");
SERIAL_PROTOCOL( digitalRead(E1_MS1_PIN));
SERIAL_PROTOCOLLN( digitalRead(E1_MS2_PIN));
}

 

/*
stepper.h - драйвер шагового двигателя: выполняет движения планах planner.c с помощью шаговых двигателей
Часть Grbl

Copyright (c) 2009-2011 Simen Svale Skogsrud

Grbl является свободным программным обеспечением: вы можете распространять и/или модифицировать
it under the terms of the GNU General Public License, опубликованной
Free Software Foundation, либо версии 3 лицензии, или
(по вашему выбору) любой более поздней версии.

Grbl распространяется в надежде что она будет полезной,
но без всякой гарантии; даже без подразумеваемой гарантии
Пригодности для продажи или пригодности для конкретной цели.  См.
GNU General Public License для более подробной информации.

Вы должны были получить копию GNU General Public License
вместе с Grbl. Если нет, см. <http://www.gnu.org/licenses/>.
*/

#ifndef stepper_h
#define stepper_h 

#include "planner.h"

#если ЭКСТРУДЕРЫ > 2
#define WRITE_E_STEP(v) { if(current_block->active_extruder == 2) { WRITE(E2_STEP_PIN, v); } else { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}}
#define NORM_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, !INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}}
#define REV_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}}
#elif ЭКСТРУДЕРЫ > 1
#ifndef DUAL_X_CARRIAGE
#define WRITE_E_STEP(v) { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}
#define NORM_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}
#define REV_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}
#else
extern bool extruder_duplication_enabled;
#define WRITE_E_STEP(v) { if(extruder_duplication_enabled) { WRITE(E0_STEP_PIN, v); WRITE(E1_STEP_PIN, v); } else if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}
#define NORM_E_DIR() { if(extruder_duplication_enabled) { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}
#define REV_E_DIR() { if(extruder_duplication_enabled) { WRITE(E0_DIR_PIN, INVERT_E0_DIR); WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}
#endif 
#else
#define WRITE_E_STEP(v) WRITE(E0_STEP_PIN, v)
#define NORM_E_DIR() WRITE(E0_DIR_PIN, !INVERT_E0_DIR)
#define REV_E_DIR() WRITE(E0_DIR_PIN, INVERT_E0_DIR)
#endif

#ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED
extern bool abort_on_endstop_hit;
#endif

// Инициализация и запуск шагового двигателя подсистемы
void st_init();

// Блока до тех пор, пока все буферизованные шаги исполняются
void st_synchronize();

// Установить текущее положение в шагах
void st_set_position(const long &x, const long &y, const long &z, const long &e);
void st_set_e_position(const long &e);

// Получить текущую позицию в действия
долго st_get_position(__u8 оси);

#ifdef ENABLE_AUTO_BED_LEVELING
// Получить текущую позицию в мм
float st_get_position_mm(__u8 оси);
#endif //ENABLE_AUTO_BED_LEVELING

// Stepper подсистема переходит в спящий режим, когда он работает из вещей, чтобы выполнить. Вызвать этот
// оповестить подсистемы, что пора идти на работу.
void st_wake_up();


void checkHitEndstops(); //вызов откуда-то создать серийный сообщение об ошибке с места концевики там, где бьют, в случае, если они были вызваны
void endstops_hit_on_purpose(); //не создавать сообщения, т.е. после самонаведения и перед обычным call of checkHitEndstops();

void enable_endstops(bool check); // Enable/disable endstop проверка

void checkStepperErrors(); //выводим ошибки, выявленные с помощью шагового

void finishAndDisableSteppers();

extern block_t *current_block; // указатель на блок, в настоящее время прослеживается

void quickStop();

void digitalPotWrite(int address, int value);
void microstep_ms(__u8 драйвер, int8_t ms1, int8_t, ms2);
void microstep_mode(__u8 драйвер, __u8 шага);
void digipot_init();
void digipot_current(__u8 driver, int current);
void microstep_init();
void microstep_readings();

#ifdef BABYSTEPPING
void babystep(const __u8 оси,const bool direction); // выполнить короткий шаг с одного шагового двигателя, вне какой-либо Конвенции
#endif



#endif

не пытайся сам все писать

100 килобайт для Atmel текста пишут командой 5 лет если с парсером команд

мне известен толко один проект в мире на 28 килобайт который не знаю сколько писало но поддерживает 1 человек

искать ссылку на станок с ЧПУ попроще или сам все уже изучаешь?

 

 

sirik
Offline
Зарегистрирован: 10.11.2012

Да хотелось бы самому. Пока что в планах линейный ход и круговой (соответсвенно G коды: G01, G02, G03).

ps/ код действительно не плох))

art100
Offline
Зарегистрирован: 09.03.2014

sirik пишет:

Да хотелось бы самому. Пока что в планах линейный ход и круговой (соответсвенно G коды: G01, G02, G03).

ps/ код действительно не плох))

код из жирного проекта который толпа студентов и преподов за казенные харчи писала отлаживала

уууу все таки на g-code парсер тебя несет в ардуину

есть в мире только 3 варианта

1.mach lpt + твои драйверы (ардуине тут делать нечего кроме чегонибудь шпиндельно индикаторного вспомогательного)

всякий софт проверенный на 3dпринтерах не важно ну допустмим printrun arduino разделяется на две ветки

2.atmega256 потому что болше 32килобайта мозга и туда люди смогли всунуть парсер толстый и развивающийся

и единственный вариант

3.arduino uno r3 и автор много труда потратил на оптимизацию кода чтоб всунуться 3 мотора 3 концевики 1 шпиндел и g-code для резки твоих кругов корпусов короче резки метала

30 ног как бы везде хватает на станок с ЧПУ и твои драйверы везде

4 вариант не сбрасывай со счетов когда arduino только контроллирует станок с ЧПУ а сам парсер все таки в большом интел компьютере

 

sirik
Offline
Зарегистрирован: 10.11.2012

Ну вот и ответ) Я смотрю на 4 вариант. Но это все пока что идеи и мысли... Так сказать собираю все в одну корзинку

art100
Offline
Зарегистрирован: 09.03.2014

sirik пишет:

Ну вот и ответ) Я смотрю на 4 вариант. Но это все пока что идеи и мысли... Так сказать собираю все в одну корзинку

Ну вот вы мне за мой опыт уже должны сколько я вам сэкономил

не менее 2000$

;)

ссылку давать на готовый вариант

я его даже собирал когда-то проверял g-code-ом

работает

и дури практически не обнаружил

 

 

sirik
Offline
Зарегистрирован: 10.11.2012

Пока что не надо) Пока что обдумываю различные алгоритмы

art100
Offline
Зарегистрирован: 09.03.2014

sirik пишет:

Пока что не надо) Пока что обдумываю различные алгоритмы

да брось ты велосипеды изобретать

все уже отлажено толпами студентов

надо использовать и двигаться дальше

 

sirik
Offline
Зарегистрирован: 10.11.2012

Мб ты и прав. Но тогда где найти нормальный интерпритатор G кодов на Arduino? Хотя бы коды 01, 02, 03

art100
Offline
Зарегистрирован: 09.03.2014

ну попробуй

что-то на диске вижу лежит

раз дата есть значит я это пробовал

честно не помню

https://yadi.sk/d/6MI_SSNmbdFoC