Как заставить прерывание перезапустить основной цикл вместо возобновления? (вопрос времени!)
За последние два дня я написал программу, которая в общих чертах генерирует довольно точный настраиваемый пользователем импульсный сигнал (как по частоте, так и по рабочему циклу). Он в основном использует функцию micros() для отслеживания времени, чтобы вывести 4 или 4 канала цифрового выхода.
Эти 4 канала всегда должны иметь разность фаз 90 градусов (например, 4-цилиндровый двигатель). Чтобы пользователь мог изменить настройки, реализован ISR, который возвращает флаг в основной цикл для повторной инициализации программы. Этот флаг определен как логическое значение 'set4'. Когда оно ложно, оператор while в основном цикле будет запускать выходы. Когда оно истинно, оператор if выполнит необходимые пересчеты и сбросит флаг, чтобы оператор while возобновился.
Программа отлично работает с начальными значениями. Этап идеален. Однако, когда ISR вызывается и возвращается к основному циклу, насколько я понимаю, он возобновляет программу в операторе 'while' с того места, где он был первоначально прерван, до тех пор, пока не завершится и не проверит флаг 'set4', чтобы увидеть его Теперь верно, и это должно прекратиться. Затем, даже несмотря на то, что оператор "if" впоследствии сбрасывает и пересчитывает все необходимые переменные, фаза между этими 4 выходными каналами теряется. Проверено вручную, я вижу, в зависимости от того, в какое время вызывается ISR, это даст разные результаты, обычно синхронизируя все 4 выходных канала! Это происходит, даже если я не могу изменить никакие значения (таким образом, подпрограмма if сбрасывает переменные до тех же самых значений, когда вы впервые включаете arduino!). Однако, если я закомментирую эту процедуру и просто оставлю строку, которая сбрасывает флаг 'set4', программа продолжит работу как обычно, ничего не произошло!
Я почти уверен, что это как-то вызвано таймером micros(), потому что цикл будет возобновлен с того места, где был вызван ISR. Я пытался сделать это по-другому, проверяя и отключая прерывания с помощью cli() и sei(), но я не смог заставить его работать, потому что он просто зависнет, когда аргументы для cli() верны. Единственное решение, о котором я могу подумать (я перепробовал все, потратил целый день на поиски и испытания), - заставить ISR возобновить работу с начала цикла, чтобы программа могла правильно инициализироваться. Еще одно решение, которое приходит на ум, - это, может быть, каким-то образом сбросить таймер micros(), но, по-моему, это испортит ISR.
Чтобы помочь вам визуализировать то, что происходит, вот фрагмент моего кода (пожалуйста, не обращайте внимания на имя 'Millis' в переменных micros и любые пропущенные фигурные скобки, так как это не просто copy-paste:p):
void loop()
{
while(!set4)
{
currentMillis = micros();
currentMillis2 = micros();
currentMillis3 = micros();
currentMillis4 = micros();
if(currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
{
interval = ONTIME;
ledState = HIGH;
}
else
{
interval = OFFTIME;
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
.
.
//similar code for the other 3 output channels
.
.
}
if (set4){
//recalculation routine - exactly the same as when declaring the variables initially
currentMillis = 0;
currentMillis2 = 0;
currentMillis3 = 0;
currentMillis4 = 0;
//Output states of the output channels, forced low seperately when the ISR is called (without messing with the 'ledState' variables)
ledState = LOW;
ledState2 = LOW;
ledState3 = LOW;
ledState4 = LOW;
previousMillis = 0;
previousMillis2 = 0;
previousMillis3 = 0;
previousMillis4 = 0;
//ONTIME is the HIGH time interval of the pulse wave (i.e. dwell time), OFFTIME is the LOW time interval
//Note the calculated phase/timing offset at each channel
interval = ONTIME+OFFTIME;
interval2 = interval+interval/4;
interval3 = interval+interval/2;
interval4 = interval+interval*3/4;
set4=false;
}
}
Есть идеи, что не так? С уважением, Кен
1 ответ
Проблема здесь:
previousMillis = 0;
previousMillis2 = 0;
previousMillis3 = 0;
previousMillis4 = 0;
Все, если утверждение будет верно в следующем цикле.
Попробуйте с:
previousMillis = micros();
previousMillis2 = micros();
previousMillis3 = micros();
previousMillis4 = micros();