Объясните метаморфозу с обработкой прерывания

ALEGYR
Offline
Зарегистрирован: 20.09.2018

Есть подпрограмма обработки прерывания


//***********************************************************
       ISR(TIMER1_COMPA_vect)
//***********************************************************
{
    moveONESteps() ;   // делаем один шаг перемещения

    StopStep_X = true; // разрешаем работу мотора "X" 
    StopStep_Y = true; // разрешаем работу мотора "Y"
    count_ ++ ;        // увеличиваем счетчик всех шагов перемещения
    count_a ++ ;       // увеличиваем счетчик шагов перемещения в сегменте
    Delta_Move -- ;    // уменьшаем указатель остатка шагов перемещения

    if ( count_ <= max_count_Acceleration ){ // если разгоняемся, то
      stepCount = count_ ; }                 // 

    if ( stepCount >= Delta_Move ){          // если тормозим, то 
      stepCount = Delta_Move ; }             //
        
    TCNT1 = 0;                   // обнуляем таймер
    OCR1A = delay_H[stepCount] ; // определяем длительность работы таймера для следующего шага
    
    if ( Delta_Move_Segment == count_a  ){ // 
        movementDone = true;     // выcтавляем флаг окончания движения
        TIMER1_INTERRUPTS_OFF    // запрещаем прерывания таймера 

       // delayMicroseconds(200) ;      // *************


    }
}
//************************************************************
                  void moveONESteps() // 
//************************************************************
{
    if ( StopStep_X == true ) { X_STEP_HIGH } // формируем импульс "STEP_X"
    if ( StopStep_Y == true ) { Y_STEP_HIGH } // формируем импульс "STEP_Y" 
    delayMicroseconds(12) ;            //  держим сигналы "STEP_"           
    X_STEP_LOW                                // сбрасываем сигнал "STEP_X"
    Y_STEP_LOW                                // сбрасываем сигнал "STEP_Y"
}

 

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

Она используется на плате ардуино MEGA 2560 и через плату RAMPS 1.4 управляет движками X и Y.

При работе прототипа, столкнулся со следующей проблемой - Если  производится перемещение на любое расстояние из точкки А в точку B,  заданное одним значением (например в G-коде - "G1 X50.00")  то перемещение происходит плавно и тихо.

А если перемещение задается отрезками 

"G1 X10.00"

"G1 X20.00"

"G1 X30.00"

"G1 X40.00"

"G1 X50.00"

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

Если в 25 строке кода, разрешить действие задержки (delayMicroseconds(200);), то есть увеличить время выполнения подпрограммы обработки прерывания на 200 микросекунд, то ничего криминального не происходит, и в обоих случаях перемещение происходит плавно и тихо!!!

Когда на логическом анализаторе смотришь на сигналы "STEP_X" и "STEP_Y",  то на "шумной" диаграмме видны 4 четких прерываниий сигналов, протяженностью 6.05 - 6.06 милисекунды.

Объясните пожалуйста

1 - Откуда у этой метаморфозы ноги растут? 

2 - Почему увеличение времени работы подпрограммы обработки прерывания убирает обрывы во временной диаграмме?

GarryC
Offline
Зарегистрирован: 08.08.2016

Боюсь, что по этому фрагменту ничего не определеить.
Совершенно непонятно, как строка "G1 X50.00" превращается в указания драйверу, нет описания переменных, ну и т.д.
Нужен полный код )

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

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

Например я загружу, посмотрю на осцилографе и подумаю, где ошибка.

Пока кажется, что ошибке в непредставленной части кода.

a5021
Offline
Зарегистрирован: 07.07.2013

Вангую: где-то в прерываниях беснуются переменные, объявленные без volatile.

ALEGYR
Offline
Зарегистрирован: 20.09.2018

GarryC пишет:

Боюсь, что по этому фрагменту ничего не определеить.
Совершенно непонятно, как строка "G1 X50.00" превращается в указания драйверу, нет описания переменных, ну и т.д.
Нужен полный код )

Cтрока "G1 X50.00" превращается в указания драйверу подпрограммой 

//***********************************************************
                  void Serial_Report () 
//***********************************************************
{
//  Serial.println("Starting...");
  
    while ( Serial.available() > 0) {               // пока в буфере приема есть принятый байт, то
       char c = Serial.read();                      // считываем его в переменную "char c"
       Serial.print(c);                             // и возвращаем запомненный код обратно в компьютер 
       if ( sofar < MAX_BUF-1 ){                    // если счетчик принятых байтов меньше глубины программного буфера приема, то
           buffer[sofar++] = c ; }                  // запоминаем принятый байт в программном буфере приема, и увеличиваем счетчик принятых байтов  
       if ( c == '\n' ) {                           // если принятого байта кода конца строки G-кода ('\n'), то
           buffer[sofar] = 0 ;                      // в программном буфере приема запоминаем байт "00h", и
           processCommand() ;                       // определяем тип принятого G-кода 

           if ( input_G_code == 0 || input_G_code == 1 ){       // если введен цепочный G-код, то     
           
               START_Chain_Segment = true ;                     // выставлем флаг приема данных цепочки сегментов
               input_X = parsenumber('X',temp_Xa) ;             // фиксируем введенную координату "оси X"
               input_Y = parsenumber('Y',temp_Ya) ;             // фиксируем введенную координату "оси Y"

               if ( input_X == temp_Xa && input_Y == temp_Ya ){ // если введенные координаты соответствуют текущим координатам, то 
                   ready(); }                                   // посылаем запрос на введение следующего G-кода
               else {                                           // если введенные координаты НЕ соответствуют, то 
                   SET_input_data() ; } }                       // обрабатываем данные введенного G-кода
           else {                                               // если введен НЕ цепочный G-код, то
               START_Chain_Segment = false ;                    // сбрасываем флаг приема данных цепочки сегментов, и 
               SET_input_data() ; }                             // обрабатываем данные введенного G-кода
    }
  }  
}

прерывание задается операторами

  TCCR1A = 0;                               // 
  TCCR1B = 0;                               // 
  TCNT1  = 0;                               // 
  
  OCR1A = delay_HIGH;                       // 
  TCCR1B |= (1 << WGM12);                   // 
  TCCR1B |= ((1 << CS11) | (1 << CS10));    //   

 

 

ALEGYR
Offline
Зарегистрирован: 20.09.2018

wdrakula пишет:

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

Это как?

ALEGYR
Offline
Зарегистрирован: 20.09.2018

a5021 пишет:

Вангую: где-то в прерываниях беснуются переменные, объявленные без volatile.

Волатильными у меня объявлены

volatile unsigned long stepCount = 0 ; // это указатель числа пройденных шагов для фаз разгона и торможения
volatile boolean movementDone = false; // флаг состояния выполнения движения
volatile long  Delta_Move = 0;   // счетчик шагов для всей цепочки сегментов
volatile long  Delta_Move_Segment = 0;   // указатель числа шагов для сегмента
volatile long count_a = 0;    // счетчик пройденных шагов в сегменте

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ALEGYR пишет:

