Страница 1 из 1
Реализация "старт/пауза", стоп
Добавлено: Ср фев 04, 2015 05:59:56
Tasmanec
Всем доброго времени суток.
К примеру, имеется ATmega16, несколько кнопок. Одна из кнопок должна выполнять функцию старта, паузы выполнения кода. Другая в качестве стопа, при чем не должны сбиваться настройки, которые устанавливаются другими кнопками по мере работы устройства, т.е. reset в данном случае не подойдет. Main состоит практически из одной основной функции, которая вызывает десяток-другой других функций, работает с кучей переменных, содержит множество циклов. Реализовал задуманное следующим способом: две вышеуказанные кнопки являются инициаторами прерываний int0, int1. Сама основная функция (не main) выполняется по условию cikle_job_status==1(переменная для индикации состояния: 1- в работе, 2- на паузе, 0 - еще не запущена, остановлена). Так же внутри каждого цикла и еще в куче мест выполняется проверка на условие (cikle_job_status==1) . Как только условие не выполняется, оператором return выполнение программы прекращается.
собственно код:
Спойлер
Код: Выделить всё
ISR (INT0_vect)
{
cikle_job_status = 3; //останавливаем работу программы
}
ISR (INT1_vect)
{
if (cikle_job_status ==1)
{
cikle_job_status =2; //переводим в паузу
}
else
{
cikle_job_status = 1; //заставим работать
}
}
void pausa()
{
while (cikle_job_status==2)
{
_delay_ms(1);
}
}
//////////////////
дальше объявления кучи функций
//////////////////
main (){
тут кучка функций с настройками и т.п.
while(1)
{
/////
тут отслеживание нажатий других кнопок для настройки и прочие мелочи выполняются
/////
MY_BIG_function()
{
while (perem==1)
{
тут перед каждым вызовом функций, внутри каждого цикла и т.п. проверка на условие
if (cikle_job_status==1)
{
выполняем код
}
else if (cikle_job_status==2)
{
pausa();
}
else
{
return; //прекращаем выполнение функции
}
}
cikle_job_status =0; //переводим в ноль чтоб повторно не стала выполняться
}
}
Так вот вопрос: есть ли какие-либо стандартные средства в микроконтроллерах, чтоб можно было поставить выполнение программы на паузу на неопределенное время?? А то много лишних действий контроллеру приходится выполнять, жалко время, которое он тратит на проверки и т.п.
Re: Реализация "старт/пауза", стоп
Добавлено: Ср фев 04, 2015 10:34:53
Z_h_e
Переведите контроллер в спящий режим. Инструкция ассемблера SLEEP. Перед этим нужно настроить режим сна в MCUCR.
Re: Реализация "старт/пауза", стоп
Добавлено: Ср фев 04, 2015 11:11:09
uk8amk
1) Никогда не делайте return из main() если не желаете получить непредсказуемое поведение системы(зависание, крах, сброс и т.д.).
2) Для управления задачами используйте RTOS или более простой вариант в виде сопрограммы.
Re: Реализация "старт/пауза", стоп
Добавлено: Ср фев 04, 2015 11:30:40
ARV
1. автор работает с WinAVR, поэтому выполнять return из main абсолютно безопасно: это приводит к полной остановке функционирования программы (запрещаются прерывания и производится бесконечный цикл).
2. RTOS - это здорово, но для AVR малоприемлемо...
3. предлагаю такой алгоритм:
INT1 -
стоп, делает ровно то, что и return из man, т.е. подвешивает систему на неопределенное время
INT0 - старт/пауза
Код: Выделить всё
#define MODE_RUN 0
#define MODE_STOP 1
#define MODE_PAUSE 2
volatile uint8_t mode = MODE_RUN;
// две функции воздействуют только на флаги разрешения прерываний периферийных устройств, не глобально!
static disable_interrupt(void); // эта функция запрещает все прерывания, кроме INT0
static enable_interrupt(void); // эта функция разрешает все прерывания
ISR(INT1_vect, ISR_NOBLOCK){
disable_interrupt();
// если нужно - выключаем периферию, гасим индикацию и т.п.
mode = MODE_STOP;
while(mode == MODE_STOP); // виснем
}
ISR(INT0_vect, ISR_NOBLOCK){
if(mode == MODE_STOP)}
enable_interrupt();
// если надо - включаем периферию и т.п.
mode = MODE_RUN;
} else if (mode == MODE_PAUSE){
mode = MODE_RUN;
} else mode = MODE_PAUSE;
while(mode == MODE_PAUSE);
}
в основом цикле и вообще повсюду в программе никаких анализов режима работы делать не нужно.
следует только добавить борьбу с дребезгом

