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 секунды другая и т.д.
Часто в коде есть более важные задачи, чем реакция на нажатие пользователем кнопки. Для них достаточно и обычного опроса. К тому же при опросе пропадает проблема дребезга контактов.
Вы, видимо, не очень понимаете как работают прерывания. Как раз таки чтобы ваши "более важные задачи работали" и существуют прерывания, которые не отнимают процессорного времени пока не произойдут и не будет вызван их обработчик. Проблемы дребезга же контактов при них нет вообще, если подходить к задаче грамотно. В коде МК delay'ев вообще быть не должно, это время, когда ваш МК без всякой пользы расходует энергию ничего не делая.
Про delay я ни слова не упомянул, если что.
Конечно, все еще зависит от самого устройства, где работает МК. Если много процессорного времени занимают внутренние долгие, например, расчеты, то вклинивать в них периодические проверки кнопок, вероятно, действительно не самая лучшая идея.
Но если происходит много важных событий, требующих быстрой реакции, то зачем еще отвлекаться на прерывания кнопок. Пусть опрашиваются в фоне. Опрос может выполняться процессором как мало приоритетная задача «в свободное от работы время».
Подытоживая - я о том, что нельзя категорично сказать «нафиг опросы, делайте всегда через прерывания». Все зависит от ситуации.
Сам микроконтроллер работает до 2,7в, потом уходит в защиту, судя по документации. Фатального разряда аккумулятора по идее не должно случится.
Если под "защитой" имеется в виду срабатывание "brown-out reset", то это только прекращение работы программы. Потребление тока остаётся и даже может стать больше.
Всем доброго времени суток! Может будет интересно, сенсорная емкостная кнопка ttp223. Не имеет дребезга контактов, срабатывает с зазором до 5 мм, в том числе через пластиковый корпус. Не надо сверлить корпус, подгонять. Если надо поставить несколько кнопок, запаиваю на макету плоской стороной к корпусу, между кнопками хотя бы сантиметр нужен, чтобы не "нажимать" сразу несколько. Успехов!
Часы на базе микроконтроллера ch32v003 (часть 2)