Выполнение последовательного действия в качестве прерывания
Я пытаюсь создать программу для управления шаговым двигателем с последовательными входами, и при написании функции для его запуска у меня возникают проблемы с пониманием того, как заставить последовательный вход остановить цикл, который запускает двигатель, не делая время на шаг несогласованным. Есть ли способ, чтобы новый последовательный ввод действовал как прерывание и прерывал любой выполняемый цикл.
void jog() {
if(input[1] == 0) sd.setDirection(0);
else sd.setDirection(1);
while(true){
if(Serial.available() > 0) break;
sd.step();
delayMicroseconds(10);
}
sd.setDirection(0);
}
Прямо сейчас у меня есть это (я использую библиотеку Pololu, которая определяет шаги), но по какой-то причине это ничего не делает или, по крайней мере, движется так медленно, что незаметно (один шаг перемещает двигатель только на 0,007 градуса). Он очень плавно перемещает двигатель, если я удаляю, если(Serial.available() > 0) сломается;>
но тогда я не могу его остановить.
void loop() {
getData();
switch(input[0]){
case 'r':
Serial.write('r');
ramp();
break;
case 'c':
Serial.write('c');
cycle();
break;
case 'j':
//Serial.write('j');
jog();
break;
default:
break;
}
}
void getData(){
if(Serial.available() > 0){
for(int i = 0; i < 200; i ++){
input[i] = 0;
}
for(int i = 0; i < Serial.available(); i++){
input[i] = Serial.read();
Serial.print(input[i]);
}
}
Serial.flush();
//Serial.print(input[0]);
}
Это соответствующий код, который вызывает jog()
@Bob Dave, 👍1
Обсуждение1 ответ
Как вы узнаете, что в последовательном буфере ничего нет, когда вы вводите функцию jog ()
? Вы не проверяете это.
Я думаю, что ваша проблема на самом деле в вашей функции getData ()
. Цикл for
for(int i = 0; i < Serial.available(); i++){
может сработать не так, как вы думаете, потому что i увеличивается на каждой итерации цикла, в то время как Serial.available()
уменьшается на каждой итерации. Таким образом, вы на самом деле читаете меньше данных, чем доступно в буфере. Например, предположим, что у вас есть 2 байта в буфере. Серийный.доступно()
возвращает 2. В первой итерации цикла для i
равно 0, в то время как Serial.available()
равно 2. При чтении из последовательного буфера в итерации значение Serial.available()
уменьшается до 1 (так как вы удалили один байт из буфера, прочитав его). В конце итерации цикл for увеличит i
на 1 (из-за i++
). Теперь в состоянии вашего цикла for у вас есть 1 < 1
(потому что и i
, и Serial.available()
равны 1), таким образом, цикл for завершится без каких-либо дальнейших итераций. Но у вас все еще остался 1 байт в буфере, который вы не прочитали.
Как я читал из документации Serial.flush()
(хотя документация, как известно, плохая) и из этого вопроса, я вижу, что она будет ждать только до тех пор, пока выходной буфер не будет очищен подпрограммами прерывания. Он ничего не делает с входным буфером. Таким образом, у вас все еще есть данные в буфере RX после этой строки.
Это означает, что у вас действительно есть данные в буфере RX, когда вы входите в функцию jog ()
. Таким образом, он выйдет напрямую, не делая ни одного шага.
Чтобы решить эту проблему, вы должны сначала исправить свою функцию getData ()
, чтобы прочитать все доступные данные из буфера RX. Вы можете изменить свой цикл for следующим образом:
for(int i = 0; Serial.available() > 0 && i < INPUT_BUFFER_SIZE; i++){
Это будет повторяться до тех пор, пока буфер RX не опустеет (когда Serial.available()
возвращает 0) или пока ваш входной
массив[] не заполнится (пожалуйста, добавьте константу или определите размер входного буфера. Может быть, он у вас уже есть. Вы не включили полный код. Но я думаю, что это 200).
После цикла for вы можете очистить буфер, прочитав из него, пока ничего не останется (пожалуйста, смотрите Связанный вопрос для этого). Вы даже можете сделать это в начале своей функции jog ()
. Это гарантирует, в основном, что в буфере нет данных в начале функции jog ()
(в основном, потому что время приема данных может быть таким, что вы получите байт между опорожнением буфера RX и циклом. Маловероятно, но не исключено).
Хотя, как утверждает Ник Гэммон в связанном ответе, это не лучший способ очистить буфер RX и использовать каждый последовательный ввод в качестве прерывания (иногда у вас нет точного контроля, когда именно поступают данные). Лучшим решением является реализация протокола сообщений, в котором конец полного сообщения помечается специальным символом. Затем вы читаете с последовательного, пока не будет получено полное сообщение (вы даже можете сделать это неблокирующим, чтобы вы могли делать другие вещи, пока сообщение не будет завершено), и только тогда действуйте в соответствии с сообщением. Для этого потребуются большие изменения в вашем коде. Вам придется переписать свою функцию getData ()
, а затем удалить весь блокирующий код из скетча (например, все задержки) и вместо этого работать с неблокирующим кодом (например, с помощью функции micros ()
. Принцип объясняется в примере BlinkWithoutDelay, который поставляется с IDE Arduino (хотя он использует
millis()
вместо micros ()
, это тот же принцип). Вы бы неоднократно вызывали функцию jog ()
, которая выполняла бы только один шаг, если бы пришло время его выполнить. Тем временем остальная часть кода может получать новые сообщения. Это делает вас более гибким и независимым от точного времени приема данных. Поскольку это было бы большим переписыванием вашего кода, вы должны сами решить, хотите ли вы пойти этим путем или остаться с более простым и несовершенным решением.
- Как запустить шаговый двигатель через последовательную связь
- Как разделить входящую строку?
- Как вывести несколько переменных в строке?
- В чем разница между Serial.write и Serial.print? И когда они используются?
- Загрузка Arduino Nano дает ошибку: avrdude: stk500_recv(): programmer is not responding
- Программы построения последовательных данных
- Как узнать частоту дискретизации?
- Что такое Serial.begin(9600)?
Пожалуйста, покажите нам полный рабочий пример, который показывает вашу проблему, а не только одну функцию. Может ли быть так, что в последовательном буфере все еще есть данные, когда вы вводите функцию jog()` В этом случае он выйдет напрямую, @chrisl
Когда он запускается, в буфере ничего нет. Сообщение обновлено с полным кодом., @Bob Dave