wdrakula пишет:

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

Это как?

Это написать маленькую программу, на основе большой, которую можно тут опубликовать (по размеру) и в которой происходит тоже самое.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ALEGYR, в идеале все операции с 16-битными регистрами таймеров нужно выполнять при выключенном таймере. Попробуйте для эксперимента перед 19 строчкой остановить а после 20-й запустить таймер.

ALEGYR
Offline
Зарегистрирован: 20.09.2018

wdrakula пишет:

Это написать маленькую программу, на основе большой, которую можно тут опубликовать (по размеру) и в которой происходит тоже самое.

Мужики, вы меня ставите в тупик!

Одному нужен полный код, а другому "маленькую программу, на основе большой".

У меня в обоих вариантах заданых перемещений меняется только ОДНА 26 строка  в подпрограмме обработки прерывания  ISR(TIMER1_COMPA_vect) и больше я нигде и ничего во всей программе не изменияю!

ALEGYR
Offline
Зарегистрирован: 20.09.2018

dimax пишет:

ALEGYR, в идеале все операции с 16-битными регистрами таймеров нужно выполнять при выключенном таймере. Попробуйте для эксперимента перед 19 строчкой остановить а после 20-й запустить таймер.

Я не знаю как (чем) его остановить! :(

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ALEGYR пишет:

Мужики, вы меня ставите в тупик!

Одному нужен полный код, а другому "маленькую программу, на основе большой".

Смотри: я прошу что-то ВМЕСТО полного кода. Повтори ошибку выкинув неважное, экран, кнопки и прочее.

Просто законченная программа, которую можно запустить на Меге. Вместо драйвера ШД, можно будет просто посмотреть осликом или логаналайзером на ногу СТЕП.

Часто новичек сам находит ошибку, готовя тестовый пример, но если ошибка сохранится - посмотрим.

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

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ALEGYR пишет:

Я не знаю как (чем) его остановить! :(

Ну блии-ин! Это не серьезно! Даташит читай... как ты иначе хочешь разговора?

ALEGYR
Offline
Зарегистрирован: 20.09.2018

wdrakula пишет:

Смотри: я прошу что-то ВМЕСТО полного кода. Повтори ошибку выкинув неважное, экран, кнопки и прочее.

А у меня в полном коде и нет ни кнопок, ни экрана, используется только СОМ порт. 

wdrakula пишет:

Просто законченная программа, которую можно запустить на Меге. Вместо драйвера ШД, можно будет просто посмотреть осликом или логаналайзером на ногу СТЕП.

Я могу скинуть экран с логаналайзера Saleae Logic 1.1.15. Там у меня и СТЕПЫ и ДИРЫ и RX и ТX

 

a5021
Offline
Зарегистрирован: 07.07.2013

ALEGYR пишет:

a5021 пишет:

Вангую: где-то в прерываниях беснуются переменные, объявленные без volatile.

Волатильными у меня объявлены

volatile unsigned long stepCount = 0 ; // это указатель числа пройденных шагов для фаз разгона и торможения
volatile boolean movementDone = false; // флаг состояния выполнения движения
volatile long  Delta_Move = 0;   // счетчик шагов для всей цепочки сегментов
volatile long  Delta_Move_Segment = 0;   // указатель числа шагов для сегмента
volatile long count_a = 0;    // счетчик пройденных шагов в сегменте

Тут не все переменные, которые используются в прерывании. С остальными, что?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ALEGYR пишет:

Я могу скинуть экран с логаналайзера Saleae Logic 1.1.15. Там у меня и СТЕПЫ и ДИРЫ и RX и ТX

Дорогой! Будь, плз, внимательным. Я верю тому, что ты написал, мне твоих логов не нужно.

Мне нужно увидеть такую же ошибку на своей плате, у себя в мастерской. Твой полный код для этого не годится, потому, что он связан с твоим железом. Нужно сделать независимый от железа код, для голой Меги 2560, но с тем же поведением. Это возможно, потому, что непонятное поведение в серии прерываний таймера, а не в железоспецифичной части кода.

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

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

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

ALEGYR пишет:

прерывание задается операторами

  TCCR1A = 0;                               // 
  TCCR1B = 0;                               // 
  TCNT1  = 0;                               // 
  
  OCR1A = delay_HIGH;                       // 
  TCCR1B |= (1 << WGM12);                   // 
  TCCR1B |= ((1 << CS11) | (1 << CS10));    //  

ведь останавливал же и запускал, но судя по отсутствию комментариев код скопипастен и не осознан.

ALEGYR
Offline
Зарегистрирован: 20.09.2018

a5021 пишет:

ALEGYR пишет:

a5021 пишет:

Вангую: где-то в прерываниях беснуются переменные, объявленные без volatile.

Волатильными у меня объявлены

volatile unsigned long stepCount = 0 ; // это указатель числа пройденных шагов для фаз разгона и торможения
volatile boolean movementDone = false; // флаг состояния выполнения движения
volatile long  Delta_Move = 0;   // счетчик шагов для всей цепочки сегментов
volatile long  Delta_Move_Segment = 0;   // указатель числа шагов для сегмента
volatile long count_a = 0;    // счетчик пройденных шагов в сегменте

Тут не все переменные, которые используются в прерывании. С остальными, что?

Остальные выглядят так -

boolean StopStep_X = false;    // флаг блокировки работы мотора X
boolean StopStep_Y = false;    // флаг блокировки работы мотора Y
long count_ = 0;              // рабочий счетчик шагов цепочки сегментов
int delay_H[700];             // МАССИВ РАССЧИТАННЫХ ЗНАЧЕНИЙ ЗАДЕРЖЕК для СИГНАЛА "STEP" [мкс]
 
#define TIMER1_INTERRUPTS_OFF   TIMSK1 &= ~(1 << OCIE1A);
a5021
Offline
Зарегистрирован: 07.07.2013

Вам кажется прикольным использовать эти переменные в обработчике? Фигли тогда жалуетесь?

ALEGYR
Offline
Зарегистрирован: 20.09.2018

wdrakula пишет:

Мне нужно увидеть такую же ошибку на своей плате, у себя в мастерской. Твой полный код для этого не годится, потому, что он связан с твоим железом. Нужно сделать независимый от железа код, для голой Меги 2560, но с тем же поведением. Это возможно, потому, что непонятное поведение в серии прерываний таймера, а не в железоспецифичной части кода.

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

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

Для меня не проблема выставить тут всю программу! Для меня проблема отредактивровать ее под ТВОЕ железо! 

ALEGYR
Offline
Зарегистрирован: 20.09.2018

a5021 пишет:

Вам кажется прикольным использовать эти переменные в обработчике? Фигли тогда жалуетесь?

А разве я жалуюсь?! Я просто задал два вопроса

Цитата:

1- Откуда у этой метаморфозы ноги растут? 

 

2 - Почему увеличение времени работы подпрограммы обработки прерывания убирает обрывы во временной диаграмме?

и попросил их мне объяснить.

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

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

ALEGYR пишет:

Остальные выглядят так -

boolean StopStep_X = false;    // флаг блокировки работы мотора X
boolean StopStep_Y = false;    // флаг блокировки работы мотора Y
long count_ = 0;              // рабочий счетчик шагов цепочки сегментов
int delay_H[700];             // МАССИВ РАССЧИТАННЫХ ЗНАЧЕНИЙ ЗАДЕРЖЕК для СИГНАЛА "STEP" [мкс]
 
#define TIMER1_INTERRUPTS_OFF   TIMSK1 &= ~(1 << OCIE1A);

Если переменные используются внутри обработчика прерываний - где volatile?

a5021
Offline
Зарегистрирован: 07.07.2013

Первое правило правописания должно быть таково, что все переменные, которые используются в обработчике, должны быть volatile.

ALEGYR
Offline
Зарегистрирован: 20.09.2018

xDriver пишет:

ALEGYR пишет:

прерывание задается операторами

  TCCR1A = 0;                               // 
  TCCR1B = 0;                               // 
  TCNT1  = 0;                               // 
  
  OCR1A = delay_HIGH;                       // 
  TCCR1B |= (1 << WGM12);                   // 
  TCCR1B |= ((1 << CS11) | (1 << CS10));    //  

ведь останавливал же и запускал, но судя по отсутствию комментариев код скопипастен и не осознан.

исходником была программа 

#define DIR_PIN          2
#define STEP_PIN         3
#define ENABLE_PIN       4

#define STEP_HIGH        PORTD |=  0b00001000;
#define STEP_LOW         PORTD &= ~0b00001000;

#define TIMER1_INTERRUPTS_ON    TIMSK1 |=  (1 << OCIE1A);
#define TIMER1_INTERRUPTS_OFF   TIMSK1 &= ~(1 << OCIE1A);

unsigned int c0;

void setup() {
  Serial.begin(9600);
  
  pinMode(STEP_PIN,   OUTPUT);
  pinMode(DIR_PIN,    OUTPUT);
  pinMode(ENABLE_PIN, OUTPUT);

  noInterrupts();
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;
  OCR1A = 1000;                             
  TCCR1B |= (1 << WGM12);
  TCCR1B |= ((1 << CS11) | (1 << CS10));
  interrupts();

  c0 = 1600; //2000 * sqrt( 1 ) * 0.67703;
}

volatile int dir = 0;
volatile unsigned int maxSpeed = 80;
volatile unsigned long n = 0;
volatile float d;
volatile unsigned long stepCount = 0;
volatile unsigned long rampUpStepCount = 0;
volatile unsigned long totalSteps = 0;

volatile int stepPosition = 0;

volatile bool movementDone = false;

ISR(TIMER1_COMPA_vect)
{
  if ( stepCount < totalSteps ) {
    STEP_HIGH
    STEP_LOW
    stepCount++;
    stepPosition += dir;
  }
  else {
    movementDone = true;
    TIMER1_INTERRUPTS_OFF
  }

  if ( rampUpStepCount == 0 ) { // ramp up phase
    n++;
    d = d - (2 * d) / (4 * n + 1);
    if ( d <= maxSpeed ) {
      d = maxSpeed;
      rampUpStepCount = stepCount;
    }
    if ( stepCount >= totalSteps / 2 ) {
      rampUpStepCount = stepCount;
    }
  }
  else if ( stepCount >= totalSteps - rampUpStepCount ) { // ramp down phase
    n--;
    d = (d * (4 * n + 1)) / (4 * n + 1 - 2);
  }

  OCR1A = d;
}

void moveNSteps(int steps) {

  digitalWrite(DIR_PIN, steps < 0 ? HIGH : LOW);
  dir = steps > 0 ? 1 : -1;
  totalSteps = abs(steps);
  d = c0;
  OCR1A = d;
  stepCount = 0;
  n = 0;
  rampUpStepCount = 0;
  movementDone = false;

  TIMER1_INTERRUPTS_ON
}

void moveToPosition(int p, bool wait = true) {
  moveNSteps(p - stepPosition);
  while ( wait && ! movementDone );
}

void loop() {

  Serial.println("Starting...");

  moveToPosition( 8000, false );

  int count = 0;
  while ( !movementDone ) {    
    if ( count > 3 ) {
      movementDone = true;
      TIMER1_INTERRUPTS_OFF
    }
    else {
      Serial.print(count++);
      Serial.print(" ");
      Serial.println( stepPosition );
      delay(500);
    }
  }

  Serial.println("Finished.");

  Serial.println( stepPosition );

  while (true);

}

ее и адаптировал под сябя


 

ALEGYR
Offline
Зарегистрирован: 20.09.2018

DIYMan пишет:

Если переменные используются внутри обработчика прерываний - где volatile?

Так они точно также используются и с delayMicroseconds(200) ; (26 строкой в первом сообщении темы) и без нее. Я же их никак не меняю,  а вот результаты получаю разные!!! ПОЧЕМУ?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ALEGYR пишет:

 Я же их никак не меняю,  а вот результаты получаю разные!!! ПОЧЕМУ?

Это называется оптимизация. "Некогда объяснять, но..." ;)

--------------

Под какое "мое железо"? Я тебе написал: сделай пример просто под 2650, под голую. Я запущу у себя в мастерской и точно скажу - волатиль тут или неправильная работа с таймером.

--------------

волатиль просто проверь - поставь и пересобери.

ALEGYR
Offline
Зарегистрирован: 20.09.2018

a5021 пишет:

Первое правило правописания должно быть таково, что все переменные, которые используются в обработчике, должны быть volatile.

Не проблема! Сейчас поставлю все volatile и проверю.

ALEGYR
Offline
Зарегистрирован: 20.09.2018

ALEGYR пишет:

Не проблема! Сейчас поставлю все volatile и проверю.

Результат ОТРИЦАТЕЛЬНЫЙ!!!

a5021
Offline
Зарегистрирован: 07.07.2013

Анализа на сифилис?

sadman41
Offline
Зарегистрирован: 19.10.2016

Помнится, я как-то словил странный стук на шаговике... Оказалось, что сам дурак - написал алгоритм так, что при иногда один шаг отличался от другого на 1 мс. Шаговик кряхтел при некоторых обстоятельствах, как предпенсионер. 

ALEGYR
Offline
Зарегистрирован: 20.09.2018

a5021 пишет:

Анализа на сифилис?

Анализа на правильное правописание переменных в подпрограмме обработки прерыванний. 

Поставил на все оставшиеся переменные указатель volatile, но тарахтение не прошло. Вставляю  задержку delayMicroseconds(200) ; и все идет тихо и гладко!

ALEGYR
Offline
Зарегистрирован: 20.09.2018

sadman41 пишет:

Помнится, я как-то словил странный стук на шаговике... Оказалось, что сам дурак - написал алгоритм так, что при определенных обстоятельствах один шаг отличался от другого на 1 мс. Шаговик кряхтел при некоторых обстоятельствах, как предпенсионер. 

У меня шаги при разгоне и торможении меняются в 5 раз от стартовых 1-3 милисекунд и до выхода на скорость 20-60 микросекунд, и никаких посторонних звуков не происходит. Тарахтение происходит только если прямое перемещение разбито на отрезки и в подпрограмме обработки прерывания отсутствует задержка при выходе из режима прерывания.

    if ( Delta_Move_Segment == count_a  ){ //|| Delta_Move == 0 ){ //

        movementDone = true;     // вычтавляем флаг окончания движения
        TIMER1_INTERRUPTS_OFF    // запрещаем прерывания таймера 
        //delayMicroseconds(200) ; // 
    }

 

nik182
Offline
Зарегистрирован: 04.05.2015

Ребята, я не в курсе, на меге delayMicroseconds(200) в прерывании работает?

sadman41
Offline
Зарегистрирован: 19.10.2016

delayMicroseconds() работает, delay() не работает. millis() и micros() стоят, как у Мавзолея.

sadman41
Offline
Зарегистрирован: 19.10.2016

ALEGYR пишет:

У меня шаги при разгоне и торможении меняются в 5 раз от стартовых 1-3 милисекунд и до выхода на скорость 20-60 микросекунд, и никаких посторонних звуков не происходит. Тарахтение происходит только если прямое перемещение разбито на отрезки и в подпрограмме обработки прерывания отсутствует задержка при выходе из 

Если последовательно увеличивается, то мож и ничего, а у меня на прямом ходе флапало и тарахтело. Тоже сначала ничего не понимал, потом вывел миллисы в сериал...

a5021
Offline
Зарегистрирован: 07.07.2013

ALEGYR пишет:
если прямое перемещение разбито на отрезки и в подпрограмме обработки прерывания отсутствует задержка при выходе из режима прерывания.

Задержка в прерывании -- это почище гвоздя в сапоге. Никаких задержек в обработчике быть не должно в принципе.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Так, если все еще чего-то хочешь - готовь программу... в крайнем случае, хер с тобой, выложи как есть. Еще проведи эксперимент - 200 мкс лечат, а 100? а 50?... короче, понял, да?

На все про все, повторюсь, если это тебе надо, у тебя - день. Завтра шабат и я заниматься херней не буду.

Всем Шабат шалом, в этом чате! ;) ;) ;)

