• Объявления

    • admin

      Просьба всем принять участие!   24.11.2017

      На форуме разыгрывается спектроанализатор Arinst SSA-TG LC (цена 18500 руб). Просьба всем перейти по ссылке ниже и принять участие!
Alex

Подключение Кнопок К Микроконтроллерам

98 сообщений в этой теме

Alex    525

В этой теме обсуждаем подключение кнопок к МК и алгоритмы их обработки.

---------------------------------------------------------------------------------------------------------------

Итак. Первый пример обработки кнопок от mail_robot для PIC'ов. http://forum.cxem.ne...20#comment-2213207

Ещё один пример от mail_robot под АРМы. http://forum.cxem.ne...20#comment-2213705

Еще один вариант описания алгоритма обслуживания клавиатуры от ST_A - http://forum.cxem.ne...20#comment-2214985

Вариант алгоритма от Illusi0ns - http://forum.cxem.ne...20#comment-2279559 . Код несколькими постами дальше - http://forum.cxem.ne...40#comment-2279693

Вариант от меня - http://forum.cxem.ne...40#comment-2293341 компилятор - CVAVR

Ещё один вариант от POlSS0N - http://forum.cxem.net/index.php?showtopic=157804&st=60#comment-2380479 Пример под PIC16f877a.

Изменено пользователем Alex

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Быстрый заказ печатных плат

Полный цикл производства PCB по низким ценам!

  • x
    мм
Заказать Получить купон на $5.00
DmitryS    25

Всем доброго дня !

В посте я боролся с помехами , помехи вроде победил , теперь решил немного модернизировать программу , и сделать опрос кнопки управления воротами не в основном цикле , а повесить кнопку на INT0 , и осуществлять управление в обработчике прерываний .

 /* Garazh_vorota3.c
* Created: 20.08.2015 23:50:50
*  Author: Dmitry S
*/
//ATtiny13A Управление секционными воротами
#define F_CPU 1200000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define DIRECT_OPEN  PORTB |= (1<<0)//&= ~(1<<0)
#define DIRECT_CLOSE PORTB &= ~(1<<0)//|= (1<<0)
#define MOTOR_STOP  PORTB |= (1<<2)//&= ~(1<<1)
#define MOTOR_LAUNCH  PORTB &= ~(1<<2)//|= (1<<1)
unsigned char a=1;
void Stop() // Остановка двигателя
{
   _delay_ms(20);
   MOTOR_STOP;
   _delay_ms(50);
   DIRECT_OPEN;
};
ISR(INT0_vect)
{
   GIMSK &= ~(1<<INT0);
   switch(a)
       {
           case 1:
           _delay_ms(50);
           DIRECT_OPEN; // Вращение на открытие
           _delay_ms(100);
           MOTOR_LAUNCH; // Пуск двигателя
           a=2;
           break;

           case 2: // Stop
           Stop();
           a=3;
           break;

           case 3:
           _delay_ms(50);
           DIRECT_CLOSE; // Вращение на закрытие
           _delay_ms(150);
           MOTOR_LAUNCH; // Пуск двигателя
           a=4;
           break;

           case 4: //Stop
           Stop();
           a=1;
           break;
       }
}
ISR(PCINT0_vect) // обработка прерывания
{
   if (!(PINB &(1<<PINB3))) // Только если концевик замкнут
   {
       MOTOR_STOP;	  // остановить двигатель
       _delay_ms(50);
       DIRECT_OPEN;
       a++;		    // определить направление вращения
       if(a==5)
       a=1;
   }
   if (!(PINB &(1<<PINB4)))  // Защита заклинивания ворот по току двигателя
   {
       _delay_ms(300); // отфильтровываем пусковой ток
       if (!(PINB &(1<<PINB4)))
       {
           MOTOR_STOP;	  // остановить двигатель
           _delay_ms(50);
           DIRECT_OPEN;
           a++;		    // определить направление вращения
           if(a==5)
           a=1;
       }
   }
}

