Перейти к содержанию

Короткое И Длительное Нажатие Кнопки. Как?


poligon

Рекомендуемые сообщения

Здравствуйте. Собираю себе фонарь на мощном светодиоде. Возникла необходимость регулировать всё одной кнопкой. А именно: короткое нажатие - вкл/выкл, удержание кнопки во включенном состоянии - регулировка яркости (аппаратный 8-ми битный ШИМ). Т.е. пока держим кнопку гоняем OCR2 по кругу 0-255-0-255 и т.д.

Встал в ступор относительно этих самых нажатий :blink: В коде реализовать не могу

Итак:

1. Как только заметили ноль на пине, нужно подождать 40-50 мс и проверить ещё раз пин;

2. Если там по прежнему ноль, то это не помеха/дребезг;

3. Запустить при этом увеличение какой либо переменной;

4. Если на выходе стал 1 (кнопку отпустили) то остановить приращение переменной;

5. Посмотреть до скольки досчитали, если меньше отсечки "длинного нажатия", то это короткое нажатие, если больше - то это долгое нажатие;

6. Сбросить всё, вернуться в режим ожидания.

Но как это записать в прерывании не знаю. Тупой какой то я :(

Сделал так. Не работает. В принципе понимаю почему, потому что нет обработки дребезга контактов и переменная state постоянно будет меняться. Но по другому не знаю как написать. Может кто подскажет.

#define button PINB.0 

volatile bit long_push = 0;
volatile unsigned int cnt = 0;
volatile bit state = 0;
...
// Clock value: 7812,5 Hz
TCCR0=0x05;
TCNT0=0xB2;
...
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
                      // Reinitialize Timer 0 value
 TCNT0=0xB2;          // срабатывание каждые ~10 мс

 if (!button) {       // если нажата кнопка т.е. PINB.0 не равен 1
   cnt++;             // прибавляем счетчик
   if (cnt>65534) {   // если кому то вздумается очень долго удерживать кнопку
     cnt=101;         // чтобы не перевалили за значение 65535
     }
   }
 else if (button) {   // если на PINB.0 стал 1 
   cnt=0;             // то сбрасываем счетчик
   long_push=0;       // сбрасываем бит долгого нажатия
   }

 if ((cnt > 3) && (cnt < 100)) {   // проверяем условие короткого нажатия (держали > 40 мс и < 1 сек; 10мс * 100 срабатываний)
                                   // заодно и подавляем дребезг 40 мс  (10 мс * 4 срабатывания)
   if (!state) {                   // если фонарь выключен, то
     OCR2=0x7D;                    // установили 50% ШИМ
     TCCR2=0x6A;                   // запустили таймер  (вкл)
     state = 1;                    // флаг что фонарь включен
     }
   else if (state) {               // если фонарь включен, то
     OCR2=0x00;                    // выключили ШИМ
     TCCR2=0x00;                   // остановили таймер (выкл)
     state = 0;                    // флаг что фонарь выключен
     }
   }

 if (cnt > 100) {                  // если держим > 1 сек - это длинное нажатие
   long_push = 1;                  // потом проверяем long_push в основном цикле
   } 
}

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

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

Фонарик на мк это жестоко))

Однако аппартное устранение дребезга помойму лучше.

А по коду, по идее если отпускают кнопку, то сразу весь алгоритм вывалиться тут

  else if (button) {   // если на PINB.0 стал 1 
   cnt=0;             // то сбрасываем счетчик
   long_push=0;       // сбрасываем бит долгого нажатия
   }

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

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Я бы кусочек кода

 if (!button) {   	// если нажата кнопка т.е. PINB.0 не равен 1
   cnt++;         	// прибавляем счетчик
   if (cnt>65534) {   // если кому то вздумается очень долго удерживать кнопку
     cnt=101;     	// чтобы не перевалили за значение 65535
     }
   }

написал бы так

 if (!button) {   	// если нажата кнопка т.е. PINB.0 не равен 1
if (cnt<101) {   // если кому то вздумается очень долго удерживать кнопку
        cnt++;         	// прибавляем счетчик
 	}
 }

Пока ты жив, надежда есть.

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

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Пока только вот это родить смог. Первое событие - кнопка нажата, второе - кнопку отжали

volatile bit enable = 1;
volatile unsigned int timer_count = 0;
...
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
                                   // Reinitialize Timer 0 value
 TCNT0=0xB2;                       // срабатывание каждые ~10 мс  
 timer_count++;                    // постоянно считаем 10 мс интервалы  
 if (timer_count>65534) {          // если насчитали больше 65535, то сбрасываем на 0    
   timer_count=0;                      
   } 

 if ((button == 0) && (enable == 1)) {   // если нажата кнопка и это первое срабатывание
  timer_count = 0;                    // сбрасываем счетчик
  enable = 0;                         // запрещаем сброс timer_count (случайный дребезг)
   }

 if (timer_count == 4) {                 // подавили дребезг 40 мс
   if (button == 0) {                    // если кнопка всё ещё нажата через 40 мс
   // кнопка нажата               // фиксируем что кнопку действительно нажали
  }
   }

 if (timer_count == 30) {                // если через 300 мс кнопка не нажата, то её отпустили
     if (button == 1) {
    // кнопку отпустили
	enable = 1;               // разрешаем сброс timer_count
    }
   }
}