ALEGYR
Offline
Зарегистрирован: 20.09.2018

sadman41 пишет:

Если последовательно увеличивается, то мож и ничего, а у меня на прямом ходе флапало и тарахтело. Тоже сначала ничего не понимал, потом вывел миллисы в сериал...

Что такое "флапало" и "вывел миллисы в сериал" ?

sadman41
Offline
Зарегистрирован: 19.10.2016

ALEGYR пишет:

sadman41 пишет:

Если последовательно увеличивается, то мож и ничего, а у меня на прямом ходе флапало и тарахтело. Тоже сначала ничего не понимал, потом вывел миллисы в сериал...

Что такое "флапало" и "вывел миллисы в сериал" ?

1) от англ. flap — махать, хлопать. Т.е. междушаговый интервал был то N, то N+1 мс.

2) Serial.println(millis()-stepStartTime); В обработчике прерывания наврядли такой способ поможет. Я просто поделился опытом - рокот и стук был из-за неравномерности шага. Может вы своим delayMicroseconds() его выравниваете и таинственный стук пропадает.

ALEGYR
Offline
Зарегистрирован: 20.09.2018

a5021 пишет:

Задержка в прерывании -- это почище гвоздя в сапоге. Никаких задержек в обработчике быть не должно в принципе.

Так ее там вроде как и нет! Задержка используется только ОДИН раз за все перемещение по сегменту, и только после запрета прерывания по таймеру!!!  

