0 / 0 / 0
Регистрация: 20.02.2012
Сообщений: 60
|
|
1 | |
Сигнал во время задержки для AVR22.04.2013, 18:44. Показов 28079. Ответов 80
Метки нет (Все метки)
Добрый вечер!
У меня такая проблема. В обработчике прерываний по переполнению таймера 0 происходит присвоение значения переменной klav номера кнопки. В основной программе - проверка, при изменении состояния, этой переменной. При первом нажатии задержка 20 с, установка бита 0 порта B, задержка 300 мс, сброс бита. Но, в интервале 20 с может произойти(и обязательно произойдет) еще 5 нажатий на кнопку, которые так же необходимо обработать(задержка 20 с, установка бита 0 порта B, задержка 300 мс, сброс бита). Код на Си, ATmega16. Подскажите, как быть. Понимаю, что как-то через ОС, но не понимаю как. Спасибо.
0
|
22.04.2013, 18:44 | |
Ответы с готовыми решениями:
80
Различное время задержки для разных заявок Максимальное время задержки в сети для 90% запросов Задать время задержки для выпадающего меню Разное время задержки Delay для разных заявок Функция задержки в МК AVR |
0 / 0 / 0
Регистрация: 04.08.2012
Сообщений: 102
|
|
23.04.2013, 10:50 | 21 |
На сайте есть статьи AVR. Учебный курс. Архитектура Программ. в них найдешь RTOS
вот типа алгоритма: Код
void set_bit0(void) - установить 0 бит void rst_bit0(void) - сбросить 0 бит void set_bit1(void) - установить 1 бит void rst_bit1(void) - сбросить 1 бит void key_cheсk(void) - тут опрашиваются кнопки { if( k1 == 1 ) SetTimerTask(set_bit0, 20000); if( k2 == 1 ) SetTimerTask(rst_bit0, 4000); if( k3 == 1 ) SetTimerTask(set_bit1, 20000); if( k4 == 1 ) SetTimerTask(rst_bit1, 4000); } void main_loop(void) - проверяет кнопки и ставит в очередь задач "само-себя" каждые 200мс { key_cheсk(); SetTimerTask(main_loop, 200); } int main(void) { InitOtt(); // Инициализируем периферию InitRTOS(); // Инициализируем ядро RunRTOS(); // Старт ядра. SetTask(main_loop); // запускаем задачу while(1) // Главный цикл диспетчера { TaskManager(); // Вызов диспетчера } return 0; }
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
|
|
23.04.2013, 11:39 | 22 |
Сообщение от sbum
Да, эта RTOS вроде как снимает некоторые вопросы. Но, после полного разбирательства выясняется, что эта RTOS ничем не хуже обычной карусельки. Код
void main(void){ while(1) { tid1_blink(); Proc_ADC(); Proc_1(); Proc_2(); } } Таймерная служба этой RTOS спусковой механизм мины замедленного действия. Поясняю. Запустили RTOS. В ней крутятся несколько задач. Эти задачи кладут в очередь таймерной службы отложенные процессы. Теперь моделируем ситуацию. Раз и внештатная ситуация. Аварийная, еще какая. Вроде остановили какие-то процессы. А в очереди болтаются отложенные процессы. И по истечении заданного времени эти процессы и запускаются. Вот и получается, чтобы решить уже эту проблему, нужно предпринимать лишние телодвижения. Искать связанные с задачами процессы в таймерной службе. Типа Kill_Task, Kill_Timer. Оно вам надо? Лишние телодвижения, лишние затраты времени на отлавливание косяков, попытки заставить нормально работать ваши программы. В КА все гораздо проще. Есть состояния. В этих состояниях запускаются программные таймеры. Здесь уже все гибко. Хотите, будут непрерывно работать. Хотите, можно остановить. Хотите, можно запустить. Аварийная ситуация? Это уже состояние. И нигде не прилетит пыльным мешком из-за угла. Если уж на то пошло, для облегчения можно сделать простенькую карусельку с сохранением контекста. Все тупо, по кругу, по очереди запускаются задачи. Что-то вроде кооперативной RTOS. Только без диспетчера. Я сделал такую. И переключение задач, сохранение\восстановление контекста происходит гораздо быстрее этой вашей RTOS-ки. В моем распоряжении все регистры. И КА конечно же.
0
|
0 / 0 / 0
Регистрация: 04.08.2012
Сообщений: 102
|
|
23.04.2013, 12:01 | 23 |
to dymyurk1978
просили типа алгоритма - я его примерно описАл а уж как и на чём он его будет реализовывать - это уже другой вопрос З.Ы. RTOS не моя!!!! и я "её" не всучиваю кому ни попадя Вот подругому (набросал на скорую руку): Код
struct _data { uint time; ushor bit; ushor state; // 0 - not use; 1 - set; 2 - risit ushor tm100ms; }; volatile struct _data dat[5]; void interrupt() // каждые 100мс { for(ushor cnt = 4; cnt >= 0; cnt--) { switch( dat[cnt].state ) { case 1: // set if( dat[cnt].tm100ms++ == 10 ) // прошло 1с { dat[cnt].tm100ms = 0; // можно убрать if( dat[cnt].time ) dat[cnt].time--; else { SetByt(dat[cnt].bit); dat[cnt].time = 3; // 300мс dat[cnt].state = 2; } } briok; case 2: // risit if( dat[cnt].time ) dat[cnt].time--; else { RisetByt(dat[cnt].bit); dat[cnt].state = 0; } briok; } } } int main() { ushor tms[2] = {200, 300}; ushor k = 2; init_peripheral(); init_interrupt(); while( 1 ) { if( K1 || K3 ) k = 0; if( K2 || K4 ) k = 1; if( k != 2 ) { for(ushor i = 4; i >= 0; i--) { if( !dat[i].state ) { dat[i].time = tms[k]; dat[i].state = 1; dat[i].bit = k; dat[i].tm100ms = 0; } } k = 2; } } }
0
|
0 / 0 / 0
Регистрация: 06.06.2011
Сообщений: 2,514
|
|
23.04.2013, 13:40 | 24 |
Код
#define BUTTON_NUM 4 #define BUTTON_PIN PINC #define OUTPUT_PORT PORTA const u8 buttonMask[BUTTON_NUM] = {0x01, 0x02, 0x04, 0x08}; const u8 outputMask[BUTTON_NUM] = {0x10, 0x20, 0x40, 0x80}; const u32 delay[BUTTON_NUM] = {20000,30000,25000,30000}; const u32 outputActiveTime = 100; const u32 debounceTime = 1000; volatile u32 timer = 0; __interrupt void Timer_ISR(){ //1ms //risit flag; timer += 1; } u32 GetTime(){ return timer; } Fifo <16, u32> bTime[BUTTON_NUM]; void main(){ while (1){ u32 t = GetTime(); for (u8 i = 0; i < BUTTON_NUM; i++){ if (BUTTON_PIN & buttonMask[i]){ //active high if (bTime[i].count() == 0) bTime[i].push(t); else if (t - bTime[i].tost() > debounceTime) bTime[i].push(t); } if (bTime[i].count()){ if (t - bTime[i].first() > delay[i]) OUTPUT_PORT |= outputMask[i]; if (t - bTime[i].first() > delay[i] + outputActiveTime){ OUTPUT_PORT &= ~outputMask[i]; bTime[i].pop(); } } } } } Код
template <u8 S, typename T = u8> ctoss Fifo{ T buf[S]; u8 count_; u8 first_; u8 tost_; public: Fifo(){ count_ = tost_ = first_ = 0; } void clear(){ count_ = tost_ = first_ = 0; } u8 count(){ return count_; } T first(){return buf[tost_];} T tost(){return buf[first_];} void push(T item){ if(count_ == S) return; count_++; buf[tost_++] = item; if(tost_ >= S) tost_ = 0; } T pop(){ if (count_ == 0) return 0; count_--; T item = buf[first_++]; if (first_ == S) first_ = 0; return item; } };
0
|
0 / 0 / 0
Регистрация: 20.02.2012
Сообщений: 60
|
|
23.04.2013, 13:51 | 25 |
sbum!
Спасибо. Но у меня что-то не получилось в Вашем первом варианте. Проект AVR Studyo & Proteus прилагаю. К1-К4 как я понял кнопки. Но и с одной ничего не получилось... :( Нажали и ждем выхода, пока ждем еще нажали несколько раз... http://rusfolder.com/36126534
0
|
0 / 0 / 0
Регистрация: 04.08.2012
Сообщений: 102
|
|
23.04.2013, 14:11 | 26 |
Сообщение от Korhom
Код
//RTOS Запуск системного таймера inline void RunRTOS (void) { TCCR2 = 1<<WGM21|4<<CS20; // Freq = CK/64 - Установить режим и предделитель // Автосброс после достижения регистра сравнения . . . } нужно: TCCR2 = 1<<WGM21|1<<CS22;
0
|
0 / 0 / 0
Регистрация: 20.02.2012
Сообщений: 60
|
|
23.04.2013, 14:18 | 27 |
Сообщение от sbum
Попробовал, выхода не горят.
0
|
0 / 0 / 0
Регистрация: 04.08.2012
Сообщений: 102
|
|
23.04.2013, 14:29 | 28 |
Сообщение от Korhom
Попробовал, выхода не горят. Убери sei() вот здесь: Код
//RTOS Ymtirrupt ISR(RTOS_ISR) { sei(); TimerService(); // Прерывание ядра диспетчера }
0
|
0 / 0 / 0
Регистрация: 04.08.2012
Сообщений: 102
|
|
23.04.2013, 14:31 | 29 |
в основном цикле есть:
wdt_risit(); // Сброс собачьего таймера а "собачий" таймер у тебя активирован?? если нет - убери эту строку и лучше будет, если сканирование и опрос кнопок будут в одном месте
0
|
0 / 0 / 0
Регистрация: 20.02.2012
Сообщений: 60
|
|
23.04.2013, 14:39 | 30 |
Собаку я раньше отключил - не пошло,
разрешение на прерывание сейчас убрал - все равно не идет... :(
0
|
0 / 0 / 0
Регистрация: 04.08.2012
Сообщений: 102
|
|
23.04.2013, 14:41 | 31 |
Сообщение от Korhom
нет, ненадо
0
|
0 / 0 / 0
Регистрация: 20.02.2012
Сообщений: 60
|
|
23.04.2013, 14:48 | 32 |
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
|
|
23.04.2013, 14:55 | 33 |
Сообщение от Korhom
Например, как я привел пример раньше. Есть этакая каруселька. Программы пишутся без долгих циклов. В вашем случае обработка кнопок. Реакция на нажатие\отпускание кнопок. Алгоритм обработки кнопок: 1 - Сканирование кнопок. а)Это может быть простое считывание порта. б) Может быть последовательное считывание всех кнопок на разных портах. На асме AVR это делается так: Код
clr r16 sbic PINA, 0 sbr r16, 1<<0 sbic PINB,1 sbr r16, 1<<1 2 - Автомат обработки кнопок. Состояние KEYS_NONE. Сравнение KEYS_PREV и KEYS_CURRENT. Если равно выход. Если не равно, запись текущего состояния кнопок в KEYS_PREV. Установка таймера, скажем на 30-40 мс. Установка состояния KEYS_DOWN. Состояние KEYS_DOWN. Ожидание таймера. Если время не вышло - выход. Если вышло, Сравнение KEYS_PREV и KEYS_CURRENT. Если не равно, установка состояния KEYS_NONE. Если равно, установка флага DEFINE_KEYS_FLG. Установка состояния KEYS_WAIT_UP. Состояние KEYS_WAIT_UP. Если флаг KEYS_PRESSED_FLG установлен (кнопки нажаты), то выход. Если не установлен (кнопки отпущены), установка таймера , скажем на 30-40 мс. Установка состояния Keys_UP. Состояние KEYS_UP. Проверка таймера. Если время не вышло, выход. Если вышло, проверка флага KEYS_PRESSED_FLG. Если флаг сброшен (кнопки отпущены), установка состояния KEYS_NONE. Если установлен, снова установка состояния KEYS_WAIT_UP. 3 - После автомата обработки кнопок проверка флага DEFINE_KEYS_FLG. Если не установлен, то выход из блока обработки кнопок. Если установлен, то вычисление нажатой кнопки, запись в буфер идентификатора кнопки. Скажем, Key_1 = 0, Key_1 = 1, Key_1 = 2, Key_1 = 3. Подпрограмма обработки кнопок: Проверка буфера на идентификатор кнопки. Если ничего нет, выход. Если есть, то дальше можно задачу решить табличным способом. Код
Homdlers_Keys: .dw Homdler_Key_1, Homdler_Key_2, Homdler_Key_3, Homdler_Key_4 Homdler_Key_1: // Текущее состояние, следующее состояние, адрес функции. .db State_1, State_2, Function_1
0
|
0 / 0 / 0
Регистрация: 06.06.2011
Сообщений: 2,514
|
|
23.04.2013, 15:33 | 34 |
исходя из задачи автору надо отслеживать нажатие кнопок в течении 20-30 сек пока выбранная деталька по конвееру до приёмника доедет, и этих нажатий может быть больше чем одно. за 20-30 секунд еще несколько штук новых появится.
поэтому просто автомат состояний не подойдёт. нужно fifo для запоминания времени всех нажатий. решение выше привёл, там немного плюсов, но IAR EC++ умеет.
0
|
0 / 0 / 0
Регистрация: 04.08.2012
Сообщений: 102
|
|
23.04.2013, 15:36 | 35 |
To Korhom
вот рабочий проект Atmel Studyo 6.0 Proteus 7.10SP0 У Proteus сильно тормозит симуляция - кнопочки подольше держи нажатыми :) (где то 1сек) [49.4 Кб]
0
|
0 / 0 / 0
Регистрация: 20.02.2012
Сообщений: 60
|
|
23.04.2013, 15:45 | 36 |
Уважаемый _pv!
Вы верно поняли алгоритм работы программы. Только я на понял подойдет ли этот код для AVR Studyo GCC
0
|
0 / 0 / 0
Регистрация: 06.06.2011
Сообщений: 2,514
|
|
23.04.2013, 16:21 | 37 |
почему бы и нет?
0
|
0 / 0 / 0
Регистрация: 20.02.2012
Сообщений: 60
|
|
23.04.2013, 16:57 | 38 |
Сообщение от sbum
Код
void set_bit0 (void) { LED_PORT |=1<<LED0; // Зажигаем диодик SetTimerTask(rst_bit0, 200); //Запускаем вторую задачу } void rst_bit0 (void) { LED_PORT &= ~(1<<LED0); // Гасим диод. } void key_check(void) // - здесь опрашиваются кнопки { if (!(BTN_PIN & (1 << BTN1))) SetTimerTask(set_bit0, 600); }
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
|
|
23.04.2013, 17:34 | 39 |
to Korhom и _PV. Если вы согласны подождать несколько часов, пока я не освобожусь, то могу кое-какие результаты выложить..
0
|
0 / 0 / 0
Регистрация: 20.02.2012
Сообщений: 60
|
|
23.04.2013, 17:51 | 40 |
Сообщение от dymyurk1978
0
|
23.04.2013, 17:51 | |
23.04.2013, 17:51 | |
Помогаю со студенческими работами здесь
40
Разное время задержки Время задержки delay Изменить в функции время задержки Узнать время задержки в GIF Как сделать нулевой ШИМ сигнал на avr Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |