Отговори на тема  [ 13 мнения ] 
Прекъсване от RB4-7 
Автор Съобщение
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Пет Фев 05, 2010 7:53 pm
Мнения: 25
Мнение Прекъсване от RB4-7
Здравейте,

от известно време ползвам асемблер (не мога да кажа, че го знам отлично :) ), но реших да мигрирам към С. Захванах CCS компилатора и до колкото мога сам да се уча четейки хелп-а и официалния форум, до някъде вече успявам да се справям с малки програмки. :roll:
Но запецнах ..., та реших да потърся вашата помощ. Чета от доста време форума този като "гост" но явно само с четене не става, трябва и някой по знаещ да удари едно рамо. :oops:

До тук с представянето, време е за въпроса ми. :)
Сигурно е елементарен ама ...

Ползвам 16ф914
на порт RB7, 6, 5 има включени бутончета и когато са натиснати, подават 0 на входовете.
На RB1, 2, 3 са включени светодиодчета, та идеята ми е просто да си направя една фунцийка която да познава кой бутон е натиснат и този на RB7 примерно да разпознава дали е натиснат или е задъжан.
Използвам си една глобална променлива като флаг регистър, където да се отрази състоянието на бутоните и от където да се вземе инфо за по-нататъшното действие. За сега ползвам светодиодите за индикация на състоянието на бутоните.
(Знам, че на много места е писано по въпроса, но някои от примерните кодове не разбрах а и реших да си спретна сам.)

Ето кода от прекъсването:

Код:
#int_RB                     
void RB_isr(void)
{
int8 button_stat, count;

   button_stat=portb;
   if(!bit_test(button_stat,5)) bit_set(rb_int_flags,5);
   else if(!bit_test(button_stat,6)) bit_set(rb_int_flags,6);
   else if(!bit_test(button_stat,7))
        {
          for(count=0 ; count>=200; count++)
          {
            button_stat=portb;                       //тук малко не ми е ясно дали ще се изпълни този ред
            if(bit_test(button_stat,7)) break;
            else
            delay_ms(10);
          }
          if(!bit_test(button_stat,7) && (count>=200))
           { bit_set(rb_int_flags,4);
             bit_clear(rb_int_flags,7);
           }
          else bit_set(rb_int_flags,7);
        }
        else rb_int_flags=0;   
   clear_interrupt(INT_RB);
}


Проблема е, че искам при задържан бутон за RB7 (примерно 2 секунди), да се вдигне флаг 4. А той не се вдига. Дали ще задъжа бутона или ще го натисна и отпусна бързо си се вдига 7.
Сигурно грешката е много елементарна или просто начина по който съм го написал е не правилен, но като начинаещ ми е малко трудно да я открия.

И още едно дребно въпросче: това го правя като прекъсване, но може и да го направя като функция която ще се извиква в главната програма а не да се чака прекъсването. Ако реша да използвам това като управление на някакво елементарно меню, кое е за предпочитане - прекъсване или функцийка?

Благодаря Ви предварително.


Пет Фев 05, 2010 9:05 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Сеп 26, 2004 9:21 pm
Мнения: 30686
Местоположение: София
Мнение 
Ами ... има няколко неща които като цяло не ми допадат, най вече това чакане в прекъсване, после това бит тест .... много размива писането. Пиковете имат побитови команди, съответно в CCS може да работиш с битови променливи които директно се компилират в побитови команди, много по прегледно ще е ако работиш с битове, това не променя как работи програмата де.
Аз това го виждам да работи по друг начин, т.е. няколко други но не и този. Като цяло дори няма нужда да използваш това прекъсване, ако целта е да обработиш тия входове с времеви филтър си направи едно прекъсване по таймер.

rttc_isr()
......................
if(rb4)
{
if(rb4_time>200)
{
rb4_press=true;
}
}
else
{
rb4_time=0;
}
rb4_time++;
.............................