Ее в изначальном варианте не было. Я ее ввел только тогда, когда стал разбираться с тарахтением. 

ALEGYR
Offline
Зарегистрирован: 20.09.2018

wdrakula пишет:

Так, если все еще чего-то хочешь - готовь программу... 

То что мне надо я написал в своем первом сообщении!

ALEGYR пишет:

Объясните пожалуйста

1 - Откуда у этой метаморфозы ноги растут? 

2 - Почему увеличение времени работы подпрограммы обработки прерывания убирает обрывы во временной диаграмме?

 

А что касается 

wdrakula пишет:

в крайнем случае, хер с тобой, выложи как есть. Еще проведи эксперимент - 200 мкс лечат, а 100? а 50?... короче, понял, да?

то на 50 тарахтит, а на 100, 200, 300 уже не тарахтит!

ALEGYR
Offline
Зарегистрирован: 20.09.2018

sadman41 пишет:

1) от англ. flap — махать, хлопать. Т.е. междушаговый интервал был то N, то N+1 мс.

2) Serial.println(millis()-stepStartTime); В обработчике прерывания наврядли такой способ поможет. Я просто поделился опытом - рокот и стук был из-за неравномерности шага. Может вы своим delayMicroseconds() его выравниваете и таинственный стук пропадает.

Это на каком движке надо было шагать с междушаговым интервалом от N, то N+1 мс ? 

Мои nema 17 на междушаговом интервале в 1-2 мс просто стартуют и останавливаются

 

sadman41
Offline
Зарегистрирован: 19.10.2016

На неме и рокотало. 

Вы хотите, чтобы я назвал вам точные цифры? Уверены, что наши немы эквивалентны, драйверы и блоки питания одинаковы на 100% и эффект повторится? Я указал на возможную причину. Можете проверять ее или просто игнорировать - дело ваше.

ALEGYR
Offline
Зарегистрирован: 20.09.2018

sadman41 пишет:

На неме и рокотало. 

Вы хотите, чтобы я назвал вам точные цифры? 

Нет не хочу! Я хочу сказать, что с 1-2 милисекунд движок стартует из полного покоя, и успевает остановится если он вращался. Все что будет дольше, вынуждает вращаться шаговый движок как-бы в режиме СТАРТ-СТОП,  и это сопровождается характерным рокотом или тарахтением. А если при этом, на каждом шаге, еще и переключался сигнал ENABLE,  то звук будет еще заметнее,  за счет постоянного включения и выключения выходного каскада драйвера.

sadman41
Offline
Зарегистрирован: 19.10.2016

У шагового двигателя нет старта или стопа. Вал просто перескакивает между обмотками (или зависает между ними при микрошаге) в случае подачи импульса на вход STEP драйвера. Чтобы изучить (изучить) истинные причины рокота необходимы целенаправленные и практически лабораторные исследования. Таковых я не проводил. Наблюдением поделился. Используйте его, если пожелаете.