int main(void)
{  
   // Настрока порта B
    DDRB = 0b00000101;
   PORTB = 0b00011111;

   PCMSK |= (1<<PCINT4) | (1<<PCINT3);// Настройка прерывания PCINT3 PCINT4
   MCUCR |= (ISC01<<1)    | (ISC00<<0);//INT0 по спадающему фронту
   GIMSK |= (1<<PCIE) | (1<<INT0);//Разрешение прерываний
   GIFR |= (1<<PCIF) | (1<<INTF0);//Сброс флагов
   sei();

   while(1)
   {
   GIMSK |= (1<<INT0);   
   }
}

И нихрена у меня не получилось , INT0 ловит дребезг кнопки просто жутко , хоть и прописано в коде уходить в прерывание по спадающему фронту , преывание ловит его и при размыкании кнопки . В Протеусе все работает отлично , в железе просто жуть . Я пробовал даже запрещать прерывание INT0 в обработчике , ни чего не помогает . Пришлось все возвращать в зад . Причину такого поведения INT0 я что то не догоняю , ведь прерывания по PCINT работают вполне корректно ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
my504    166

Это какой то жуткий бред с прерыванием в обработчике которого стоят задержки по 50 мс.

Причем тут вообще прерывания, если кнопка нажимается РУКОЙ, то есть задержка в обработке этого события никаким боком к реальному времени не привязана.

Правда если у Вас алгоритм строится на таких же задержках, то тогда вообще нет вменяемого решения...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
mail_robot    1 209

Кнопки это вообще больная тема для новичков.

При размыкании кнопки происходит тот же самый дребезг, что и при замыкании. Поэтому вылавливание фронтов пустая затея. Необходимо по входу в прерывание его запретить (и только его), поставить на эту тему глобальный флаг. По выходу из прерывания отработать антидребезг и сбросить флаг и только после этого опять разрешить прерывание по входу.

Но вообще вешать кнопку на прерывание по входу не лучшая идея. Кнопка это всегда медленное событие и мгновенная его обработка лишена здравого смысла. Кнопки обычно обрабатываются в основном цикле процедурой опроса. Быстрее им просто не требуется

INT0 предназначен в основном для мгновенной обработки несистемных событий, требующих именно безотлагательных действий контроллера. К примеру прием ИК посылки. Хотя и это не та задача, потому как она тоже достаточно неторопливая. Но просто как пример

Изменено пользователем mail_robot

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Viktor26    300

настроите таймер на сброс при совпадении, отмеряйте через сколько тактов при ваше частоте пройдет 20 мс, и в этом обработчике опрашивайте кнопку. заведите 2 флага обработки этой кнопки, и антидребезг вам обеспечен и основной цикл всякой фигней не занимается, и делеи проч

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
COKPOWEHEU    249

Плюс если линия от кнопки до контроллера достаточно длинная, надо озаботиться подавлением помех

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
DmitryS    25

Я почему решил попробовать повесить кнопку на прерывание INT0, потому что в моем в первоначальном исполнении хоть все и работает , но есть небольшой недостаток , когда кнопка опрашивается в основном цикле , если кнопку долго держать нажатой , больше 1сек , выполнится следующее действие , т.е выбор в операторе switch будет происходить по череди с интервалом чуть больше секунды , вот я и хотел избавится от этого недостатка , повесив кнопку на INT0 , что бы сколько кнопку не держи нажатой , пока её не отпустишь и не нажмешь по новой , ни чего не происходило .

/*
* GarVorota_2.c
*
* Created: 13.04.2015 21:57:50
* Author: Dmitry
*/


#define F_CPU 1200000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define NAPR_OPEN PORTB |= (1<<0)//&= ~(1<<0)
#define NAPR_CLOSE PORTB &= ~(1<<0)//|= (1<<0)
#define DVIG_STOP PORTB |= (1<<1)//&= ~(1<<1)
#define DVIG_PUSK PORTB &= ~(1<<1)//|= (1<<1)