Така може да навържеш колкото поискаш входа и всички ще са с филтър по време. Прекъсването може да го използваш ако имаш опасения че може да изтървеш натискането, което пти 4 секундно изчакване няма как да стане. В този случай пак имаш варианти, може да проверяваш в самото прекъсване тези стойности, или просто там да вдигаш флаг rb4_state който да проверяваш в таймера. Разбира се тази проверка може и да не е в таймера а в основния цикъл, също така може да не инкрементваш много стойности а да ползваш твой таймерпо който зареждаш, и след това сравняваш, но това е по бавно като операции. Не збаравяй също че това прекъсване е по промяна, т.е. и при 1 и при 0.
След това променливата за състоянието на порта я дефинираш в самото прекъсване, тя не е глобална, въпреки че като гледма я изпозлваш май само в самото прекъсване. Не забравяй че прекъсване имаш и от порт 4.
Малко ми е объркано писането ти, това portb дефинирал ли си го някъде като byte=0x06 ? После в твоя код първо определяш кой е източника, да речем ОК, но както е написано ако натиснеш и пуснеш наистина мърда само 7, като задържиш би трябвало да се вдигне и 4 ама ... отделно хубавото на този порт с тия прекъсвания е че можеш да обработваш и 4-те, но ти изкуствено си си създал приоритет, 5,6,7 т.е. ако се задейства порт 5 или 6 ще пропуснеш порт 7.
Аха току що загледох for не ти е наред, count =0 ти е условието при което започваш, count++ е правилото по което се изменя, count >=200 определя докога ще се изпълнява този for, в твоя случай ще прекъсва всеки път тъй като count ти е 0, би трябвало да е count<200, т.е. цикъла ще с еизпълнява докато count е по малко от 200.


Пет Фев 05, 2010 10:12 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Пет Фев 05, 2010 7:53 pm
Мнения: 25
Мнение 
Благодаря за отговора и идеите, ще обмисля написаното и ще пиша дали съм се справил. :)

А да портб е дефиниран #byte PORTB =0x06
а за приоритета - идеята ми е простичка, тоест на едно прекъсване ме интересува само един бутон. Приоритета не би ли трябвало да е важен ако ще имам проверка за 2 натиснати бутона :?

Инак мисля да пробвам дали ще се справя с твоя метод. :)


пп: като направих count<200 стана, ама че грешка съм направил :oops:


Пет Фев 05, 2010 10:26 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Пет Фев 05, 2010 7:53 pm
Мнения: 25
Мнение 
Направих си едно файлче в което дефинирах битови променливи и ще го инклуудвам когато се ползва тази серия пикове.

По моя калпав начин тръгна програмката, все пак реших да я направя както си му е реда, но само искам да попитам ако използвам този "времеви филтър" с прекъсване, това значи ли, че програмата ще се прекъсва постоянно от таймера при препълване за да проверява дали е натиснат бутон?
Това постоянно прекъсване няма ли да пречи нещо?


Съб Фев 06, 2010 11:57 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пет Ное 25, 2005 11:41 am
Мнения: 1680
Мнение 
Да, програмата ще се прекъсва постоянно, това не пречи. Но там няма да проверяваш за натиснат бутон и обработката му, а само ще увеличваш стойността на времевия филтър. Но и това което Тони ти е написал не отнема много време, после някъде във друга функция ще обработиш:
if rb4_press {...};


Нед Фев 07, 2010 10:45 pm
Профил ICQ WWW
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пон Ное 22, 2004 11:24 pm
Мнения: 1923
Местоположение: Габрово
Мнение 
Това прекъсване не беше ли по фронт? :)

Аз бих го направил не с прекъсване а с таймер и броячи за закъснението. Като му дойде на таймера времето гледа тези входове и с елементарни проверки разбира дали дали бутона е задържан или не. :)


Пон Фев 08, 2010 6:04 pm
Профил ICQ
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Сря Яну 04, 2006 6:23 pm
Мнения: 43
Местоположение: Earth
Мнение Re: Прекъсване от RB4-7
iivantodorov написа:
...
И още едно дребно въпросче: това го правя като прекъсване, но може и да го направя като функция която ще се извиква в главната програма а не да се чака прекъсването. Ако реша да използвам това като управление на някакво елементарно меню, кое е за предпочитане - прекъсване или функцийка?

...