Зачем Enable дергать на каждом шаге - не представляю на данный момент.

 

ALEGYR
Offline
Зарегистрирован: 20.09.2018

sadman41 пишет:

У шагового двигателя нет старта или стопа.

...

Зачем Enable дергать на каждом шаге - не представляю на данный момент.

я писал 

ALEGYR пишет:

 как-бы в режиме СТАРТ-СТОП,  

а что касается сигнала "Enable", то в некоторых скетчах, его используют не на все время движения,  а на каждый сегмент движения. Зачем это делают я не понимаю,  но люди это используют.

ALEGYR
Offline
Зарегистрирован: 20.09.2018

wdrakula пишет:

Так, если все еще чего-то хочешь - готовь программу... в крайнем случае, хер с тобой, выложи как есть. 

Выкладываю то что получилось. Это все проверено на моем железе



// ******************************************************

#define X_STEP_PIN         54 // 
#define X_DIR_PIN          55 // 
#define X_ENAB_PIN         38 //

#define X_STEP_HIGH        PORTF |=  0b00000001;
#define X_STEP_LOW         PORTF &= ~0b00000001;


// *********************************************************
#define Y_DIR_PIN          61 //
#define Y_STEP_PIN         60 //
#define Y_ENAB_PIN         56 //

#define Y_STEP_HIGH        PORTF |=  0b01000000;
#define Y_STEP_LOW         PORTF &= ~0b01000000;

// **********************************************************

#define TIMER1_INTERRUPTS_ON    TIMSK1 |=  (1 << OCIE1A);
#define TIMER1_INTERRUPTS_OFF   TIMSK1 &= ~(1 << OCIE1A);

#define MAX_BUF           128  // глубина буфера  входного сообщения

int sofar;                     // счетчик заполнения буфера входного сообщения 
char buffer[MAX_BUF];          // буфер входного сообщения 
int cmd = 99;                  // пустая команда

boolean STATUS_MODE_Segment = false ; // ФЛАГ ОБРЫВА ЦЕПОЧКИ СЕГМЕНТОВ
boolean START_Chain_Segment = false ; // ФЛАГ НАЧАЛА ЦЕПОЧКИ СЕГМЕНТОВ
boolean START_New_Chain     = false ; // ФЛАГ НАЧАЛА НОВОЙ ЦЕПОЧКИ СЕГМЕНТОВ
boolean transfer_permission = false ; // ФЛАГ разрешения передачи ответа
boolean StopStep_X          = false;  // флаг блокировки мотора X
boolean StopStep_Y          = false;  // флаг блокировки мотора Y

int step_for_X  = 100;         // шаги на 1 мм для оси X 
int step_for_Y  = 100;         // шаги на 1 мм для оси Y 

int delay_HIGH = 1000;        // ЗНАЧЕНИЕ ПЕРВОЙ ВЫДЕРЖКИ СИГНАЛА "STEP" [мкс]
int delay_min  = 20;          // ЗНАЧЕНИЕ МИНИМАЛЬНОЙ ВЫДЕРЖКИ СИГНАЛА "STEP" [мкс]
int delay_H[700];             // МАССИВ РАСЧИТАННЫХ ЗНАЧЕНИЙ СИГНАЛА "STEP" [мкс]


int input_count_buf = 0;      // счетчик сегментов вводимой цепочки
int count_buf = 0;            // счетчик сегментов выводимой цепочки

int current_G_code = -1;     //  код текущего G-кода
int input_G_code  = -1;     //  код входного G-кода
int temp_G_code   = -1;     //  код промежуточного G-кода  

float input_X = 0.0;      // входное значение для  оси X в мм
float input_Y = 0.0;      // входное значение для  оси Y в мм

float temp_Xa = 0;        // промежуточное значение для  оси X в мм
float temp_Ya = 0;        // промежуточное значение для  оси Y в мм 

long input_Pos_X = 0;     // входное значение координаты "X" (в щагах)
long input_Pos_Y = 0;     // входное значение координаты "Y" (в щагах) 

long current_Pos_X = 0;    // текущее значение координаты "X" (в щагах) 
long current_Pos_Y = 0;    // текущее значение координаты "Y" (в щагах)  

long temp_Pos_X = 0;      // вспомогательное значение координаты "X" (в щагах) 
long temp_Pos_Y = 0;      // вспомогательное координаты "Y" (в щагах)

long input_delta_X = 0 ;  // число шапгов перемещения по оси "X"  
long input_delta_Y = 0 ;  // число шапгов перемещения по оси "Y"  

int input_MODE_Segment   = 0 ; // режим сегмента для поступившего G-кода 
int current_MODE_Segment = 0 ; // режим сегмента для текущего G-кода 

int   current_dir_X = 0 ; // указатель направления перемещения для мотора Х
int   current_dir_Y = 0 ; // указатель направления перемещения для мотора н

long  input_Delta_Move = 0 ; // длина сегмента для поступивщего G-кода

long  buf_Delta_Move[40] ;  // буфер сегментов для цепочки сегментов

int count_Acceler = 0; //  счетчик шагов для фаз усколения или торможения

volatile boolean movementDone = false; // флаг окончания движения

volatile int max_count_Acceleration  = 0 ; // число шагов выхода на максимальную скорость
volatile long Delta_Move_Segment = 0;   // указатель числа шагов конкретного сегмента цепочки
volatile long stepCount = 0 ; //  счетчик разгона и торможения 
volatile long Delta_Move = 0; // общее число шагов в цепоске сегментов 
volatile long count_ = 0;     // рабочий счетчик шагов цепочки сегментов
volatile long count_a = 0;    // счетчик шагов текущего сегмента


//***********************************************************
       ISR(TIMER1_COMPA_vect)
//***********************************************************
{

    moveONESteps() ; // делаем шаг 
    
    StopStep_X = true; StopStep_Y = true; // разрешаем движение по осям "X" и "Y"
    
    count_ ++ ;
    count_a ++ ;
    Delta_Move -- ;

    if ( count_ <= max_count_Acceleration ){ stepCount = count_ ; }     // когда разгоняемся 
    if ( stepCount >= Delta_Move )         { stepCount = Delta_Move ; } // когда тормозимся
        
    TCNT1 = 0;                   // обнуляем таймер
    OCR1A = delay_H[stepCount] ; // определяем длительность таймера 
    
    if ( Delta_Move_Segment == count_a ){ // если сегмент окончен

        movementDone = true;     //  выставляем флаг окончания движения
        TIMER1_INTERRUPTS_OFF    // запрещаем прерывания таймера 
       // delayMicroseconds(200) ; // 
    }
}


//********************************************************************************************
                  void moveONESteps() 
