Несогласованное время в цикле arduino
У меня есть этот код:
Вывод выглядит следующим образом:
Почему непериодически появляются очень большие значения?
Спасибо
@Dominik Jašek, 👍-1
Обсуждение3 ответа
Существует несколько «задач» и прерываний, которые выполняются в фоновом режиме и влияют на частоту вызова функции loop().
Например, таймер, usart...
Все они время от времени требуют внимания. Если вам нужно действительно фиксированное время выполнения, вы должны использовать что-то вроде аппаратного таймера.
и кстати: максимум ~1.1мс неплохо для такого маленького контроллера. :-)
И в дополнение к вашему вопросу в ваших комментариях: я не думаю, что есть способ ускорить цикл. Пока вам нужны другие задачи, вы должны дать им некоторое время.
Спасибо Sealion! Кроме того, исходная проблема для этого вопроса заключалась в том, что я управляю шаговым двигателем, и мне нужно общаться с Raspberry Pi с помощью UART. Проблема в том, что когда я отправляю какие-то данные о двигателе в RPi, а двигатель уже вращается очень быстро, я часто теряю шаг из-за слишком большой задержки. У вас есть идеи, как это решить?, @Dominik Jašek
Я не знаю, как реализована библиотека шаговых двигателей arduino и почему вы теряете шаги, но в целом: Убедитесь, что вы не используете ожидания занятости. Особенно, когда вы общаетесь с Rapsberry (не ждите, пока персонажи станут доступны)., @theSealion
Хорошо, я все еще выясняю причину потери шагов и, кажется, нашел ее. Я думаю, что это не имеет ничего общего с Serial.print. Я хотел бы запустить степпер со скоростью 3000 шагов в секунду. Это означает один импульс каждые 333,3 микросекунды. И, очевидно, когда есть задержка ~ 1,1 мс, это слишком большая задержка, чтобы не потерять шаг. Кстати, я использую библиотеку AccelStepper. Есть ли возможность разобраться в этом, @Dominik Jašek
Я не понимаю, что "максимум ~ 1,1 мс - это неплохо", @Juraj
Как объяснил theSealion в своем ответе, это может быть связано с различные фоновые задачи, выполняемые микроконтроллером. Однако я лично считаю, что 1 мс выглядит чрезмерным. Я предполагаю, что главный виновник — стек USB, передающий все эти байты по проводу.
Чтобы проверить это, я написал следующую программу. Он измеряет гистограмму времени выполнения цикла, а затем распечатывает ее через Серийный порт. Поскольку данные распечатываются только после измерения сделано, последовательный порт не выполняет никакой работы, пока тайминги измерено.
const int HISTOGRAM_LENGTH = 512;
uint16_t histogram[HISTOGRAM_LENGTH];
void print_histogram() {
Serial.println(F("t (us) count"));
Serial.println(F("-------------"));
for (int i = 0; i < HISTOGRAM_LENGTH; i++) {
if (histogram[i] == 0) continue; // пропустить нули
Serial.print(i * 4);
Serial.print('\t');
Serial.println(histogram[i]);
}
Serial.println(F("-------------"));
Serial.flush();
}
void setup() {
Serial.begin(9600);
}
void loop() {
static uint32_t last_time;
uint32_t now = micros();
uint32_t dt = now - last_time;
uint32_t bin = dt / 4; // разрешение micros() равно 4 мкс
if (bin >= HISTOGRAM_LENGTH)
bin = HISTOGRAM_LENGTH - 1;
if (++histogram[bin] == UINT16_MAX) {
print_histogram();
exit(0);
}
last_time = now;
}
Вот результаты при запуске на Arduino Uno:
t (us) count
-------------
8 21888
12 65535
16 632
20 323
56 1
-------------
Это показывает, что большинство итераций цикла занимает 8–12 мкс. Эти итерации
которые были прерваны, заняло 16–20 мкс. Выброс на 56 мкс составляет
скорее всего время между запуском программы и самым первым
повторение loop()
.
Здесь единственным источником прерывания, влияющим на измерения, является прерывание по таймеру. Во время измерения он выстрелил ровно 955 раз. период, который согласуется с количеством отсчетов, записанных в 16–20 мкс. Из этих данных видно, что прерывание таймера занимает примерно 8 мкс, что вполне разумно. Опять же, я бы не считайте задержку в 1 мс разумной.
Кроме того, изначальная проблема этого вопроса заключалась в том, что я управляю шаговым двигателем, и мне нужно общаться с Raspberry Pi с помощью УАРТ. Проблема в том, что когда я отправляю некоторые данные о двигателе к RPi и мотор уже крутится очень быстро, я часто теряю шаг
Ваш код шагового двигателя должен работать очень стабильно, чтобы поддерживать скорость 3000 шагов в секунду без дрожания или пропуска шагов. Он не должен ждать связи или любой другой задачи, но должен быть в состоянии вовремя выдать команду следующего шага. Некоторые возможные методы для достижения этой цели:
- Не публикуйте сообщение целиком в Pi, а отправляйте только несколько символов за раз между этапами.
- Общайтесь с Pi более короткими, четко закодированными сообщениями и позвольте Pi расширить их, если это необходимо.
- Используйте максимальную скорость передачи данных Uno & Пи может надежно использовать.
- Выдавайте пошаговые команды в подпрограмме прерывания, управляемой таймером, при этом все операции пошагового управления выполняются в фоновом режиме между пошаговыми командами.
- Используйте более быстрый процессор.
- Программирование Arduino Micro через RX/TX
- Последовательный порт USB больше не обнаруживается после успешной загрузки
- Буфер чтения из программного обеспечения-Последовательный и запись в последовательный
- Есть ли способ использовать последовательный порт в качестве источника прерывания?
- Arduino Pro micro Serial communication проблема с узлом MCU
- Помогите с алгоритмом нажатия клавиш Arduino Micro.
- Как разделить входящую строку?
- Как вывести несколько переменных в строке?
Serial.println ожидает заполнения буфера TX. А ATmega32u4 обрабатывает порт USB в фоновом режиме., @Juraj
есть ли способ сделать это быстрее?, @Dominik Jašek
Пожалуйста, без кода в виде изображения. Скопируйте и вставьте код как текст и отформатируйте его с помощью кнопки
{}
, @chrisl