Добре де, ... и мен това ми е интересно (че и аз съм от начинаещите на С :) )
Дори да остане с това прекъсване или да се направи по таймер както казва Тони, какво му е предисмтвото пред това да се направи тази проверка с една фукнция без прекъсване ?
Или е все тая :)


Вто Фев 09, 2010 11:05 am
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пет Ное 25, 2005 11:41 am
Мнения: 1680
Мнение 
Ей, не четете, ей! Прекъсването дава еталонно време със необходимата резолюция. Там само си слагаш колкото са ти необходими броячи, и после ги обработваш в програмата. От къде иначе ще знаеш за колко време се е изпълнил даден цикъл на програмата?

ПРИМЕР:

Имаш вход, на който след получаване на сигнал, искаш да имаш изход със продължителност 100 мс.
Ако прекъсването ти е на 100 us /10kHz/, след получаване на входния сигнал нулираш брояча на времето, установяваш изхода и започваш да проверяваш брояча. След като достигне стойност 1000 /100ms x 10/, нулираш изхода.


Вто Фев 09, 2010 12:32 pm
Профил ICQ WWW
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Пет Фев 05, 2010 7:53 pm
Мнения: 25
Мнение 
Здравейте отново :)

Благодарение на напътствията на Тони си направих въпросното прекъсване от таймера и продължих да си мисля и да си реализирам по нататък идеите. :) Но нещо ме гложди защото не всеки път задържането на бутон сработва, тоест той сработва но трябва да го задържам рекалено дълго.

Значи ето го въпросното прекъсване по време:

Код:
#int_TIMER0
void TIMER0_isr()
{
scroll_press=0; select_press=0; set_press=0; set_hold=0;
if(!set)
{
  set_press=true;
  set_time++;
}
else set_time=0;
if(set_time>10)     
{
  set_hold=true;
  set_time=0;
}
   
if(!select) select_press=true;
if(!scroll) scroll_press=true;
}


Ето и с прекъсване по рб4-7:

Код:
#int_RB                   
void RB_isr()
{
int8 count;
scroll_press=0; select_press=0; set_press=0; set_hold=0;
 
if(!set)
  {
   for(count=0 ; count<=200; count++)
    {
     if(set) break;
     else
     delay_ms(10);
    }
   if(!set && (count>=200))
    {set_hold=1;
     set_press=0;
    }
   else set_press=1;
  }
if(!select) select_press=1;
if(!scroll) scroll_press=1;
}

Това работи коректно, но по някога не ми е удобно да прекъсва и при 0 и при 1 :) Та за това реших да ползвам само прекъсването по време.
Ето и майн програмката:

Код:
void main()
{

   setup_adc_ports(sAN0|sAN1|sAN2|sAN3|VSS_VDD);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_spi(SPI_SS_DISABLED);
   setup_lcd(LCD_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);        //Overflow 65,5ms
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);


   portb=0;                                     
   porta=0;                                       
   portc=0;
   trisa=0x0F;                                   
   trisb=0xF0;                                   
   trisc=0x00;

   lcd_init();                                   
   
   lcd_putc(" bla bla start "); 
   delay_ms(3000);
   

  // enable_interrupts(INT_RB);
   enable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);

While(True)
{
  detect_buttons1();
  switch(adc_channel)
    {
     case 0: {lcd_putc("\f temp 1 is:\n");
              adc_convert(0,8,'k');
             } 
       break;
     case 1: {lcd_putc("\f temp 2 is:\n");
              adc_convert(1,8,'v');
             } 
       break;
     case 2: {lcd_putc("\f temp 3 is:\n");
              adc_convert(2,8,'t');
             }
       break;
     case 3: {lcd_putc("\f temp 4 is:\n");
              adc_convert(3,8,'a');
             }       
    }

  delay_ms(200);
 
}
}


Задържайки тук бутон сет влизам в една функцийка за меню. Но по някога туй задържане може и да отнеме повече от 10 сек :D
Съмнява ме този delay дали като влезе в него прекъсването не действа ...
Обаче като го няма прекалено бързо се изпълнява програмата и показанията на дисплея премигват и трудно се вижда :)
Явно както тука всички обичат да казват, нещо не съм дочел. :D Но простете ми, сега се уча. :)
Благодаря!