//********************************************************************************************
{
    if ( StopStep_X == true ) { X_STEP_HIGH } // фромируем импульс "STEP_X"
    if ( StopStep_Y == true ) { Y_STEP_HIGH } // фромируем импульс "STEP_Y" 
    delayMicroseconds(12) ; //            
    X_STEP_LOW                                // сбрасываем сигнал "STEP_X"
    Y_STEP_LOW                                // сбрасываем сигнал "STEP_Y"
}

//********************************************************************************************
                  void moveNSteps() 
//****************************************************************
{
  TCNT1 = 0;              // обнуляем таймер
  OCR1A = delay_HIGH;     // заггружаем стартовую длительность сигнала "STEP"
  movementDone = false;   // включаем флаг перемещения каретки
  TIMER1_INTERRUPTS_ON    // включаем флаг разрешения прерывания для "TIMER1"
}
//*********************************************************************
                  void SET_input_data() // Analysis_input_data
//**********************************************************************
{
// ---------------------------------------------------------------------------------------------------
// определяем тип введенного G-кода  
// ---------------------------------------------------------------------------------------------------
    if ( START_Chain_Segment == true ){ // если введен цепочный G-код
    
        set_MODE_Segment() ;            // определяем параметры режима движения,
        Calculation_Delta_Move() ;      // определяем число щагов перемещения в очередном сегменте вводимой цепочки
        
// ---------------------------------------------------------------------------------------------------
// проверяем получение первого сегмента  цепочки  
// ---------------------------------------------------------------------------------------------------
       if ( input_count_buf == 0 )                         { STATUS_MODE_Segment = true ; }  // если введен первый сегмент цепочки, то выставляем флаг совпадения режима сегмента
       else {                                                                                // если введен НЕ первый сегмент цепочки, то проверяем совпадение введенного G-кода сегмента   
           if ( current_G_code       != input_G_code       ){ STATUS_MODE_Segment = false ; } // если типы G-кодов сегментов НЕ совпадают, то сбрасываем флаг совпадения режима сегмента
           if ( current_MODE_Segment != input_MODE_Segment ){ STATUS_MODE_Segment = false ; } // если направление перемещения каретки НЕ совпадает, то сбрасываем флаг совпадения режима сегмента
           }
       }
// ---------------------------------------------------------------------------------------------------
// если введен НЕ цепочный G-код
// ---------------------------------------------------------------------------------------------------
    else {  STATUS_MODE_Segment = false ; } // сбрасываем флаг совпадения режима сегмента
    
// ---------------------------------------------------------------------------------------------------
// обрабатываем результат анализа введенного G-кода 
// ---------------------------------------------------------------------------------------------------
    
// ---------------------------------------------------------------------------------------------------
// проверяем обрыв цепочки   
// ---------------------------------------------------------------------------------------------------
    if ( STATUS_MODE_Segment == true ){                     // если цепочка НЕ оборвалась, то
        Delta_Move = Delta_Move + input_Delta_Move ;        // определяем общее число щагов перемещения в цепочке 
        SAVE_input_data() ;                                 // сохраняем расчитанные параметры для введенного сегмента
        if ( input_count_buf == 0 ){process_input_data(); } // если введен первый сегмент цепочки, то запускаем перемещение каретки
    }                                                       // 
    else {                                                  // если цепочка оборвалась, то 
        input_count_buf = 0 ;                               // сбрасываем счетчик входного буфера
        if ( START_Chain_Segment == true ){                 // если цепочка оборвалась другой цепочкой, то
            START_New_Chain = true ; }                      // выставляем флаг старта новой цепочки
        else {                                              // если цепочка оборвалась НЕ вводом G-кода другой цепочки , то
        // ждем окончания движения каретки и выполняем полученую команду  G-кода  
          ready();                                          // посылаем запрос на новый G-код программы для отладки
      }              
    }
}    

//********************************************************
                  void process_input_data()
//*********************************************************
{
   StopStep_X = true; StopStep_Y = true; // разрешаем движение по осям "X" и "Y"
  
   count_    = 0;         //
   stepCount = 0;         // обнуляем счетчик шагов ускорения 
   count_buf = 0 ;        // обнуляем счетчик буфера
   count_a = 0;           // обнуляем счетчик шагов перемещения по ОСИ "X"
   
   Delta_Move          = input_Delta_Move ;   // определяем общее число щагов перемещения в цепочке
   current_G_code       = input_G_code ;       // устанавливаем текущий тип G-кода 
   current_MODE_Segment = input_MODE_Segment ; // устанавливаем текущее направление перемещения каретки 
            
   do { moveToPosition() ; } // 
   while( Delta_Move > 0 ) ; // 

}

//*************************************************************
                  void set_MODE_Segment()
//**************************************************************
{
    input_Pos_X = input_X * step_for_X; // преобразуем входные данные в шаги для коорлинаты "X"
    input_Pos_Y = input_Y * step_for_Y; // преобразуем входные данные в шаги для коорлинаты "Y"
    
    if ( input_count_buf == 0 ){ 
        input_delta_X = input_Pos_X - current_Pos_X ; 
        input_delta_Y = input_Pos_Y - current_Pos_Y ; } //
    else { 
        input_delta_X = input_Pos_X - temp_Pos_X ;   
        input_delta_Y = input_Pos_Y - temp_Pos_Y ; }

    if (input_delta_X == 0 && input_delta_Y < 0)  input_MODE_Segment = 1; //   0-
    if (input_delta_X == 0 && input_delta_Y > 0)  input_MODE_Segment = 2; //   0+
    if (input_delta_X < 0  && input_delta_Y == 0) input_MODE_Segment = 3; //   -0
    if (input_delta_X > 0  && input_delta_Y == 0) input_MODE_Segment = 4; //   +0

    temp_Xa    = input_X ; // 
    temp_Ya    = input_Y ; // 
  
    temp_Pos_X = input_Pos_X ; //
    temp_Pos_Y = input_Pos_Y ; //

}

// ******************************************************
                        void Calculation_Delta_Move() 
// *******************************************************
{           
    if ( input_delta_X == 0 ){ input_Delta_Move = abs(input_delta_Y) ; } // 
    else                     { input_Delta_Move = abs(input_delta_X) ; } // 
}

//*******************************************************
                  void SAVE_input_data()
//********************************************************
{         
    buf_Delta_Move[input_count_buf]    = input_Delta_Move ;   // запоминаем длину сегмента
    
    transfer_permission = true ;                              // разрешаем передачу запроса на новый G-код
}  

//********************************************************
                  void moveToPosition () //
