Можно ли выйти из прерывания не по reti ?

Обсуждаем контроллеры компании Atmel.
Ответить
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

Miw писал(а):Значит буду пытаться уменьшить время на 1 эффект,
С программным Fade придется локальную для функции переменную яркости выносить в главный цикл
Всем большое спасибо за мысли и советы!
Нет бы прислушаться к советам и сделать наконец конечный автомат.
Реклама
Miw
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 33
Зарегистрирован: Пн ноя 24, 2014 16:58:41

Сообщение Miw »

Правильно ли я понимаю, что конечный автомат - это на каждый вид анимации своя функция с логикой обработки нажатий на кнопки ?
А в чем преимущество ? Минусы я вижу - дублирование кода. У меня 2 кнопки, значит разных нажатий минимум 4.

На самом деле я в итоге сделал смесь :
следит за нажатиями прерывание, оно же устанавливает признак выхода из эффекта
"короткие" эффекты - типа миганий и просто свечения длятся меньше 1 секунды, так что ничего не обрабатывают
"длинные" эффекты - типа Fade, которые по 5-10 секунд проверяют признак выхода
логика обработки различных нажатий осталась в основном цикле
в режим настройки (яркость отрегулировать, цвет выбрать и т.п.) система переходит при удержании кнопки, вызывается это все хозяйство прямо из прерывания ;)) по выходу из режима таймеры сбрасываются и прерывания снова включаются

С Наступившими !
придумал новые детальки : оптимистор и пессимистор ...
осталось придумать для чего они нужны ))))
Реклама
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

Нет. Процедура индикации в случае конечного автомата постоянно вызывается из бесконечного цикла, то есть обработка кнопок не дублируется. Вроде уже приводил кусок кода, даже не знаю как еще расписать.
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

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

Заводим прерывание от таймер на 1-10ms (для системы антидребезга кнопок)
Внутри него будут счётчики всё остальное в главном цикле.

Я не совсем понял как у вас реализован опрос кнопок. Но это не принципиально в общем есть функция skan_key() которая возвращает один из 4 кодов нажатых клавиш и ещё один код(0xFF) когда кнопки не нажаты.

Тогда главный цикл будет выглядит следующим образом
Спойлер
interrupt [TIM3_OVF] void timer1_ovf_isr(void){
time_run++;
time_anim++;
...................
}

signed char mode;

void main(void){
unsigned char code_key;
while(1){
//===================
//=================Опрос кнопок========
//===================
code_key=skan_key();
//===================
//==============обработка нажатия кнопок=================
//===================
switch(code_key){
case 0xFF:{break;} //кнопки не нажаты нечего не делаем
//------Следующий эфект---------------------------
case next_effect:{
mode++;
if(mode>=MAX_EFFECT){
mode=MAX_EFFECT;
}
break;
}
//-------Предыдущий эффект--------------------------
case previous_effect:{
mode--;
if(mode<=0){
mode=0;
}
break;
}
//---------------------------------------
case setting:{......break;}
...................
}
//===================
//================Запуск эффектов=======
//===================
switch(mode){
case 0: {eff_run(); break;}
case 1: {eff_anim(); break;}
}

}
}
//=============Функции эффектов==========
void eff_run(){ //эффект бегущего огня
static unsigned char eff=0; // текущее состояние
static unsigned char mode_run=0;
switch(mode_run){
case START_RUN:{
PORTB = (1<<eff);
if(eff++>7)eff=0;
// После того как вывели в порт переменную eff делаем паузу на 1-10секунд
mode_run=PAUSE_RUN; //Переходим в состояние ожидание завершения паузы
time_run=0; // Засекаем 1 секунду с этого места
break;
}
case PAUSE_RUN:{
if(time_run>=1000){ // пауза в 1 секунду
mode_run=START_RUN; // Время вышло возвращаемся обратно в START_RUN
}
break;
}
}
}
При такой реализации получается неважна какая у вас задержка 1,10 секунд час или два. В главном цикле произойдёт сравнение и он продолжит дальнейшую работу опрашивать кнопки и тд. Если в это время произойдёт нажатие кнопки то оно тут же вызовет обработчик и эффект изменится.

PS: Если пауза будет большая то при смене и возврата эффекта мы попадём обратно в паузу тут надо подумать как запускать эффекты с начала (START_RUN)
Для реализации функции skan_key(); можно воспользоваться вот этим алгоритмом
http://www.kit-e.ru/articles/circuit/2007_08_170.php
Там не важна сколько кнопок и как они подключены.
Реклама
Эиком - электронные компоненты и радиодетали
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

pokk писал(а):предложил COKPOWEHEU, только там я не увидел как реализованы задержки
Вот уж не думал, что для понимания это так важно. Задержку можно расположить в основном цикле, а можно внутри эффекта. Можно даже вызывать по таймеру.
.
Индивидуальная задержка
Спойлер

Код: Выделить всё

const unsigned char eff2_tab[8]={0x00,0x55,0xAA,0xFF,0xFF,0xAA,0x55,0x00};
void eff1(){
 if(PORTD & (1<<7)) PORTD = 0x01; else PORTD <<=1;
 _delay_ms(100);
}
void eff2(){
 unsigned char time=0;
 PORTD=eff2_tab[time];
 time++;
 if(time>7)time=0;
 _delay_ms(200);
}
int main(){
unsigned char mode=0;
 ...
 while(1){
 ...
  if(mode)eff1(); else eff2();
 }
}
Общая задержка
Спойлер

Код: Выделить всё

void eff1(){
 if(PORTD & (1<<7)) PORTD = 0x01; else PORTD <<=1;
}
void eff2(){
 unsigned char time=0;
 PORTD=eff2_tab[time/2]; //поскольку задержка должна быть вдвое больше, чм в прошлом случае, делим локальный счетчик пополам. На самом деле это лучше делать через сдвиг, но так нагляднее
 time++;
 if(time>15)time=0; //поскольку счетчик приходится делить, его максимум будет удвоен
}
int main(){
unsigned char mode=0;
 ...
 while(1){
 ...
  if(mode)eff1(); else eff2();
  _delay_ms(100);
 }
}
По таймеру
Спойлер

Код: Выделить всё

void eff1(){
 if(PORTD & (1<<7)) PORTD = 0x01; else PORTD <<=1;
}
void eff2(){
 unsigned char time=0;
 PORTD=eff2_tab[time/2];
 time++;
 if(time>15)time=0;
}
volatile char timer_flag=0;
ISR(TIMER0_OVF_vect){
 timer_flag=1;
}
int main(){
unsigned char mode=0;
 ...
 while(1){
 ...
  if(timer_flag){
   timer_flag=0;
   if(mode)eff1(); else eff2();
  }
 }
}
Если надо больше эффектов, блок if(mode) изменится например на switch(mode), для демонстрации концепции это не важно.
Реклама
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

COKPOWEHEU писал(а):Вот уж не думал, что для понимания это так важно.
Ну как я понял из этого что у автора короткие эффекты и длинные эффекты находятся в разных местах в прерывании/главный цикл.
Miw писал(а):На самом деле я в итоге сделал смесь :
следит за нажатиями прерывание, оно же устанавливает признак выхода из эффекта
"короткие" эффекты - типа миганий и просто свечения длятся меньше 1 секунды, так что ничего не обрабатывают
"длинные" эффекты - типа Fade, которые по 5-10 секунд проверяют признак выхода
Так как есть задержки 5-10 секунд, то варианты с индивидуальной и общей задержкой не подходят.
А вот по таймеру как раз то что надо.

P.S. Я походу в своём варианте наворотил лишнего в эффекте.
Реклама
Ответить

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