unsigned char a=1;
//unsigned char b;
ISR(PCINT0_vect) // обработка прерывания
{
if (!(PINB &(1<<PINB3))) // Только если концевик замкнут
{
DVIG_STOP;	 // остановить двигатель
_delay_ms(50);
NAPR_OPEN;
a++;		 // определить направление вращения
if(a==5)
a=1;
}
if (!(PINB &(1<<PINB4))) // Защита заклинивания ворот по току двигателя
{
_delay_ms(300); // отфильтровываем пусковой ток
if (!(PINB &(1<<PINB4)))
{
DVIG_STOP;	 // остановить двигатель
_delay_ms(50);
NAPR_OPEN;
a++;		 // определить направление вращения
if(a==5)
a=1;
}

}
}

void Stop() // Остановка двигателя
{
_delay_ms(20);
DVIG_STOP;
_delay_ms(50);
NAPR_OPEN;
};


int main(void)
{ // Настрока порта
DDRB = 0b00000011;
PORTB = 0b00011111;
// Настройка и разрешение прерывания PCINT3 PCINT4
PCMSK = (0<<PCINT5) | (1<<PCINT4) | (1<<PCINT3) | (0<<PCINT2) | (0<<PCINT1) | (0<<PCINT0);
GIMSK |= (1<<PCIE); GIFR |= (1<<PCIF);
sei();

while(1)
{
_delay_ms(1000);
while (PINB &(1<<PINB2)){}
switch(a)
{
case 1:
_delay_ms(100);
NAPR_OPEN; // Вращение на открытие
_delay_ms(100);
DVIG_PUSK; // Пуск двигателя
a=2;
break;

case 2: // Stop
Stop();
a=3;
break;

case 3:
_delay_ms(100);
NAPR_CLOSE; // Вращение на закрытие
_delay_ms(100);
DVIG_PUSK; // Пуск двигателя
a=4;
break;

case 4: //Stop
Stop();
a=1;
break;
}

}
}

Плюс если линия от кнопки до контроллера достаточно длинная, надо озаботиться подавлением помех

Немного по подробней можно , примерно как должна выглядеть эта защита ? Изменено пользователем DmitryS

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    525

У Вас все задержки дальнейшей программы из-за delay-ев. Не используйте их без особой надобности.

Для чего втыкать задержку, скажем на 100 миллисекунд, если за это время контроллер может делать что-то полезное ? А ведь delay_ms - это просто, извиняюсь за выражение, тупое зацикливание программы. Пустой цикл...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
DmitryS    25

Уважаемый Alex , я знаю , что делей это просто задержка и что в это время МК мог бы заняться еще чем то , но я не могу придумать контроллеру задачу на это время , а ту задачу которую я ему задал , он поганец отказывается выполнять . Шутка .А по поаду 100мс , так это я пробовал бороться с помехами , потому такие большие и поставил , изначально да и сейчас можно уменьшить до 20-50мс , это антидребезг . А вот другие задержки нужны , потому как два реле которые меняют полярность на двигателе , могут в силу своих конструктивных особеностей страбатывать не одновременно , по этому я переключаю сначала эти реле , жду когда они сработают , и лишь потом другим реле пускаю на них ток . На всякий случай так сказать .

Изменено пользователем DmitryS

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    525

Чтобы зафиксировать отжатие/нажатие кнопки, не обязательно его ждать. Достаточно просто поймать момент изменения уровня на ноге МК. И ловить его можно необязательно внешним прерыванием, а периодичным опросом состояния входа, к которому подключена кнопка. Даже, я бы сказал не можно, а нужно - во избежании поимки дребезга.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
DmitryS    25

Аlex , а я что делаю ?

_delay_ms(1000);
while (PINB &(1<<PINB2)){}
switch(a)
{
case 1:
_delay_ms(100);
NAPR_OPEN; // Вращение на открытие
_delay_ms(100);
DVIG_PUSK; // Пуск двигателя
a=2;
break;

case 2: // Stop
Stop();
a=3;
break;

case 3:
_delay_ms(100);
NAPR_CLOSE; // Вращение на закрытие
_delay_ms(100);
DVIG_PUSK; // Пуск двигателя
a=4;
break;

case 4: //Stop
Stop();
a=1;
break;
}