Дальше никак :blink:

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

Как подождать 40 мс ???

#define button PINB.0 

volatile unsigned int timer_count = 0;

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
                                   // Reinitialize Timer 0 value
 TCNT0=0xB2;                       // срабатывание каждые ~10 мс    
 timer_count++;                    // постоянно считаем 10 мс интервалы  
 if (timer_count>65534) {          // если насчитали больше 65535, то сбрасываем на 0    
   timer_count=0;                      
   } 

 if (button == 0) {          // если на пине 0, то надо подождать 40 мс и опять проверить пин
                             // если через 40 мс там по прежнему 0, то кнопку нажали   
   }                         // НО КАК ПОДОЖДАТЬ 40 мс ???
}

Я это прекрасно понимаю что это 4 переполнения TCNT0. Но как??? Если сбросить при этом timer_count в ноль и ждать пока timer_count не станет больше 4, то при дребезге счет нарушится!!! Потому что на пине будет то 0 то 1

Изменено пользователем poligon
Ссылка на комментарий
Поделиться на другие сайты

Делайте все по порядку, сразу, без ошибок и отладки не одна программа не пишеться.

Сначала сделайте простое включение выключение, потом добавьте длительное нажатие с ШИМом, а уже потом боритесь с дребезгом, хоть программно хоть аппаратно.

ждать можно либо счетчиком, приращать его при нажатии если он увеличился к примеру до 3х значит кнопка нажата и это не дребезг, либо каким нибудь Delay'ем. Честно сказать не раз не писал софт под МК, да и вообще в Си не раз не писал. поэтому немогу подсказать точно.

Изменено пользователем CHAOSITO
Ссылка на комментарий
Поделиться на другие сайты

Делайте все по порядку, сразу, без ошибок и отладки не одна программа не пишеться.
Во-во.У меня программатор греется,когда я думать начинаю. :)
Как подождать 40 мс ???

Прочитайте,справку к своей программе в которой пишете.Нужно найти функцию задержки.

Например в код вижене.В начале подключается библиотека-#include <delay.h>

Дальше в тексте,где нужна задержка delay_ms(500);или там например delay_us(500);в микросекундах.Конечно это не идеально точно,тк контроллер может физически не дать этого времени(тактовая частота,коэфф деления итд)но для таких целей как раз!

CHAOSITO.А что это за программа,в которой Вы алгоритм рисовали? :huh:

Изменено пользователем evgesha53
Ссылка на комментарий
Поделиться на другие сайты

  • 10 лет спустя...

подниму старую тему. не давно сам задался таким вопросом. вот такой код у меня получился. 

	//---------------------обработка кнопки энкодера-----------------------------
			if(button()) 
			{
				button_time++;    
			}
		}
		//---------------------работаем вне таймера 1 с результатами энкодера------------
		if (!button && button_time>200)//т.к. таймер срабатывает 100 раз в сек. то 200 будет = 2с
		{
				
			button_time = 0;
			button_long = 1;
			return button_long;
		}
        if (!button && button_time > 0 && button_time < 200)
		{
			button_time = 0;
			button_shot = 1;
			return button_shot;
		}

 

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

  • 1 месяц спустя...

Конечные автоматы. Состояния:

KBD_INIT. Инициализация.

KBD_WAIT_DOWN. Следим за нажатием. Если не нажато, выход. Если нажато, установка программного таймера на 20-40 мс, выход. Установка состояния KBD_DOWN.

KBD_DOWN. Если время не вышло, выход. Если вышло, проверка нажатия. Если не нажато, то помеха, установка состояния KBD_WAIT_DOWN. Если нажато, установка флага, события, что короткое нажатие. Установка таймера длительного нажатия и состояния KBD_HOLD_REPEAT.

Ну и так далее, смысл понятен.

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

  • 4 недели спустя...
  • 2 недели спустя...

вот что у меня получилось

	if(button()) 
			{
				button_time++;    
			}
		}
		//---------------------работаем вне таймера 1 с результатами энкодера------------
		if (!button() && button_time>200)//т.к. таймер срабатывает 100 раз в сек. то 200 будет = 2с
		{
				
			button_time = 0;
			button_long = 1;
		}
        if (!button() && button_time > 0 && button_time < 200)
		{
			button_time = 0;
			button_shot = 1;
		}
		if (button_shot && speed==0)
		{
			start();
			button_shot = 0;
		}
		if (button_shot && speed > 0)
		{
			revers_f();
			button_shot = 0;
		}
		if (button_shot && speed < 0)
		{
			revers_w();
			button_shot = 0;
		}
		if (button_long)
		{
			stop();
			button_long = 0;
		}

 

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

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...