ну и учитывать, что пауза или стоп может наступить в любой момент, например, посредине вывода на ЖКИ (мусор появится)
Re: Реализация "старт/пауза", стоп
Добавлено: Ср фев 04, 2015 14:13:40
Tasmanec
Z_h_e писал(а):Переведите контроллер в спящий режим. Инструкция ассемблера SLEEP. Перед этим нужно настроить режим сна в MCUCR.
Спасибо за идею, надо обдумать.
uk8amk писал(а):
1) Никогда не делайте return из main() если не желаете получить непредсказуемое поведение системы(зависание, крах, сброс и т.д.).
2) Для управления задачами используйте RTOS или более простой вариант в виде сопрограммы.
return делается не из main(), а из функции, которая выполняется в бесконечном цикле внутри main(), т.е. программа в моем случае начинает выполняться сначала(если плей нажать еще раз), минуя первоначальные настройки, забитые в прошивку и настройки, выставленные вручную в процессе работы. Про RTOS тоже первый раз слышу, надо будет изучить, спасибо.
ARV писал(а):
1. автор работает с WinAVR, поэтому выполнять return из main абсолютно безопасно: это приводит к полной остановке функционирования программы (запрещаются прерывания и производится бесконечный цикл).
2. RTOS - это здорово, но для AVR малоприемлемо...
3. предлагаю такой алгоритм:
INT1 - стоп, делает ровно то, что и return из man, т.е. подвешивает систему на неопределенное время
INT0 - старт/пауза
Спойлер
Код: Выделить всё
#define MODE_RUN 0
#define MODE_STOP 1
#define MODE_PAUSE 2
volatile uint8_t mode = MODE_RUN;
// две функции воздействуют только на флаги разрешения прерываний периферийных устройств, не глобально!
static disable_interrupt(void); // эта функция запрещает все прерывания, кроме INT0
static enable_interrupt(void); // эта функция разрешает все прерывания
ISR(INT1_vect, ISR_NOBLOCK){
disable_interrupt();
// если нужно - выключаем периферию, гасим индикацию и т.п.
mode = MODE_STOP;
while(mode == MODE_STOP); // виснем
}
ISR(INT0_vect, ISR_NOBLOCK){
if(mode == MODE_STOP)}
enable_interrupt();
// если надо - включаем периферию и т.п.
mode = MODE_RUN;
} else if (mode == MODE_PAUSE){
mode = MODE_RUN;
} else mode = MODE_PAUSE;
while(mode == MODE_PAUSE);
}
в основом цикле и вообще повсюду в программе никаких анализов режима работы делать не нужно.
следует только добавить борьбу с дребезгом

ну и учитывать, что пауза или стоп может наступить в любой момент, например, посредине вывода на ЖКИ (мусор появится)
Работаю в Atmel Studio 6.0
Не могу вкурить, как будет останавливаться работа программы, если внутри громоздкой функции не делать анализ рижима работы
Код: Выделить всё
while(mode == MODE_RUN)
{
MY_BIG_FUNTION();
any_function1();
any_function2();
any_function3();
/*
many any functions();
*/
}
Даже если прерываниями менять значение mode, цикл все равно выполнится до конца, т.к. условие проверяется только один раз перед его началом.
Про мусор и дребезг: в ответственных местах программы запрещаю прерывания, а в самих прерываниях ставлю выдержку, чтоб от дребезга избавиться. Просто не хотел лишними строчками нагружать пост
Re: Реализация "старт/пауза", стоп
Добавлено: Ср фев 04, 2015 15:54:20
ARV
моя идея в том, что зайдя в прерывание "стоп" программа висит до тех пор, пока режим mode не будет изменен. так как прерывание может прервать любое место программы, получается остановка без анализа.
чтобы выйти из прерывания "стоп", я разрешаю прерывания от "старт-пауза", где и меняю режим.
т.е. работали, работали, а затем нажали СТОП - вошли в прерывание и там остались, ожидая изменения (по другом прерыванию!) режима. программа стоит.
нажали "старт-пауза", попали в обработчик - смотрим, а режим СТОП. ну, тогда меняем его на СТАРТ и выходим. в этот момент в ранее "подвисшем" обработчике выясняется, что режим уже не СТОП - и оттуда выходим, продолжая прогу с прерванного места.
в любой момент аналогично можно нажать на ПАУЗУ, в этом случае подвисание произойдет уже в этом обработчике до следующего нажатия.
вот как-то так

