Я работаю над кодом для управления двухмодульным реле доступа к двери. Я ищу способ остановить текущие задачи перед запуском новой (той же задачи). Все, что я хочу, это избежать дублирования.
void TaskOpenManRoom(void *parameter){
Serial.println("Opening men room");
digitalWrite(manRelay, LOW);
vTaskDelay(6000 / portTICK_PERIOD_MS);
digitalWrite(manRelay, HIGH);
Serial.println("Closing men room");
vTaskDelete(NULL);
};
xTaskCreate(
TaskOpenManRoom,
"TaskOpenManRoom",
1000,
(void *) &man,
1,
&TaskMen
);
Моя цель - увеличить время, когда дверь должна быть открыта. Таким образом, в основном, когда первая задача была запущена, а затем через некоторое время вторая, дверь должна оставаться открытой еще 6000 мс.
В текущем коде, когда вызывается вторая задача, как в середине первой, дверь закрывается из-за вызова первой задачи digitalWrite(manRelay, HIGH);
Я был бы признателен за подсказку, как я могу убить первую задачу, когда запущена вторая.
Много способов:
Я был бы признателен за подсказку, как я могу убить первую задачу, когда второй сработал.
Это убьет текущую задачу:
vTaskDelete(NULL);
Я бы не стал убивать первую задачу при запуске второй.
Если вы вообще используете задачу, я бы переписал задачу во что-то вроде этой общей линии:
cast parameter to pointer to uint32
atomic increment open count, and if it was zero {
open the door
repeat {
sleep six seconds
} atomic decrement count, and exit loop if it was 1
close the door
}
exit the task
... и когда вы создаете задачу, передайте указатель на uint32_t, чтобы он использовал для хранения количества открытых.
Таким образом, задача начинается с атомарного увеличения числа открытых, которое возвращает значение, которое ранее было в счете открытых. Если это было равно нулю, это означает, что дверь в настоящее время закрыта. В таком случае мы открываем его и ложимся спать.
Если задача снова запустится, пока она находится в спящем режиме, количество открытых операций теперь будет равно единице. Мы немедленно увеличиваем это значение, но когда мы проверяем предыдущее значение, оно было равно 1, поэтому мы не пытаемся снова открыть дверь — мы просто пропускаем все, что есть в операторе if
, и выходим из задачи.
Когда первый экземпляр задачи просыпается, он уменьшает счетчик, и если он равен 1, он выходит из цикла, закрывает дверь и выходит из задачи. Но если задача снова запустится во время сна, счетчик все равно будет больше 1, поэтому она останется в цикле и еще немного спит.
Это открыто для небольшой оптимизации. В настоящее время он бездействует фиксированный период времени (шесть секунд), даже если текущий счетчик открытых данных больше 1. Если задача достаточно дорогая, чтобы оправдать небольшую дополнительную работу, мы могли бы выполнить атомарный обмен, чтобы получить текущий открытый счетчик и установите открытый счетчик на 0, умножьте полученное значение на 6000, затем спите в течение этого времени. Однако это добавляет немного дополнительной сложности, и в этом случае польза будет слишком мала, чтобы ее оправдать.
Это действительно зависит от того, не запустим ли мы задачу более 4 миллиардов раз, пока дверь открыта. Если бы мы это сделали, наше атомарное приращение переполнилось бы, и код работал бы неправильно. Для рассматриваемого случая (и большинства других) это вряд ли будет проблемой. В редких ситуациях, когда это может быть, очевидным решением является 64-битная переменная (и 64-битное атомарное увеличение и уменьшение). Увеличение переменной до переполнения 64-битной переменной, как правило, нереально (например, если вы увеличиваете на 1 ГГц, это займет столетия).
Задачи предназначены для длительного выполнения, потому что они относительно тяжеловесны. Не запускайте и не завершайте задачи для каждого действия пользователя и не откладывайте их на длительные периоды времени.
Вам вообще не нужна задача для вашей функциональности, вам просто нужен таймер для выполнения действия закрытия через 6000 мс. Затем вы можете сбросить его, когда вам нужно.
TimerHandle_t closeManRoomTimer;
void OpenManRoom() {
xTimerReset(closeManRoomTimer, 100); // <------ (re)arm the close timer
Serial.println("Opening men room");
digitalWrite(manRelay, LOW);
};
void CloseManRoom(TimerHandle_t) {
Serial.println("Closing men room");
digitalWrite(manRelay, HIGH);
};
// during program startup, setup a one-shot close timer
closeManRoomTimer = xTimerCreate("closeManRoomTimer", pdMS_TO_TICKS(6000), pdFALSE, 0, &CloseManRoom);
Это то, что я искал. Я новичок :P Большое спасибо, босс! :)