Объясните метаморфозу с обработкой прерывания
- Войдите на сайт для отправки комментариев
Есть подпрограмма обработки прерывания
//***********************************************************
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 - Почему увеличение времени работы подпрограммы обработки прерывания убирает обрывы во временной диаграмме?
Боюсь, что по этому фрагменту ничего не определеить.
Совершенно непонятно, как строка "G1 X50.00" превращается в указания драйверу, нет описания переменных, ну и т.д.
Нужен полный код )
попробуй выделить отдельный компилируемы и загружаемый код, иллюстрирующий проблемму.
Например я загружу, посмотрю на осцилографе и подумаю, где ошибка.
Пока кажется, что ошибке в непредставленной части кода.
Вангую: где-то в прерываниях беснуются переменные, объявленные без volatile.
Боюсь, что по этому фрагменту ничего не определеить.
Совершенно непонятно, как строка "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-кода } } }прерывание задается операторами
попробуй выделить отдельный компилируемы и загружаемый код, иллюстрирующий проблемму.
Это как?
Вангую: где-то в прерываниях беснуются переменные, объявленные без volatile.
Волатильными у меня объявлены
попробуй выделить отдельный компилируемы и загружаемый код, иллюстрирующий проблемму.
Это как?
Это написать маленькую программу, на основе большой, которую можно тут опубликовать (по размеру) и в которой происходит тоже самое.
ALEGYR, в идеале все операции с 16-битными регистрами таймеров нужно выполнять при выключенном таймере. Попробуйте для эксперимента перед 19 строчкой остановить а после 20-й запустить таймер.
Это написать маленькую программу, на основе большой, которую можно тут опубликовать (по размеру) и в которой происходит тоже самое.
Мужики, вы меня ставите в тупик!
Одному нужен полный код, а другому "маленькую программу, на основе большой".
У меня в обоих вариантах заданых перемещений меняется только ОДНА 26 строка в подпрограмме обработки прерывания
ISR(TIMER1_COMPA_vect)и больше я нигде и ничего во всей программе не изменияю!ALEGYR, в идеале все операции с 16-битными регистрами таймеров нужно выполнять при выключенном таймере. Попробуйте для эксперимента перед 19 строчкой остановить а после 20-й запустить таймер.
Я не знаю как (чем) его остановить! :(
Мужики, вы меня ставите в тупик!
Одному нужен полный код, а другому "маленькую программу, на основе большой".
Смотри: я прошу что-то ВМЕСТО полного кода. Повтори ошибку выкинув неважное, экран, кнопки и прочее.
Просто законченная программа, которую можно запустить на Меге. Вместо драйвера ШД, можно будет просто посмотреть осликом или логаналайзером на ногу СТЕП.
Часто новичек сам находит ошибку, готовя тестовый пример, но если ошибка сохранится - посмотрим.
Скорее всего трабл в том, что ты не останавливаешь тайме, а только запрещаешь прерывания... но нужно тестить.
Я не знаю как (чем) его остановить! :(
Ну блии-ин! Это не серьезно! Даташит читай... как ты иначе хочешь разговора?
Смотри: я прошу что-то ВМЕСТО полного кода. Повтори ошибку выкинув неважное, экран, кнопки и прочее.
А у меня в полном коде и нет ни кнопок, ни экрана, используется только СОМ порт.
Просто законченная программа, которую можно запустить на Меге. Вместо драйвера ШД, можно будет просто посмотреть осликом или логаналайзером на ногу СТЕП.
Я могу скинуть экран с логаналайзера Saleae Logic 1.1.15. Там у меня и СТЕПЫ и ДИРЫ и RX и ТX
Вангую: где-то в прерываниях беснуются переменные, объявленные без volatile.
Волатильными у меня объявлены
Тут не все переменные, которые используются в прерывании. С остальными, что?
Я могу скинуть экран с логаналайзера Saleae Logic 1.1.15. Там у меня и СТЕПЫ и ДИРЫ и RX и ТX
Дорогой! Будь, плз, внимательным. Я верю тому, что ты написал, мне твоих логов не нужно.
Мне нужно увидеть такую же ошибку на своей плате, у себя в мастерской. Твой полный код для этого не годится, потому, что он связан с твоим железом. Нужно сделать независимый от железа код, для голой Меги 2560, но с тем же поведением. Это возможно, потому, что непонятное поведение в серии прерываний таймера, а не в железоспецифичной части кода.
У себя мне это нужно, потому, что я сделаю кучу отладочных принтов, посмотрю то, о чем сейчас не думаю.
Тебе нужна помощь - я пишу как ее получить, а ты начинаешь торговаться...
прерывание задается операторами
ведь останавливал же и запускал, но судя по отсутствию комментариев код скопипастен и не осознан.
Вангую: где-то в прерываниях беснуются переменные, объявленные без volatile.
Волатильными у меня объявлены
Тут не все переменные, которые используются в прерывании. С остальными, что?
Остальные выглядят так -
Вам кажется прикольным использовать эти переменные в обработчике? Фигли тогда жалуетесь?
Мне нужно увидеть такую же ошибку на своей плате, у себя в мастерской. Твой полный код для этого не годится, потому, что он связан с твоим железом. Нужно сделать независимый от железа код, для голой Меги 2560, но с тем же поведением. Это возможно, потому, что непонятное поведение в серии прерываний таймера, а не в железоспецифичной части кода.
У себя мне это нужно, потому, что я сделаю кучу отладочных принтов, посмотрю то, о чем сейчас не думаю.
Тебе нужна помощь - я пишу как ее получить, а ты начинаешь торговаться...
Для меня не проблема выставить тут всю программу! Для меня проблема отредактивровать ее под ТВОЕ железо!
Вам кажется прикольным использовать эти переменные в обработчике? Фигли тогда жалуетесь?
А разве я жалуюсь?! Я просто задал два вопроса
1- Откуда у этой метаморфозы ноги растут?
2 - Почему увеличение времени работы подпрограммы обработки прерывания убирает обрывы во временной диаграмме?
и попросил их мне объяснить.
А что касается прикольного использования переменных, то я еще нахожусь в начальной школе, и всех правил правописания не освоил.
Остальные выглядят так -
Если переменные используются внутри обработчика прерываний - где volatile?
Первое правило правописания должно быть таково, что все переменные, которые используются в обработчике, должны быть volatile.
прерывание задается операторами
ведь останавливал же и запускал, но судя по отсутствию комментариев код скопипастен и не осознан.
исходником была программа
#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); } ее и адаптировал под сябяЕсли переменные используются внутри обработчика прерываний - где volatile?
Так они точно также используются и с delayMicroseconds(200) ; (26 строкой в первом сообщении темы) и без нее. Я же их никак не меняю, а вот результаты получаю разные!!! ПОЧЕМУ?
Я же их никак не меняю, а вот результаты получаю разные!!! ПОЧЕМУ?
Это называется оптимизация. "Некогда объяснять, но..." ;)
--------------
Под какое "мое железо"? Я тебе написал: сделай пример просто под 2650, под голую. Я запущу у себя в мастерской и точно скажу - волатиль тут или неправильная работа с таймером.
--------------
волатиль просто проверь - поставь и пересобери.
Первое правило правописания должно быть таково, что все переменные, которые используются в обработчике, должны быть volatile.
Не проблема! Сейчас поставлю все volatile и проверю.
Не проблема! Сейчас поставлю все volatile и проверю.
Результат ОТРИЦАТЕЛЬНЫЙ!!!
Анализа на сифилис?
Помнится, я как-то словил странный стук на шаговике... Оказалось, что сам дурак - написал алгоритм так, что при иногда один шаг отличался от другого на 1 мс. Шаговик кряхтел при некоторых обстоятельствах, как предпенсионер.
Анализа на сифилис?
Анализа на правильное правописание переменных в подпрограмме обработки прерыванний.
Поставил на все оставшиеся переменные указатель volatile, но тарахтение не прошло. Вставляю задержку delayMicroseconds(200) ; и все идет тихо и гладко!
Помнится, я как-то словил странный стук на шаговике... Оказалось, что сам дурак - написал алгоритм так, что при определенных обстоятельствах один шаг отличался от другого на 1 мс. Шаговик кряхтел при некоторых обстоятельствах, как предпенсионер.
У меня шаги при разгоне и торможении меняются в 5 раз от стартовых 1-3 милисекунд и до выхода на скорость 20-60 микросекунд, и никаких посторонних звуков не происходит. Тарахтение происходит только если прямое перемещение разбито на отрезки и в подпрограмме обработки прерывания отсутствует задержка при выходе из режима прерывания.
if ( Delta_Move_Segment == count_a ){ //|| Delta_Move == 0 ){ // movementDone = true; // вычтавляем флаг окончания движения TIMER1_INTERRUPTS_OFF // запрещаем прерывания таймера //delayMicroseconds(200) ; // }Ребята, я не в курсе, на меге delayMicroseconds(200) в прерывании работает?
delayMicroseconds() работает, delay() не работает. millis() и micros() стоят, как у Мавзолея.
У меня шаги при разгоне и торможении меняются в 5 раз от стартовых 1-3 милисекунд и до выхода на скорость 20-60 микросекунд, и никаких посторонних звуков не происходит. Тарахтение происходит только если прямое перемещение разбито на отрезки и в подпрограмме обработки прерывания отсутствует задержка при выходе из
Если последовательно увеличивается, то мож и ничего, а у меня на прямом ходе флапало и тарахтело. Тоже сначала ничего не понимал, потом вывел миллисы в сериал...
Задержка в прерывании -- это почище гвоздя в сапоге. Никаких задержек в обработчике быть не должно в принципе.
Так, если все еще чего-то хочешь - готовь программу... в крайнем случае, хер с тобой, выложи как есть. Еще проведи эксперимент - 200 мкс лечат, а 100? а 50?... короче, понял, да?
На все про все, повторюсь, если это тебе надо, у тебя - день. Завтра шабат и я заниматься херней не буду.
Всем Шабат шалом, в этом чате! ;) ;) ;)
Если последовательно увеличивается, то мож и ничего, а у меня на прямом ходе флапало и тарахтело. Тоже сначала ничего не понимал, потом вывел миллисы в сериал...
Что такое "флапало" и "вывел миллисы в сериал" ?
Если последовательно увеличивается, то мож и ничего, а у меня на прямом ходе флапало и тарахтело. Тоже сначала ничего не понимал, потом вывел миллисы в сериал...
Что такое "флапало" и "вывел миллисы в сериал" ?
1) от англ. flap — махать, хлопать. Т.е. междушаговый интервал был то N, то N+1 мс.
2) Serial.println(millis()-stepStartTime); В обработчике прерывания наврядли такой способ поможет. Я просто поделился опытом - рокот и стук был из-за неравномерности шага. Может вы своим delayMicroseconds() его выравниваете и таинственный стук пропадает.
Задержка в прерывании -- это почище гвоздя в сапоге. Никаких задержек в обработчике быть не должно в принципе.
Так ее там вроде как и нет! Задержка используется только ОДИН раз за все перемещение по сегменту, и только после запрета прерывания по таймеру!!!
Ее в изначальном варианте не было. Я ее ввел только тогда, когда стал разбираться с тарахтением.
Так, если все еще чего-то хочешь - готовь программу...
То что мне надо я написал в своем первом сообщении!
Объясните пожалуйста
1 - Откуда у этой метаморфозы ноги растут?
2 - Почему увеличение времени работы подпрограммы обработки прерывания убирает обрывы во временной диаграмме?
А что касается
в крайнем случае, хер с тобой, выложи как есть. Еще проведи эксперимент - 200 мкс лечат, а 100? а 50?... короче, понял, да?
то на 50 тарахтит, а на 100, 200, 300 уже не тарахтит!
1) от англ. flap — махать, хлопать. Т.е. междушаговый интервал был то N, то N+1 мс.
2) Serial.println(millis()-stepStartTime); В обработчике прерывания наврядли такой способ поможет. Я просто поделился опытом - рокот и стук был из-за неравномерности шага. Может вы своим delayMicroseconds() его выравниваете и таинственный стук пропадает.
Это на каком движке надо было шагать с междушаговым интервалом от N, то N+1 мс ?
Мои nema 17 на междушаговом интервале в 1-2 мс просто стартуют и останавливаются
На неме и рокотало.
Вы хотите, чтобы я назвал вам точные цифры? Уверены, что наши немы эквивалентны, драйверы и блоки питания одинаковы на 100% и эффект повторится? Я указал на возможную причину. Можете проверять ее или просто игнорировать - дело ваше.
На неме и рокотало.
Вы хотите, чтобы я назвал вам точные цифры?
Нет не хочу! Я хочу сказать, что с 1-2 милисекунд движок стартует из полного покоя, и успевает остановится если он вращался. Все что будет дольше, вынуждает вращаться шаговый движок как-бы в режиме СТАРТ-СТОП, и это сопровождается характерным рокотом или тарахтением. А если при этом, на каждом шаге, еще и переключался сигнал ENABLE, то звук будет еще заметнее, за счет постоянного включения и выключения выходного каскада драйвера.
У шагового двигателя нет старта или стопа. Вал просто перескакивает между обмотками (или зависает между ними при микрошаге) в случае подачи импульса на вход STEP драйвера. Чтобы изучить (изучить) истинные причины рокота необходимы целенаправленные и практически лабораторные исследования. Таковых я не проводил. Наблюдением поделился. Используйте его, если пожелаете.
Зачем Enable дергать на каждом шаге - не представляю на данный момент.
У шагового двигателя нет старта или стопа.
...
Зачем Enable дергать на каждом шаге - не представляю на данный момент.
я писал
как-бы в режиме СТАРТ-СТОП,
а что касается сигнала "Enable", то в некоторых скетчах, его используют не на все время движения, а на каждый сегмент движения. Зачем это делают я не понимаю, но люди это используют.
Так, если все еще чего-то хочешь - готовь программу... в крайнем случае, хер с тобой, выложи как есть.
Выкладываю то что получилось. Это все проверено на моем железе
// ****************************************************** #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 (); }ОК. Завтра посмотрю.
Я еще не компилировал, сорри.
У меня пес приболел - к вету поеду.
НО! Я посмотрел - все проблеммы в том (ИМХО), что ты не останавливаешь таймер.
Вместо 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);}Сорри, проверять не было времени. Возможно еще что-то добавить нужно.
И укажи, плз, тестовый пример, на котором неравномерность проявляется. Чтобы я не угадывал, как и куда этот пример подать.
Вместо 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);}проблема осталась!
И укажи, плз, тестовый пример, на котором неравномерность проявляется. Чтобы я не угадывал, как и куда этот пример подать.
примером использую текстовый файл
Времени катастрофически мало. Работа по дому срочная... Сорри.
Но: в программе такое количество ляпов и ошибок, что прости, но я устал пытаться понять, как она разбирает команды.
То есть ясно, что в моменте стыковки команд возникает неравномерность шага... но в каком месте - это тайна. ;) в коде, представленном мне, даже шаги разгона-торможения вычисляются неверно., тип команды всегда один и пр. и пр. Посмотри на массив delay_H! ;)
Посмотри на то, как и где он вообще используется!! Распечатай его.
-------------------
Давай я тебя попрошу о следующем:
Напиши на русском языке, что код должен делать, в каком виде принимать команды, какой у команд синтаксис? Пока ограничимся только командами движения.
Зачем ты хочешь отслеживать цепочки? Почему эту работу не отдать отпимизатору G-кода, а не станку? Команда перемещения - это разгон+движение+торможение. Если два перемещения состыкованы, то какие случаи станок должен (по твоему мнению) должен отслеживать?
------------------
Может попробовать сперва на одной оси -X? для отладки? Напиши словами - какую идею ты хочешь отладить?