//********************************************************
{

    Delta_Move_Segment = buf_Delta_Move[count_buf] ;   // 

    switch ( current_MODE_Segment ) 
      {
// ----------------------------------------------------------------------------------------------------
    case 1: // ДЛЯ перемещения только по оси "Y" DeltaPos_X == 0 && DeltaPos_Y < 0  "dir_X=0" "dir_Y =-1"
// ----------------------------------------------------------------------------------------------------
            current_dir_X = 0 ; current_dir_Y = -1 ; //  
            digitalWrite(X_DIR_PIN, LOW) ; digitalWrite(Y_DIR_PIN, HIGH) ; break; // 
// ----------------------------------------------------------------------------------------------------
    case 2: // ДЛЯ перемещения только по оси "Y" DeltaPos_X == 0 && DeltaPos_Y > 0  "dir_X=0" "dir_Y =+1"
// ----------------------------------------------------------------------------------------------------
            current_dir_X = 0 ; current_dir_Y = 1 ; //  
            digitalWrite(X_DIR_PIN, HIGH); digitalWrite(Y_DIR_PIN, LOW) ; break; // 
// ----------------------------------------------------------------------------------------------------
    case 3: // ДЛЯ перемещения только по оси "-X" DeltaPos_X < 0 && DeltaPos_Y == 0  "dir_X=-1" "dir_Y =0"
// ----------------------------------------------------------------------------------------------------
            current_dir_X = -1 ; current_dir_Y = 0 ; //   
            digitalWrite(X_DIR_PIN, LOW) ; digitalWrite(Y_DIR_PIN, LOW) ; break;// 
// ----------------------------------------------------------------------------------------------------
    case 4: // ДЛЯ перемещения только по оси "+X" DeltaPos_X > 0 && DeltaPos_Y == 0   "dir_X=+1" "dir_Y =0"
// ----------------------------------------------------------------------------------------------------
            current_dir_X = 1 ; current_dir_Y = 0 ; //  
            digitalWrite(X_DIR_PIN, HIGH); digitalWrite(Y_DIR_PIN, HIGH); break;// 

}

  moveNSteps();// 

  while ( movementDone == false ){        // 
  
      if ( transfer_permission == true ){ // если разрешен запрос на новый G-код, то
      
          input_count_buf++ ;             // увеличиваем счетчик входного буфура, 
          transfer_permission = false ;   // сбрасываем флаг на разрешенние запроса нового G-кода программы
          ready();                        // посылаем запрос на новый G-код программы и  
        
      } 
          Serial_Report();                // 
  } 

  if ( Delta_Move_Segment == count_a ){      // если закончился очережной сегмент

      current_Pos_X = current_Pos_X + current_dir_X * count_a ; // запоминаем значение новой текущей координаты по оси "X"
      current_Pos_Y = current_Pos_Y + current_dir_Y * count_a ; // запоминаем значение новой текущей координаты по оси "Y"
        
      count_a = 0 ;  //
      count_buf ++ ; //
     }

  if ( Delta_Move == 0 ){               // если закончилась вся цепочка сегментов

      if ( START_New_Chain == true ){   // 
          START_New_Chain     = false ; //
          STATUS_MODE_Segment = true ;  // выставлем флаг совпадения G-кодов
          set_MODE_Segment() ;          // определяем параметры режима движения,
          Calculation_Delta_Move() ;    // определяем число щагов перемещения в очередном сегменте вводимой цепочки
          SAVE_input_data() ;           // сохраняем рассчитанные параметры введенного сегмента
          process_input_data() ; }      //  
      else    {ready(); }               // посылаем запрос на новый G-код программы и 
         }
 } 


  

//*******************************************************************
         void Calculation_max_count_Acceleration_()  // 
//********************************************************************

{
  
  float dd = delay_HIGH ;          // 
  
  do {  
     dd = delay_HIGH * (sqrt(count_Acceler + 1) - sqrt(count_Acceler) ) ;
   
     int dd_ = dd;                    //
     delay_H[count_Acceler] = dd_ ;   //    
     count_Acceler++ ;
  }
  while (abs(dd) >= delay_min);       //
  
  max_count_Acceleration = count_Acceler - 1 ; //  
  
}


// ******************************************************
                  void processCommand() 
// *******************************************************
/*
 * Read the input buffer and find any recognized commands.  One G or M command per line.
 */
{
  cmd = parsenumber('G',-1);

  switch(cmd)  {
    
    case  0: input_G_code = 0 ;   break; // "G0" 
    case  1: input_G_code = 1 ;   break; // "G1"  
 }

 }
 

// ***************************************************
                  void ready() 
// ****************************************************
/*
 * prepares the input buffer to receive a new message and tells the serial connected device it is ready for more.
 */
{

  sofar=0 ;               // clear input buffer
  Serial.print(F(">")) ;  // signal ready to receive input
}    


// *******************************************************
                  float parsenumber(char code,float val) 
// ********************************************************
/**
 * Look for character /code/ in the buffer and read the float that immediately follows it.
 * @return the value found.  If nothing is found, /val/ is returned.
 * @input code the character to look for.
 * @input val the return value if /code/ is not found.
 **/
 
{
  char *ptr = buffer;
  while(ptr && *ptr && ptr < buffer + sofar) 
  {
    if(*ptr == code) {return atof(ptr+1);}
    ptr = strchr(ptr,' ')+1;
  }
  return val;
} 

//************************************************************
                  void Serial_Report () 
//************************************************************
{

    while ( Serial.available() > 0) {               // пока в буфере приема есть принятый байт, то
       char c = Serial.read();                      // считываем его в переменную "char c"
       Serial.print(c);                             // и возвращаем запомненный код обратно в компьютер 
       if ( sofar < MAX_BUF-1 ){                    // если счетчик принятых байтов меньше глубины программного буфера приема, то
           buffer[sofar++] = c ; }                  // запоминаем принятый байт в программном буфере приема, и увеличиваем счетчик принятых байтов  
       if ( c == '\n' ) {                           // если принятого байта кода конца строки G-кода ('\n'), то
           buffer[sofar] = 0 ;                      // в программном буфере приема запоминаем байт "00h", и
           processCommand() ;                       // определяем тип принятого G-кода 

           if ( input_G_code == 0 || input_G_code == 1 ){       // если введен цепочный G-код, то     
           
               START_Chain_Segment = true ;                     // выставлем флаг приема данных цепочки сегментов
               input_X = parsenumber('X',temp_Xa) ;             // фиксируем введенную координату "оси X"
               input_Y = parsenumber('Y',temp_Ya) ;             // фиксируем введенную координату "оси Y"

               if ( input_X == temp_Xa && input_Y == temp_Ya ){ // если введенные координаты соответствуют текущим координатам, то 
                   ready(); }                                   // посылаем запрос на введение следующего G-кода
               else {                                           // если введенные координаты НЕ соответствуют, то 
                   SET_input_data() ; } }                       // обрабатываем данные введенного G-кода
           else {                                               // если введен НЕ цепочный G-код, то
               START_Chain_Segment = false ;                    // сбрасываем флаг приема данных цепочки сегментов, и 
               SET_input_data() ; }                             // обрабатываем данные введенного G-кода
    }
  }  
}


//**************************************************************
                  void setup() 
