Реализация "старт/пауза", стоп

Обсуждаем контроллеры компании Atmel.
Ответить
Родился
Сообщения: 12
Зарегистрирован: Вс фев 01, 2015 01:35:57

Сообщение 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; //переводим в ноль чтоб повторно не стала выполняться 
       
       }
}



Так вот вопрос: есть ли какие-либо стандартные средства в микроконтроллерах, чтоб можно было поставить выполнение программы на паузу на неопределенное время?? А то много лишних действий контроллеру приходится выполнять, жалко время, которое он тратит на проверки и т.п.
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Сообщение Z_h_e »

Переведите контроллер в спящий режим. Инструкция ассемблера SLEEP. Перед этим нужно настроить режим сна в MCUCR.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Реклама
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

1) Никогда не делайте return из main() если не желаете получить непредсказуемое поведение системы(зависание, крах, сброс и т.д.).
2) Для управления задачами используйте RTOS или более простой вариант в виде сопрограммы.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение 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);
}
в основом цикле и вообще повсюду в программе никаких анализов режима работы делать не нужно.
следует только добавить борьбу с дребезгом :))) ну и учитывать, что пауза или стоп может наступить в любой момент, например, посредине вывода на ЖКИ (мусор появится)
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Родился
Сообщения: 12
Зарегистрирован: Вс фев 01, 2015 01:35:57

Сообщение 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, цикл все равно выполнится до конца, т.к. условие проверяется только один раз перед его началом.
Про мусор и дребезг: в ответственных местах программы запрещаю прерывания, а в самих прерываниях ставлю выдержку, чтоб от дребезга избавиться. Просто не хотел лишними строчками нагружать пост
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

моя идея в том, что зайдя в прерывание "стоп" программа висит до тех пор, пока режим mode не будет изменен. так как прерывание может прервать любое место программы, получается остановка без анализа.

чтобы выйти из прерывания "стоп", я разрешаю прерывания от "старт-пауза", где и меняю режим.

т.е. работали, работали, а затем нажали СТОП - вошли в прерывание и там остались, ожидая изменения (по другом прерыванию!) режима. программа стоит.
нажали "старт-пауза", попали в обработчик - смотрим, а режим СТОП. ну, тогда меняем его на СТАРТ и выходим. в этот момент в ранее "подвисшем" обработчике выясняется, что режим уже не СТОП - и оттуда выходим, продолжая прогу с прерванного места.

в любой момент аналогично можно нажать на ПАУЗУ, в этом случае подвисание произойдет уже в этом обработчике до следующего нажатия.

вот как-то так :))) внимательно рассмотрите пример кода, что я вам дал - проанализируте его поведение.

и никаких РТОС, никаких проверок в циклах и других местах. тонкости алгоритма я упомянул: дребезг и запрет-разрешение прерываний в нужных местах, а так же борьба с побочными эффектами из-за прерывания в непредсказуемые моменты - все лечится перенастройкой периферии.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Родился
Сообщения: 12
Зарегистрирован: Вс фев 01, 2015 01:35:57

Сообщение Tasmanec »

Недосып дает о себе знать.. Пойду высплюсь, еще раз перечитаю все, осмыслю на свежую голову и отвечу)) Всем спасибо за советы:)
Родился
Сообщения: 12
Зарегистрирован: Вс фев 01, 2015 01:35:57

Сообщение Tasmanec »

ARV писал(а):моя идея в том, что зайдя в прерывание "стоп" программа висит до тех пор, пока режим mode не будет изменен. так как прерывание может прервать любое место программы, получается остановка без анализа.

чтобы выйти из прерывания "стоп", я разрешаю прерывания от "старт-пауза", где и меняю режим.

т.е. работали, работали, а затем нажали СТОП - вошли в прерывание и там остались, ожидая изменения (по другом прерыванию!) режима. программа стоит.
нажали "старт-пауза", попали в обработчик - смотрим, а режим СТОП. ну, тогда меняем его на СТАРТ и выходим. в этот момент в ранее "подвисшем" обработчике выясняется, что режим уже не СТОП - и оттуда выходим, продолжая прогу с прерванного места.

в любой момент аналогично можно нажать на ПАУЗУ, в этом случае подвисание произойдет уже в этом обработчике до следующего нажатия.

вот как-то так :))) внимательно рассмотрите пример кода, что я вам дал - проанализируте его поведение.

и никаких РТОС, никаких проверок в циклах и других местах. тонкости алгоритма я упомянул: дребезг и запрет-разрешение прерываний в нужных местах, а так же борьба с побочными эффектами из-за прерывания в непредсказуемые моменты - все лечится перенастройкой периферии.
Немножко мы с Вами друг-друга недопоняли:) Ваш вариант предлагает именно подвисание при нажатии на СТОП. А нужно, чтобы можно было дальше кнопками менять настройки контроллера и т.п.
Во вложении кратенькая блок-схема программы с описаниями что требуется.
Вложения
блок-схема.jpg
(44.78 КБ) 313 скачиваний
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

ну, как объясняли, так и понял :)

по вашему алгоритм сложно сказать что-либо определенное, но если на самом деле ваша большая функция что-то вычисляет очень долго и много всего делает, даже RTOS вам не поможет, т.к. систему жесткой многозадачности AVR не потянет из-за дефицита ресурсов (вы же на меге128 делаете?), а кооперативная многозадачность в сущности будет сведена именно к постоянному опросу флага "разрешения" продолжить вычисления.

есть сильное подозрение, что у вас не самый оптимальный алгоритм решения вашей задачи, отсюда и сложности с приостановкой и т.п.
то есть я хочу сказать, что вам надо подумать над изменением алгоритма, а не над тем, как его останавливать и продолжать. но то лишь догадки...

кстати, на счет использования RESET. это может оказаться вполне разумным решением, и не надо бояться того, что будет портиться текущее состояние программы: достаточно нужные переменные разместить в секции .noinit, и после сброса они не будут ни обнуляться, ни как-то изменяться, т.е. будут сохранять свое прежнее значение. может быть, это вам поможет?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Ответить

Вернуться в «AVR»