Pull to refresh

Comments 18

как повысить отзывчивость на нажатие кнопок?

Менять подход к написанию программы.

Для начала можно почитать тут - Планировщик - chipenable.ru и далее по ссылкам там.

Потому что вот это

 while (1) {
    Delay_Ms(100);
    ... // куча наваленного подряд кода
}

никуда не годится.

Спасибо, почитаю и поправлю.

Смотрю тут описывают варианты работы с кнопками.

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

Сама функция опроса на данный момент такая:

Скрытый текст
void Controls_PushButtonsPooling(void)
{
	// Take a push button from the list
	PushButton_t * pb = PushButtonList;
	while(pb != NULL)
	{
		// Get global time
		uint32_t globalTime = TaskManager_GetTick();
		// Update pressing time
		uint32_t pressingTime = globalTime - pb->startPressTime;
		// Update gap time
		uint32_t gapTime = globalTime - pb->gapTime;

		// The branch is executed when the push button is pressed
		if (pb->pullType ? (!LL_GPIO_IsInputPinSet(pb->port, pb->pinMask)) : (LL_GPIO_IsInputPinSet(pb->port, pb->pinMask)))
		{
			// Push button press moment
			if (pb->state == OPEN)
			{
				// Change push button state
				pb->state = CLOSE;
				// Reset start press time
				pb->startPressTime = globalTime;
				// Reset gap time
				pb->gapTime = gapTime;
			}
			else
			{
				// The push button is still pressed during polling
				if ((pressingTime >= PUSHBUTTON_LONGPRESS_TIMEOUT) && (pb->pressCounter == 0))
				{
					// Long press detected
					pb->longHandler();
					pb->pressCounter += 10;
				}
				// The push button is still pressed during polling - after first short press
				else if ((pressingTime >= PUSHBUTTON_LONGPRESS_TIMEOUT) && (pb->pressCounter == 1))
				{
					// Short + long press detected
					pb->shortLongHandler();
					pb->pressCounter += 10;
				}
			}
		}
		// The branch is executed when the push button is released
		else
		{
			// Push button release moment
			if ((pb->state) == CLOSE)
			{
				// Reset gap time
				pb->gapTime = globalTime;
				pb->pressCounter++;
			}
			else
			{
				if (pressingTime < PUSHBUTTON_LONGPRESS_TIMEOUT) // Exclude push button release event after long press
				{
					// Time for the second press has expired
					if ((gapTime > PUSHBUTTON_DBLCLK_TIMEOUT) && (pb->pressCounter == 1))
					{
						// Short press detected
						pb->shortHandler();
						pb->pressCounter = 0;
						pb->gapTime = 0;
					}
					// Time for the second press has not yet expired
					else if ((gapTime < PUSHBUTTON_DBLCLK_TIMEOUT) && (pb->pressCounter == 2))
					{
						// Second short press detected
						pb->doubleShortHandler();
						pb->pressCounter = 0;
						pb->gapTime = 0;
					}
				}
				else
				{
					pb->pressCounter = 0;
				}

				// Update start press time
				pb->startPressTime = globalTime;
			}

			pb->state = OPEN;
		}

		// Go to next push button
		pb = pb->next;
	}
}

Каждая кнопка - это структура:

typedef struct PushButton
{
	GPIO_TypeDef *port;
	uint32_t pinMask;
	uint8_t pullType;
	uint8_t state;
	uint32_t startPressTime;
	uint8_t pressCounter;
	uint32_t gapTime;
	void (*shortHandler) (void); // Short press handler pointer
	void (*longHandler) (void); // Long press handler pointer
	void (*doubleShortHandler) (void); // Double short press handler pointer
	void (*shortLongHandler) (void); // Short + long press handler pointer
	struct PushButton *next; // Next push button pointer
} PushButton_t;

Думаю, по коду примерно будет понятно. Тут отслеживается одиночное короткое и длинное нажатия, двойное короткое нажатие, короткое+длинное нажатие. При необходимости, код можно и упростить, уйти от списка в пользу массива структур, можно придумать как отслеживать всякие другие комбинации нажатий, но мне пока хватало имеющихся.

Код написан для STM32, но платформо-зависимая там всего одна строчка по сути.

Я использую такой вариант

Проверка нажатия кнопки . Если нажата то начать счёт переменной которая считает количество циклов главного main. При достижении переменной определенного числа повторный опрос и если она ещё нажата то выполнение программы которая эту кнопку вызывает.

Спасибо, попробую, как поправлю свой лапшекод по предыдущему комментарию.

Неправильно считаете. Если кнопка нажата - прибавлять 3, если нет - отнимать 1 если переменная не равна нулю. При достижении некоторого значения выполняем действие и выставляем флаг нажатия кнопки, который сбрасывается только при достижении переменной 0.

Зачем вообще нужны проверки каких либо нажатий, если это все делается прерываниями ?

Прерывание это оптимальный вариант.

Просто здесь используется упрощённый вариант с возможностью оперировать длительностью нажатия кнопки. Нажал 1 секунду одна функция, 2 секунды другая и т.д.

В том то и дело, что оперировать длительностью нажатия намного проще используя прерывания + 1 таймер. Это и есть упрощённый вариант, а предлагаемый вами вариант это костыль.

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

Вы, видимо, не очень понимаете как работают прерывания. Как раз таки чтобы ваши "более важные задачи работали" и существуют прерывания, которые не отнимают процессорного времени пока не произойдут и не будет вызван их обработчик. Проблемы дребезга же контактов при них нет вообще, если подходить к задаче грамотно. В коде МК delay'ев вообще быть не должно, это время, когда ваш МК без всякой пользы расходует энергию ничего не делая.

Про delay я ни слова не упомянул, если что.

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

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

Подытоживая - я о том, что нельзя категорично сказать «нафиг опросы, делайте всегда через прерывания». Все зависит от ситуации.

Некоторых пользователей бесит отсутствие хотя бы квитирования нажатий кнопок. Покажи, что ты обратил внимание на действие пользователя и досчитывай a = b % c.

Сам микроконтроллер работает до 2,7в, потом уходит в защиту, судя по документации. Фатального разряда аккумулятора по идее не должно случится.

Если под "защитой" имеется в виду срабатывание "brown-out reset", то это только прекращение работы программы. Потребление тока остаётся и даже может стать больше.

Вот это поворот, спасибо что подсветили, как появится время, попробую прояснить этот момент.

Потребление больше стать не должно, но останется.

Если настройки портов по сбросу "CMOS w/o pull", то может и подрасти.

Всем доброго времени суток! Может будет интересно, сенсорная емкостная кнопка ttp223. Не имеет дребезга контактов, срабатывает с зазором до 5 мм, в том числе через пластиковый корпус. Не надо сверлить корпус, подгонять. Если надо поставить несколько кнопок, запаиваю на макету плоской стороной к корпусу, между кнопками хотя бы сантиметр нужен, чтобы не "нажимать" сразу несколько. Успехов!

Sign up to leave a comment.

Articles