//***************************************************************
{

  pinMode(X_STEP_PIN,   OUTPUT);
  pinMode(X_DIR_PIN,    OUTPUT);
  pinMode(X_ENAB_PIN,   OUTPUT);
  
  pinMode(Y_STEP_PIN,   OUTPUT);
  pinMode(Y_DIR_PIN,    OUTPUT);
  pinMode(Y_ENAB_PIN,   OUTPUT);
  
   current_dir_X = 0 ; 
   current_dir_Y = 0 ; 
  
  noInterrupts();
  
  TCCR1A = 0;                               // 
  TCCR1B = 0;                               // 
  TCNT1  = 0;                               // 
  
  OCR1A = delay_HIGH;                       // 
  TCCR1B |= (1 << WGM12);                   // 
  TCCR1B |= ((1 << CS11) | (1 << CS10));    //    
  
  interrupts();
  
  movementDone = true ;    // выставляем флаг отсутствия движениия

  Serial.begin(57600);    //
  
  Calculation_max_count_Acceleration_();   // создаем массив задержек для разгона и торможения

  ready();  // отсылаем в комп ">" (тут это как код готовности)

}
//*************************************************************
                  void loop() 
//**************************************************************
{
  
      Serial_Report ();
      
}  

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ОК. Завтра посмотрю.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Я еще не компилировал, сорри.

У меня пес приболел - к вету поеду.

НО! Я посмотрел - все проблеммы в том (ИМХО), что ты не останавливаешь таймер.

Вместо TIMER1_INTERRUPTS on  и off - напиши одновременные пуск и останов в этот макрос.

вот так ON

#define TIMER1_INTERRUPTS_ON    {TCCR1B |= ((1 << CS11) | (1 << CS10)); TIMSK1 |=  (1 << OCIE1A);}

 

вот так OFF

#define TIMER1_INTERRUPTS_OFF    {TCCR1B &= ~((1 << CS11) | (1 << CS10)); TIMSK1 &=  ~(1 << OCIE1A);}

Сорри, проверять не было времени. Возможно еще что-то добавить нужно.

И укажи, плз, тестовый пример, на котором неравномерность проявляется. Чтобы я не угадывал, как и куда этот пример подать.

ALEGYR
Offline
Зарегистрирован: 20.09.2018

wdrakula пишет:

Вместо TIMER1_INTERRUPTS on  и off - напиши одновременные пуск и останов в этот макрос.

вот так ON

#define TIMER1_INTERRUPTS_ON    {TCCR1B |= ((1 << CS11) | (1 << CS10)); TIMSK1 |=  (1 << OCIE1A);}

вот так OFF

#define TIMER1_INTERRUPTS_OFF    {TCCR1B &= ~((1 << CS11) | (1 << CS10)); TIMSK1 &=  ~(1 << OCIE1A);}

изменил в программе строки   #define TIMER1_INTERRUPTS_ON и #define TIMER1_INTERRUPTS_OFF

//#define TIMER1_INTERRUPTS_ON    TIMSK1 |=  (1 << OCIE1A);
//#define TIMER1_INTERRUPTS_OFF   TIMSK1 &= ~(1 << OCIE1A);

#define TIMER1_INTERRUPTS_ON    {TCCR1B |= ((1 << CS11) | (1 << CS10)); TIMSK1 |=  (1 << OCIE1A);}
#define TIMER1_INTERRUPTS_OFF   {TCCR1B &= ~((1 << CS11) | (1 << CS10)); TIMSK1 &=  ~(1 << OCIE1A);}

проблема осталась!

wdrakula пишет:

И укажи, плз, тестовый пример, на котором неравномерность проявляется. Чтобы я не угадывал, как и куда этот пример подать.

примером использую текстовый файл

Цитата:

G0 X0.000 Y10.000
G0 X0.000 Y20.000
G0 X0.000 Y30.000
G0 X0.000 Y40.000
G0 X0.000 Y50.000
G0 X50.000 Y50.000 
G0 X50.000 Y0.000
G0 X0.000 Y0.000
 
G0 X0.000 Y50.000
G0 X10.000 Y50.000
G0 X15.000 Y50.000
G0 X20.000 Y50.000
G0 X25.000 Y50.000
G0 X30.000 Y50.000
G0 X35.000 Y50.000
G0 X40.000 Y50.000
G0 X45.000 Y50.000
G0 X50.000 Y50.000 
G0 X50.000 Y0.000
G0 X0.000 Y0.000
 
G0 X0.000 Y50.000
G0 X50.000 Y50.000 
G0 X50.000 Y0.000
G0 X0.000 Y0.000
 
G0 X0.000 Y50.000
G0 X50.000 Y50.000 
G0 X50.000 Y0.000
G0 X0.000 Y0.000
 
В нем происходит движение по квадрату 50х50 мм.
на первом квадрате, одна сторона по оси "Y" разбита на 5 сегментов по 10 мм
на втором квадрате, одна сторона по оси "Х"разбита на 10 сегментов по 5 мм
на третьем и четвертом квадратах двидение происходит без разбития на сегменты, то есть происходит движение по квадрату 50х50 мм
 
Для связи с компом использую GcodeSender, в файле README, которого написано 
Цитата:
 
#GcodeSender
 
This program will feed instructions to an serial device one line at a time.
It waits for the ">" character between each send.
 
#
 
# I just want to run it!
 
./java/GcodeSender.jar is compiled and should run.
 
On most systems you can double click it to start.
 
On some you may need to do something like
 
    java -classpath RXTXcomm.jar -Djava.library.path=[path to RXTXcomm.jar] -jar DrawbotGUI.jar
 
#
 
#Drivers
 
Need Arduino code that reads GCode and moves motors?  Try https://github.com/MarginallyClever/gcodecncdemo
 
#
 
#More
 
For the latest version please visit http://www.github.com/MarginallyClever/GcodeSender
 
If you find this free program useful, please send me some beer money.
 
#
 
#Author
 
Dan Royer
2014-01-29
 
 
 
wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Времени катастрофически мало. Работа по дому срочная... Сорри.

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

То есть ясно, что в моменте стыковки команд возникает неравномерность шага... но в каком месте - это тайна. ;) в коде, представленном мне, даже шаги разгона-торможения вычисляются неверно., тип команды всегда один и пр. и пр. Посмотри на массив delay_H! ;)

Посмотри на то, как и где он вообще используется!! Распечатай его.

-------------------

Давай я тебя попрошу о следующем:

Напиши на русском языке, что код должен делать, в каком виде принимать команды, какой у команд синтаксис? Пока ограничимся только командами движения.

Зачем ты хочешь отслеживать цепочки? Почему эту работу не отдать отпимизатору G-кода, а не станку? Команда перемещения - это разгон+движение+торможение. Если два перемещения состыкованы, то какие случаи станок должен (по твоему мнению) должен отслеживать?

------------------

Может попробовать сперва на одной оси -X? для отладки? Напиши словами - какую идею ты хочешь отладить?