И я опрашиваю состояние входа . Может это надо делать как то по другому ?

Изменено пользователем DmitryS

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    525

_delay_ms(1000);
while (PINB &(1<<PINB2)){}

У Вас задержка на 1 секунду (зачем, совершенно не понятно) и ожидание уровня на входе ! Это не фиксирование изменения, а просто зацикливание программы, с ожиданием уровня.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
DmitryS    25
У Вас задержка на 1 секунду (зачем, совершенно не понятно)
Если убрать эту задержку , то не возможно предсказать что выберется в свитче Изменено пользователем Alex
Цитата

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    525
не возможно предсказать что выберется в свитче
Это как ?

В свиче выберется всегда тот пункт, значение которого имеет переменная в скобках.

Видимо, я то-то недопонимаю...

Что у Вас на PINB2 ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
DmitryS    25
не возможно предсказать что выберется в свитче
Это как ?

В свиче выберется всегда тот пункт, значение которого имеет переменная в скобках.

Видимо, я то-то недопонимаю...

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

На PINB2 кнопка , этот пин и опрашивается

Изменено пользователем DmitryS

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    525

Всё понятно.

Сделайте тогда, хотя бы, так :

while(1){
static char butt_cur=0, butt_prev=0; // Не знаю, есть ли булевые переменные в вашем компиляторе. По этому - char
//.....................
//.....................
_delay_ms(10);
butt_cur=((PINB &(1<<PINB2))==0); // 0- активный уровень кнопки
if(butt_cur && !butt_prev){ // Если нажали кнопку
//..................... // Тут код, который нужно выполнить после нажатия
//..................... // Т.б. , как я понял, switch.
}
butt_prev=butt_cur;
//.....................
// Тут выполняем что-то полезное. Но не задерживаем надолго программу.
//.....................
}

максимум, на сколько будет задерживаться цикл - 10 миллисекунд.

Но по уму, опрос ПИНа и сравнение его с предыдущим значением нужно вынести в обработчик прерывания по таймеру, настроенный на 10 мс. Тогда основной цикл полностью освободиться от этой рутины и можно будет его удерживать любое время.

Кстати, вот это :

butt_cur=((PINB &(1<<PINB2))==0);
if(butt_cur && !butt_prev){
..........
}
butt_prev=butt_cur;

и есть детектирование изменения уровня. Т.е. опрашиваем вход, сравниваем с предыдущим на изменение, сохраняем текущее значение для следующего опроса (оно потом будет предыдущим).

Этот код нужно вынести в обработчик по таймеру и выставлять флаг нажатой кнопки. А в основном цикле уже этот флаг опрашивать, не забыв его сбросить после опроса. Тогда Вы в основном цикле, в любой момент времени, сможете узнать была ли нажата кнопка, задерживая цикл абсолютно на любое время.

Вот и вся магия...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
DmitryS    25

Спасибо Alex за пример , но честно , я мало понял как это работает , особливо вот эта строчка

butt_cur=((PINB &(1<<PINB2))==0); // 0- активный уровень кнопки

Но вы меня наталкнули на мысль , что надо внутри каждого case , сделать проверку , на нажата ли еще кнопка

Выглядеть будет примерно так

while (PINB &(1<<PINB2)){}
switch(a)
{
case 1:
_delay_ms(20);
NAPR_OPEN; // Вращение на открытие
_delay_ms(100);
DVIG_PUSK; // Пуск двигателя
if (~PINB &(1<<PINB2))
{
a=1;
}
else a=2;
break;

case 2: // Stop
Stop();
if (~PINB &(1<<PINB2))
{
a=2;
}
else a=3;
break;

case 3:
_delay_ms(20);
NAPR_CLOSE; // Вращение на закрытие
_delay_ms(100);
DVIG_PUSK; // Пуск двигателя
if (~PINB &(1<<PINB2))
{
a=3;
}
else a=4;
break;

case 4: //Stop
Stop();
if (~PINB &(1<<PINB2))
{
a=4;
}
else a=1;
break;
}

