В настоящее время я пишу приложение, зависящее от времени встраиваемых систем, в частности, на ARM Cortex M4. Он имеет ряд задач, которые происходят на разных частотах, и поэтому мы используем таймер SysTick ARMs для отслеживания времени в пределах 1-секундного кадра. Основной занят цикл ожидания, пока таймер не увеличивается и начинает задачу, а так:В C самый простой способ отменить задачу?
void main(){
while(1){
if(!timerTicked)
continue; //timer hasn't updated since last loop, do nothing.
if(time==0)
toggleStatusLED();
if(time==0 || time==500){
twoHzTask(); //some task that must run twice a second
}
if(time%300==5){ //run at ms=5, 305 and 605
threeHzTask(); //some task that must run three times a second
}
}
}
void SysTick_increment(){ //Interrupt Service Routine for SysTick timer
time=(time+1)%1000;
}
Это отлично работает для приоритетных задач, которые не могут вешают. Кроме того, задачам с высоким приоритетом разрешается принимать столько, сколько им нужно выполнить, однако переход со временем может привести к тому, что система перейдет в безопасную, в зависимости от задачи. Тем не менее, я хотел бы добавить простой механизм, чтобы прервать, не критически важных код, который занимает слишком много времени, как это:
void main(){
while(1){
if(time==500){ //run at ms=500
savingWorld=1;
saveTheWorld(); //super important task
savingWorld=0;
}
else if(time==750){
spinningWheels=1;
spinWheels(); //not very important task. Code for this function is immutable, can not alter it to support task cancellation.
spinningWheels=0;
}
}
}
void SysTick_increment(){ //Interrupt Service Routine for SysTick timer
time=(time+1)%1000;
if(time==900 && spinningWheels){
spinningWheels_cancel(); //we have more important stuff to do
}
}
Как это базовая встроенная система, я бы предпочел, чтобы не вводить сложность операционной системы или многопоточного механизма. Кроме того, остальная система должна находиться в стабильном состоянии после вызова spinningWheels_cancel()
. То есть saveTheWorld()
должен по-прежнему работать должным образом. Каков самый простой способ сделать это?
Если вы не можете изменить spinWheels(), вы не сможете отменить его после его запуска, поэтому у вас нет выбора, кроме как «не выполнить его», если вы слишком близко к времени выполнения задачи saveTheWorld() нет? Поэтому, если spinWheels() занимает более 750 циклов в вашей системе, он все равно будет работать, когда придет время для запуска saveTheWorld(), и ничего не поделаешь. Альтернативой может быть запуск saveTheWord() в ISR, но зависит от того, что он делает. – Chris
Ну, твоя идея рода работ, хотя время жестко составляет 900, вероятно, не идеально. > = 900 было бы лучше, если время будет ровно 900, и вы прерываете между ними 'else if (time == 750)' и 'spinningWheels = 1;', вы не поймаете, не останавливая вращение колес, но все равно войдете в задачу как только вы вернетесь из ISR. Хотя вам не нужна полная RTOS для этого, вам придется реализовать части базового. В основном, я думаю, что обратный адрес вашего 'SysTick_increment' должен измениться, если вы отмените вращение колеса, чтобы избежать возврата обратно в эту задачу. – Unn
Я думаю, что у Криса есть хорошая идея, хотя, используя ISR для ваших самых важных задач, так они могут прерывать менее важные. (Хотя будьте осторожны, они не блокируют друг друга). – Unn