внимательно рассмотрите пример кода, что я вам дал - проанализируте его поведение.
и никаких РТОС, никаких проверок в циклах и других местах. тонкости алгоритма я упомянул: дребезг и запрет-разрешение прерываний в нужных местах, а так же борьба с побочными эффектами из-за прерывания в непредсказуемые моменты - все лечится перенастройкой периферии.
Re: Реализация "старт/пауза", стоп
Добавлено: Ср фев 04, 2015 16:41:06
Tasmanec
Недосып дает о себе знать.. Пойду высплюсь, еще раз перечитаю все, осмыслю на свежую голову и отвечу)) Всем спасибо за советы:)
Re: Реализация "старт/пауза", стоп
Добавлено: Чт фев 05, 2015 15:10:18
Tasmanec
ARV писал(а):моя идея в том, что зайдя в прерывание "стоп" программа висит до тех пор, пока режим mode не будет изменен. так как прерывание может прервать любое место программы, получается остановка без анализа.
чтобы выйти из прерывания "стоп", я разрешаю прерывания от "старт-пауза", где и меняю режим.
т.е. работали, работали, а затем нажали СТОП - вошли в прерывание и там остались, ожидая изменения (по другом прерыванию!) режима. программа стоит.
нажали "старт-пауза", попали в обработчик - смотрим, а режим СТОП. ну, тогда меняем его на СТАРТ и выходим. в этот момент в ранее "подвисшем" обработчике выясняется, что режим уже не СТОП - и оттуда выходим, продолжая прогу с прерванного места.
в любой момент аналогично можно нажать на ПАУЗУ, в этом случае подвисание произойдет уже в этом обработчике до следующего нажатия.
вот как-то так

внимательно рассмотрите пример кода, что я вам дал - проанализируте его поведение.
и никаких РТОС, никаких проверок в циклах и других местах. тонкости алгоритма я упомянул: дребезг и запрет-разрешение прерываний в нужных местах, а так же борьба с побочными эффектами из-за прерывания в непредсказуемые моменты - все лечится перенастройкой периферии.
Немножко мы с Вами друг-друга недопоняли:) Ваш вариант предлагает именно подвисание при нажатии на СТОП. А нужно, чтобы можно было дальше кнопками менять настройки контроллера и т.п.
Во вложении кратенькая блок-схема программы с описаниями что требуется.
Re: Реализация "старт/пауза", стоп
Добавлено: Чт фев 05, 2015 17:46:05
ARV
ну, как объясняли, так и понял
по вашему алгоритм сложно сказать что-либо определенное, но если на самом деле ваша большая функция что-то вычисляет очень долго и много всего делает, даже RTOS вам не поможет, т.к. систему жесткой многозадачности AVR не потянет из-за дефицита ресурсов (вы же на меге128 делаете?), а кооперативная многозадачность в сущности будет сведена именно к постоянному опросу флага "разрешения" продолжить вычисления.
есть сильное подозрение, что у вас не самый оптимальный алгоритм решения вашей задачи, отсюда и сложности с приостановкой и т.п.
то есть я хочу сказать, что вам надо подумать над изменением алгоритма, а не над тем, как его останавливать и продолжать. но то лишь догадки...
кстати, на счет использования RESET. это может оказаться вполне разумным решением, и не надо бояться того, что будет портиться текущее состояние программы: достаточно нужные переменные разместить в секции
.noinit, и после сброса они не будут ни обнуляться, ни как-то изменяться, т.е. будут сохранять свое прежнее значение. может быть, это вам поможет?