Изменено пользователем DmitryS

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    525
особливо вот эта строчка
В переменную butt_cur заносится инвертированное значение ПИНа. Т.б. состояние кнопки (=1 - нажата, =0 - отжата).

А дальше это значение сравнивается с предыдущим. Этим самым сравнением мы и ловим изменение состояния кнопки.

надо внутри каждого case , сделать проверку , на нажата ли еще кнопка
Зачем ? Я же Вам написал готовый пример. Разберитесь с ним, он на самом деле прост до безобразия :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alexeyslav    590
если кнопку долго держать нажатой , больше 1сек , выполнится следующее действие

Как уже говорили, это из-за того что вы просто проверяете уровень состояния кнопки.

Для вашей задачи, его надо не просто проверять а еще и сравнивать с предыдущим. А это предыдущее значение надо где-то хранить, в переменной.

Тогда, вместо того чтобы просто сравнить значение вы смотрите состояние кнопки - ага, нажата! А потом смотрите предыдущее состояние кнопки - если она нажата была до этого, то ничего не делать а если отпущена - вот только тогда что-то делать с ней.

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

И после всего этого сравнения не забыть скопировать текущее состояние кнопки в ту самую переменную.

Теперь этот алгоритм можно выполнять хоть 10 раз в секунду - соответствующее действие произойдет лишь однократно для нажатия и если это необходимо - для отпускания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
mail_robot    1 209

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

ну мало ли...

Изменено пользователем mail_robot

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
my504    166

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

Причем совершенно не понимая как оно работает и с чем конфликтует.

Очень ценными являются такие идеи, которые адаптируются в проекты как ФОНОВЫЙ ПРОЦЕСС с минимальным занятием ресурсов. Особенно вычислительных. Обработка кнопок должна напоминать работу официанта в ресторане. То есть основной процесс (клиент) не должен ощущать его присутствия иначе как по результату действия.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Viktor26    300

Пример с использованием таймера Т0 в Atmega8

Особых настроек этот таймер не требует, так-как он умеет только генерировать прерывание по переполнению и ничего больше.

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

условно тактируем МК от внутреннего RC 1 МГц

и так, подключаем все необходимые файлы к проекту, не забываем про interrupt.h

настраиваем порты как Вам нужно,

записываем единичку в нужный бит регистра TIMSK (какой бит отвечает за разрешения прерывания по событию "переполнение Т0" смотрите в даташите)

теперь запускаем таймер с делителем \256. Почему \256? потому что с таким коэффициентом деления он будет переполнятся раз в ~65мс.

теперь в обработчике прерывания от Т0 опрашиваем кнопку, один раз в ~65мс, вот и антидребезг.

если кнопка нажата выставляем флаг в единицу(флаг-любая переменная с удобным для вас именем)

в главном цикле программы проверяем флаг, если он равен единице выполняем нужный код, ВНИМАНИЕ, в конце которого НЕ забываем сбросить флаг.

На вот такой метод меня подтолкнул Геннадий(спасибо ему огромное, многому научил меня), но он делал это немножечко мудрее, как-то с двумя флагами, так и не въехал как. Хотя и описанная мною конструкция тоже очень хорошо и без сбоев работает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
солар    123

Первый флаг flag1 - предыдущее состояние кнопки. Второй флаг flag2 - текущее состояние кнопки.

flag1= flag2;
flag2= читаем пин кнопки.
if(flag1 && !flag2) //- момент нажатия кнопки
if(!flag1 && !flag2) //- кнопка удерживается нажатой
if(!flag1 && flag2) //- момент отпускания кнопки
if(flag1 && flag2) //- кнопка не нажата.

Тут вам и антидребезг, и состояния кнопки. Надеюсь, теперь въезжабельно.

Изменено пользователем солар
  • Одобряю 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
mail_robot    1 209

