Мне нужно определить, был ли нажат переключатель дольше установленного времени, без использования каких-либо регистров таймера во встроенном коде.
Я использую программное устранение дребезга следующим образом, чтобы обнаружить нормальное нажатие переключателя.
int buttonPress (void)
{
static int downCount= 0; // static = value isn't lost between calls.
int currentButton = ((IO0PIN & 0x00000200) == 0x00000200);
if (currentButton ) { // button is down
if (downCount == 5) { // button has been down for 5 counts
downCount++; // increase the count so we don't trigger next time
return 1;
} else { // some count other than 5
if (downCount < 5) // increase if it's less than 5
downCount++;
}
} else { // button is up
downCount = 0;
}
return 0;
}
Однако я хотел бы определить, была ли эта кнопка нажата в течение 5 секунд или дольше. Проблема, с которой я столкнулся, заключается в том, что я не могу сосчитать до 300 000, и если это не достигнуто, вернуться к оригиналу downCount
5, чтобы отметить как обычное нажатие кнопки.
(Поскольку тактовая частота моего микроконтроллера составляет 60 МГц, то для достижения 300 000 потребуется 5 секунд.)
Я поиграл с некоторой логикой следующим образом, однако в случае, показанном ниже, из-за введения while
утверждения я считаю до 300 000 независимо от того, как долго кнопка была нажата.
if (currentButton ) { // button is down
if (downCount == 5) { // button has been down for 5 counts
downCount++; // increase the count so we don't trigger next time
while (downCount > 5) {
if (debounce == 300000) {
flag_5SEC = 1;
} else if (debounce < 300000) {
debounce++;
}
}
return 1;
} else { // some count other than 5
if (downCount < 5) // increase if it's less than 5
downCount++;
}
}
Любые советы или предложения о том, как выполнить эту задачу?
Примечание . Я хочу явно определить более длительное нажатие переключателя в приведенном выше коде устранения дребезга, поскольку любые другие действия могут иметь неблагоприятные побочные эффекты для остального кода, который ранее написал кто-то другой.
Мне удалось выполнить вышеупомянутую задачу с помощью таймеров, однако с тех пор я использовал все регистры таймеров (и доступные резисторы сопоставления) для более важных задач в рамках того же проекта.
Мне не нужно определять точную временную задержку, просто если кнопка была нажата дольше, чем, скажем, 2-3 секунды.
Комментарий @DiBosco уточняет далее:
Итак, вы говорите, что если вы нажмете переключатель, скажем, на двадцать счетов, и отпустите его, это действует как обычное нажатие, выполняющее одну функцию, и если его нажать и удерживать в течение двух секунд или около того, он выполняет другая функция...
Мне удалось выполнить вышеупомянутую задачу с помощью таймеров, однако с тех пор я использовал все регистры таймеров (и доступные резисторы сопоставления) для более важных задач в рамках того же проекта.
В этом случае вы все делаете неправильно. Если вам абсолютно не нужны высокое разрешение, низкое дрожание или другие аппаратные функции аппаратных таймеров, вы должны выполнять отсчет времени программно, используя один из аппаратных таймеров для генерации непрерывных периодических прерываний, которые вы можете подсчитать в ISR.
«Прерывание пульса» с периодом от 100 мкс до 100 мс (или более) является обычной чертой встроенных систем. Это позволяет создавать произвольное количество программных таймеров.
Даже если вы уже используете все аппаратные таймеры, пока хотя бы один из них выполняет что-то периодическое, например, генерирует сигнал ШИМ или создает часы для последовательного интерфейса, вы можете включить прерывания на нем и использовать их. для временной базы вашего программного обеспечения. Период может быть неудобным значением, но это простая проблема масштабирования, с которой может справиться программное обеспечение.
Ваш код кажется немного неправильным, и его трудно понять, поскольку неясно, где находится этот цикл while по отношению к прерыванию или тому, что устанавливает функцию DownCount.
Вы также, кажется, увеличиваете счетчик отката в двух местах в цикле while, что просто кажется неправильным.
Ваше встроенное решение проблематично по многим причинам, не последней из которых является то, что ваше время будет варьироваться в зависимости от того, что еще происходит на микроконтроллере, если вы не остановитесь и не зациклитесь, пока считаете. Но останавливаться на пятисекундном счете — тоже плохая идея.
Этот тип функции обычно обрабатывается в микрос помощью счетчика тиков, также известного как сердцебиение. По сути, обычной практикой является резервирование одного таймера в качестве часов для вашего кода. Таймер будет генерировать регулярное прерывание, возможно, 10 раз в секунду.
Этот обработчик прерываний может позаботиться о многочисленных вспомогательных функциях, таких как устранение дребезга переключателей, мигание светодиодов, проверка тайм-аутов связи и т. д. Он также может включать подсчет времени нажатия кнопки. Когда он был нажат в течение соответствующего промежутка времени, указанный обработчик затем вызывает соответствующий обработчик для этого события.
Этот метод позволяет использовать один таймер для множества функций.
Поскольку кнопки управляются очень медленными людьми по отношению к скорости процессора, вы можете обойтись медленным опросом. Например, каждые 10 миллисекунд.
Вы можете легко создать одну функцию для управления многими кнопками со множеством шаблонов нажатия и удержания.
Очень простая версия того, что я часто использую, выглядит так. Он имеет только 5-секундный флаг удержания, ни одно из нажатий не подсчитывается и не подтверждается флагом (флаги будут установлены сразу после повторной очистки).
Но проявив немного творчества, вы можете добавить много вещей таким образом. Но он станет немного длинноват.
Вы даже можете добавить машинные входные каналы и таким образом устранить их дребезг.
#define BUTTON_INTERVAL 10
#define BUTTON_COUNT 1
/* Typedef for a button */
typedef struct button_s {
void* port; /* Use GPIO port type, whatever your platform uses, maybe even via bitbanding */
uint32_t hi_time; /* Time high */
uint8_t pin; /* Pin number */
uint8_t flags; /* Output flags */
} button_t;
/* The array of all buttons */
button_t buttons[BUTTON_COUNT];
/* Handle button polling */
void buttonHandler(void){
uint8_t i;
for(i=0;i<NR_OF_BUTTONS; i++){
button_t *b = buttons[i];
uint8_t state = *b->port & (1<<b->pin);
if(state){
// Saturating unsigned 32-bit addition
// your cpu might have an instruction for this eg: arm __uqadd(a,b))
if(b->hi_time < 0xFFFFFFFF) b->hi_time += BUTTON_INTERVAL;
}else{
b->hi_time = 0;
}
// One of many possible flags comparisons:
if( b->hi_time >= 5000 ){
b->flags |= BUTTON_HI_5S;
}
}
}
/* Example of flag usage */
void waitForButton(){
if( button[0]->flags & BUTTON_HI_5S ){
button[0]->flags &= ~BUTTON_HI_5S;
// ..stuff..
}
}
Ключевые моменты, если вы собираетесь самостоятельно:
- Структура для всех данных, вы даже можете переназначить ключи на лету, если хотите.
- Бесконечные кнопки с использованием структур. Никогда больше не пишите этот код!
- Насыщение таймеров, они не переполняются.
- Флаги, легко заменяемые для вызовов операционной системы.
Если я правильно понимаю ваши потребности, вы хотите что-то вроде этого:
void SwitchCheck(void)
{
DebounceTimer = false; // If using timer flag
if (currentButton)
{
debounce++;
}
else
{
if (debounce > NORMAL_OPERATION)
{
// Do normal stuff here
}
debounce = 0;
}
if (debounce == MAX_TIMEOUT)
{
// Do your held down thing here
}
}
Вызовите это из основного цикла. В идеале вызывайте его только после того, как вы правильно установили бит в прерывании таймера, чтобы у вас было точное время.
Я много-много раз за эти годы делал дебаунс переключения без таймеров (хотя и не очень нравится), просто звонил из основного цикла и все работало. Однако, если вам нужна точность в пятисекундном хронометраже, этого будет недостаточно.
Дальнейшее редактирование:
В вашем таймере ISR:
TimerISR()
{
DebounceTimer = true;
// Other stuff
}
В основном:
if (DebounceTimer)
SwitchCheck();
Или просто вызовите его из main без проверки флага, если вы не используете таймер, и эмпирически поэкспериментируйте с MAX_TIMEOUT.
ДиБоско
ДиБоско
ррз0
Тревор_G
ррз0
if(buttonPress())
утверждение, которое верно только наreturn 1
Тревор_G
ррз0
ДиБоско
ДиБоско
Ник Гэммон
millis()
на Ардуино).ррз0
Ник Гэммон
Томас Падрон-Маккарти
ррз0