Вто Мар 02, 2010 8:15 pm
Профил
Online
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Апр 20, 2005 12:02 pm
Мнения: 9119
Местоположение: Разград
Мнение 
Според мен не е от недочитане. Принципа ти на четене на бутоните е кекав. Зарежи тия прекъсвания - натискането на бутон е нещо което се извършва от човек и като такова то не може да бъде някакъв еталон за време, реакция и т.н. При бутона е по-важен така наречения дебоунс - отфлитриране разтрептяването на контактите.
За нединамични бутони съм си направил една функцийка още като почнах да се занимавам с МЦУ-та и досега си я ползвам непроменена.

Ще ти дам нещо като алгоритъм, а останалото оставям на теб :
1. Един от таймерите си го правя за ... таймер :) примерно timer1 на 9.1 Hz (макс прескалер). В прекъсването на таймера само намалявам една променлива (Т1) ако е >0.
2. Чета си порта (зависи дали целия или само битове - ненужните се маскират - AND,OR и т.н.) - слагам го в променлива Б1 примерно.
3. Проверявам дали е Б1>0. Ако не е - ясно (тука и Б2 от по-долу става 0) . Ако е:
3.1. Сверявам Б1 с другата променлива Б2. Ако Б2 е нула, Б2=Б1, Т1=12
3.2.1 Ако Б2=Б1 (вече натиснат и задържан бутон), при Т1>0 Б1=0 - тука става все едно не е натиснат бутона.
3.2.1 Б2=Б1, при Т1=0 - Т1 го правя примерно 6 вече, Б1 си го оставям - таймера е изтекъл, бутона е натиснат и се отчита.
Цялото това нещо го викаш когато ти скимне - въобще не е чувствително кога става (е не чак толкова рядко че да не хваща въобще - примерно 100-200 пъти в секунда е предостатъчно). След като го извикам си полвам битовете на Б1.
Винаги след задържане изчаква време и пак подава сигнал, ако продължиш да дръжиш подава вече на по-кратки интервали. Времето за изчакване не гълта процесорно време. А работи точно като клавиатура на компютър. С малко модификации може да се направи след 10-тия сигнал да прави нещо друго, следене за отпускане на бутоните и т.н.


Вто Мар 02, 2010 8:59 pm
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Сеп 26, 2004 9:21 pm
Мнения: 30686
Местоположение: София
Мнение 
То идеята ми като цело беше че изпозлвайки пекъсване по време не ти трябва прекъсване по RB ..


Сря Мар 03, 2010 5:50 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Пет Фев 05, 2010 7:53 pm
Мнения: 25
Мнение 
Ама да, аз и ползвам само едното - по време.
Другото просто го копирах тук, за да спомена, че с него работи безпроблемно.
А идеята ми да използвам прекъсване за бутоните е, че влизайки и ровейки в менюто, и след 1-2 мин не се натисне бутон, програмата да се върне в майн. :) И така с прекъсването щеше да е лесно в него да нулирам таймера за връщането.
Сигурно може да стане и с кучето, но трудно бих реализирал голям интервал.


Чет Мар 04, 2010 1:32 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Сеп 26, 2004 9:21 pm
Мнения: 30686
Местоположение: София
Мнение 
Е ами какво типречи да сложиш още един таймер който нулира отделно при всяко натискане на бутон ... там където са ти таймерите по които правиш филтриране слагаш още един, само че не по един за всеки бутон а еидн общ без значение кой бутон се натиска ти си го нулираш, а ако стане достаъчно голям излизаш ....


Чет Мар 04, 2010 11:44 am
Профил
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 13 мнения ] 

Кой е на линия

Потребители разглеждащи този форум: 0 регистрирани и 0 госта


Вие не можете да пускате нови теми
Вие не можете да отговаряте на теми
Вие не можете да променяте собственото си мнение
Вие не можете да изтривате собствените си мнения
Вие не можете да прикачвате файл

Търсене:
Иди на:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Хостинг и Домейни