Ну начнем пожалуй с простого варианта, но в общем то годного для многих задач, не требующих постоянного внимания процессора. Это задачи типа - нажал на кнопку, сработало реле. Потом отпустили кнопку, чего то ждем. В принципе это аналогично использованию функции delay, только чуть элегантнее.

Написано для PIC16F886

Суть в том, чтобы заставить работать программу в ритме с системными тиками, которые формируются в прерывании одного из таймеров и позволяют в любом месте программы получать задержки нужной продолжительности. Я использую обычно TMR0 для этой цели.

Перво наперво надо сконфигурировать таймер. Делается это в регистре OPTION_REG

void InitApp(void)
{
...
OPTION_REG = 0b01010110; // O_R<7>=0 init individual latch for port B (включить индивидуальную подтяжку порта В)
//			 |___________ O_R<5>=0 timer 0 internal CLK source Fosc/4 (тактирование таймера 0 от внутреннего генератора)
//				 |_________ O_R<3>=0 prescaller assigned to Timer 0 (говорим что таймер будет работать с предделителем)
//				 |||______ O_R<2:0>=110 prescaller rate 1:128 (устанавливаем предделитель в значение 128)
//							 Timer 0 period = 1/120 sec (теперь период переполнений таймера будет 1/120 секунды или 8,3 мс)

T0IE = 1;				 // Timer 0 interrupt ON (обязательно разрешаем прерывания от таймера 0)
// не забываем о том что чуть позже будет неплохо разрешить еще и прерыывания в принципе GIE = 1 как только нам понадобится начать считать тики;
.
.
.

после такой инициализации таймер TMR0 дает нам 120 прерываний в секунду. Достаточно мелко для относительно быстрых процессов и достаточно крупно для реализации долгих задержек если требуется.

Код прерывания таймера

void interrupt isr(void)
{
if (T0IF) // если произошло прерывание таймера (переполнился)
{
 TMR0 = 126;					 // перезагружаем таймер заново некоторым значением, которое дает нам более менее близкий к милисекунде интервал. Можно за точностью не гнаться, если она не нужна особо. Но точных часов тут сделать не получится
 T0IF = 0;					 // сбрасываем флаг прерывания (сам он не сбросится)
 if (TICK == 255) TICK = 0;	 // на всякий случай проверяем переполнение системных тиков если где-то прозевали
 TICK++;						 // если с тиками все в порядке, фиксируем тик
}		
}

тут надо пояснить, что в основной программе обьявлена глобальная переменная

char TICK;

, которая глобально хранит значение текущего количества системных тиков. Для чего они нужны увидим чуть ниже. Эта переменная обнуляется в основной программе всякий раз перед и после окончания использования. Тем самым мы добиваемся ее постоянной готовности к делу и следим, чтобы она никогда не переполнилась. А если переполнилась, то это можно использовать как индикатор некой ошибки и включать процедуру обработки исключения, вплоть до перезапуска программы. Можно считать это софтовым WDT таймером, но с более интеллектуальной логикой работы.

Итак, как же пользоваться тиком

Вот простой пример полусекундной задержки

TICK = 0;
while (TICK!=60);

вот код обработки нажатия на кнопку

 if (RB4==0) // нажали на кнопку, активный уровень 0
 {
	 SendMedic(); // делаем чтото полезное пока не отвлекаясь на кнопку (я посылаю ИК команду)

	 TICK = 0; // сбрасываем счетчк тиков
	 while (TICK<5) // отсчитываем 5 мс на защиту от дребезга при замыкании (на всякий пожарный)
		 // если процедура SendMedic() долгая, то можно и не делать защиту
	 while (!RB4); //Ждем когда юзер отпустит кнопку
	 TICK = 0; // опять сбрасываем системный тик
	 while (TICK<5); // отсчитываем еще 5 мс для подавления дребезга
 }

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

В принципе можно это все дело оформить и на delay, тем самым немного упростив. Главное понять общи принцип

проект целиком

Аптечка умная.zip

Изменено пользователем mail_robot
  • Одобряю 2

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас