Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: динамический опрос кнопок
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Anjey_N
Всем привет! Вот пришёл просить помощи. Задача несложная, только я вконец уже запутался.
Есть МК ATmega16, АЛС, индикация динамическая, кнопки М, +, -
Есть массив переменных set_temp[3]. Пока кнопки не нажаты, происходит каждые 5 сек поочерёдный вывод на индикатор содержимого массива. ( с этим я разобрался работает). При нажати на М включается режим редактирования, 2 мл разряда индикатора мигают. Кнопками + и - изменяется содержимое элемента массива. Последующее нажатие М приводит к переходу к следующему элементу массива.
Если все элементы отредактированы - записать в EEPROM.

Кто что посоветует, или поможет кодом. Свой я надлежаще оформлю и выставлю позже. Пишу на Си в ИАРе.
aaarrr
А вопрос-то в чем - как кнопки опрашивать?

Кнопки нужно опрашивать одновременно с выводом на индикатор - настроить PA7 на вход, включить встроенный pull-up (хотя я бы поставил внешний) и смотреть состояние порта с некоторой задержкой после начала вывода очередной цифры.
vet
в прерывании таймера - опрос кнопок, антидребезг, установка флагов нажатия кнопок, динамическая индикация.
в главном цикле - логика обработки флагов нажатых кнопок: смена содержимого ячейки, индекса текущей ячейки, запись в EEPROM.
Anjey_N
Цитата(aaarrr @ Mar 7 2008, 17:50) *
А вопрос-то в чем - как кнопки опрашивать?

Кнопки нужно опрашивать одновременно с выводом на индикатор - настроить PA7 на вход, включить встроенный pull-up (хотя я бы поставил внешний) и смотреть состояние порта с некоторой задержкой после начала вывода очередной цифры.


я так исделал, код кнопки я получаю, не получается дальше. Не сохраняются данные в памяти, содержимое масива при длительном нажатии на кнопку увеличивается/уменьшается неравномерно, иногда останавливается.
Если вам не сложно и есть желание можете написать свой код Хочется посмотреть! beer.gif
algidim
У вас схема не может работать по определению, ну подумайте сами. В тот момент, когда вы выставляете на PA7 лог 1 и опрашиваете PD0-PD2, с челью узнать нажатую кнопку, вы получите на PD0-PD2 в любом случае лог 1, даже если кнопки не нажаты, если конечно, у вас подключены встроенные подтягивающее резисторы. Если они не подключены то результат опроса будет не предсказуем, похоже, у вас такая ситуация. Просто, прежде чем проектировать подобные схемы, нужно чётко представлять логику её работы.
rezident
Поскольку для динамической индикации используется "бегущая единица", а не "бегущий ноль", то диоды нужно развернуть анодами к сканирующим пинам МК и катодами к кнопкам. А на PA7 поставить pull-down (резистор к общему проводу).
Насчет алгоритмов сканирования и устранения дребезга здесь писали настолько часто, что еще один раз пальцы об клаву мозолить уже нет никакого желания. sad.gif Пользуйтесь поиском по форуму!
aaarrr
Цитата(rezident @ Mar 7 2008, 19:57) *
Поскольку для динамической индикации используется "бегущая единица", а не "бегущий ноль...

С чего бы это вдруг? Посмотрите на схему - там p-n-p транзисторы.
Anjey_N
Цитата(algidim @ Mar 7 2008, 19:49) *
У вас схема не может работать по определению, ну подумайте сами. В тот момент, когда вы выставляете на PA7 лог 1 и опрашиваете PD0-PD2, с челью узнать нажатую кнопку, вы получите на PD0-PD2 в любом случае лог 1, даже если кнопки не нажаты, если конечно, у вас подключены встроенные подтягивающее резисторы. Если они не подключены то результат опроса будет не предсказуем, похоже, у вас такая ситуация. Просто, прежде чем проектировать подобные схемы, нужно чётко представлять логику её работы.


Не совсем так. Эта схема работает. И не только в симуляторе, но и на реальном контроллере, упрравление идёт через JTAG.
PA7 настроен на вход с подтягивающим резистором. Когда нажата кнопка, лог. нуль через диод, замкнутую кнопку подаётся на вход PA7. Запоминается номер вывода и взводится флаг антидребезга на 20 мсек для устранения дребезга. После этого программа улучает момент, когда лог. нуль появляется на том выводе, который она запомнила перед пднятием флага антидребезга. Если кнопка замкнута, тогда номер вывода = запомненному номеру и программа возвращает номер вывода, те номер кнопки. Может туманно объяснил, смотри код

// Сканирование клавиатуры
unsigned char Scan_Key(void)
{
static unsigned char pk=0;
static unsigned char Key_Buf;
if(TESTBIT(flag,DREBEZG)) //
{
if(cnt_dr!=0)
{
delay_timer1(MSEC(1)); // задержка 1 мсек
// delay_ms(1);
cnt_dr--;
}
else
{
cnt_dr=CNT_DR_MAX;
CLEARBIT(flag,DREBEZG);
BUZER=0; // снять звуковой сигнал
}
}
else
{
switch (h)
{
case 0 : if (!KEY) // кнопка нажата!
{
SETBIT(flag,DREBEZG); // взвести флаг антидребезга
BUZER=1; // подать звуковой сигнал
Key_Buf=n; // запомнить номер кнопки
h++; // увеличить счётчик прохождений
}
pk=0; break;
case 1 : if(n==Key_Buf)
{
if (!KEY)
{
SETBIT(key,n); // запоминаем нажатую кнопку!
pk=key;
SETBIT(flag,KEYBOARD);
}
else // если кнопка отжата,
{ // то проверяем - действительно ли
SETBIT(flag,DREBEZG); // взводим флаг антидребезга
h++; // и увеличиваем счётчик прохождений
}
}
break;
case 2 : if((KEY)&&(Key_Buf==n)) // если кнопка отжата и её
{ // номер соответствует записанному в буфер
Key_Buf=0xFF; // запись в буфер неиспользуемого числа
h=0; // обнуление счётчика прохождений
pk=0;
key=0;
CLEARBIT(flag,BUSY);
}
break;
default: break;
}
}
return pk;
}
algidim
Да я извиняюсь, не досмотрел, схема рабочая, просто определять нажатие кнопок нужно в момент открытия любого транзистора. Ошибка в коде. А уж разбираться в вашем коде придется вам самому, за вас врят ли кто нибудь это сделает. Алгоритм сканирования кнопок и динамической индикации довольно прост.
rezident
Цитата(aaarrr @ Mar 7 2008, 22:00) *
С чего бы это вдруг? Посмотрите на схему - там p-n-p транзисторы.
Миль пардон! Не стал увеличивать картинку и поэтому не рассмотрел направление стрелок. За такой стиль рисования схем наказывать нужно wink.gif
Anjey_N
Вот приготовил свой код на рассмотрение. Критикуйте! Можете потыкать меня носом в ошибки!
SasaVitebsk
Так, на скорую руку писал, и без проверки, но идея вроде понятна должна быть. Если нет, то спрашивай.
Anjey_N
Цитата(SasaVitebsk @ Mar 11 2008, 01:48) *
Так, на скорую руку писал, и без проверки, но идея вроде понятна должна быть. Если нет, то спрашивай.


не пошёл Ваш код. переменная антидребезга постоянно сбрасывается в исходную величину. А Вы мой код не смотрели?
SasaVitebsk
Цитата(Anjey_N @ Mar 11 2008, 22:19) *
не пошёл Ваш код. переменная антидребезга постоянно сбрасывается в исходную величину. А Вы мой код не смотрели?

Смотрел, но ваш мне показался излишне громоздким. А что значит "не пошёл"? Там же 5 операторов. Идея то понятна? Посмотрите где я хомутнул. Если вечером время будет, то сам гляну.

Индикация то работает надеюсь?
rimpocha
http://www.embedded.com/columns/breakpoint...equestid=203518

Вот! Прелестнейшая антидребезговая утилита от Jack Ganssle

По таймеру это ей жирно, я решил. Дергаю из мэйнлупа -- справляется на отлично.
// Service routine called by a timer interrupt
bool_t DebounceSwitch2()
{
static uint16_t State = 0; // Current debounce status
State=(State<<1) | !RawKeyPressed() | 0xe000;
if(State==0xf000)return TRUE;
return FALSE;
}

Подробное описание, в статье на английском. Если есть необходимость, переведу.
Anjey_N
Цитата(rimpocha @ Mar 12 2008, 23:08) *
http://www.embedded.com/columns/breakpoint...equestid=203518

Вот! Прелестнейшая антидребезговая утилита от Jack Ganssle

По таймеру это ей жирно, я решил. Дергаю из мэйнлупа -- справляется на отлично.
// Service routine called by a timer interrupt
bool_t DebounceSwitch2()
{
static uint16_t State = 0; // Current debounce status
State=(State<<1) | !RawKeyPressed() | 0xe000;
if(State==0xf000)return TRUE;
return FALSE;
}

Подробное описание, в статье на английском. Если есть необходимость, переведу.


Необходимость есть, переведи! help.gif
rimpocha
Цитата(Anjey_N @ Mar 13 2008, 21:51) *
Необходимость есть, переведи! :help:


Эх... :)
Там статья то объемненькая :)

У меня щас есть время только функцию описать.

State = (State<<1) | !RawKeyPressed() | 0xe000;
оно же в двоичном виде: (State<<1) | !RawKeyPressed() | 1110 0000 0000 0000;

State изначально = 16 ноликов.
На этом шаге мы сдвигаем State влево, а на место нулевого бита ставим 0 если кнопка нажата, иначе 1.
При этом старшие три бита всегда единички.
Дергаем нашу функцию каждые 10мс.

Тогда при нажатии кнопки (если она была отпущена) State с каждым шагом будет меняться так:
1111 1111 1111 1111 -- кнопка отпущена
1111 1111 1111 1110 -- нажали кнопку
1111 1111 1111 1100 -- держим
1111 1111 1111 1001 -- пошел дребезг
1111 1111 1111 0010
...
1111 1110 1010 1101 -- вот сколько дребезга дофига было :)
1111 1101 0101 1010 -- вот тут контакты успокоились и пошли к нам нолики ровным строем
1111 1010 1011 0100
...
1111 1101 0000 0000 -- вот сколько уже ноликов пришло и продолжают идти...

Это первая часть алгоритма. А вторая -- это условие
if(State==0xf000)return TRUE;
То есть сравниваем State с 1111 0000 0000 0000.
А состояние 1111 0000 0000 0000 означает, что кнопка нажата уже 12 ноликов подряд, и перед этими 12-ю шагами она как минимум один шаг была не нажата (единичка в 13-м разряде).

Ну вот собственно когда условие выше описанное выполняется регистрируем нажатие кнопки: возвращаем true.

Это все можно заточить под себя меняя 0xe000 и 0xf000.

И вообще алгоритм простой и быстрый, функцию можно по всякому модифицировать. Вот например я так сделал:
//------------------------------------------------------
//--- Debounce switch action
//--- function operate on external debounce-state variable
// работает с внешней переменной состояния чтоб сразу несколько кнопок опрашивать
int DebouncePress(int RawButtonPressed(char), char button, unsigned int *state){
*state = (*state<<1) | !(RawButtonPressed(button)) | 0xe000;
if(*state == 0xf000) return 1; // Pressed Нажата
if(*state == 0xefff) return 0; // Released Отпущена
return -1; // Unstable Идет дребезг
}
//-------------------------------------------------------
Anjey_N
Ух, ты!
В данном алгоритме кнопка одним концом сидит на выводе МК, а вторым на "земле"?



Цитата(SasaVitebsk @ Mar 12 2008, 13:28) *
Смотрел, но ваш мне показался излишне громоздким. А что значит "не пошёл"? Там же 5 операторов. Идея то понятна? Посмотрите где я хомутнул. Если вечером время будет, то сам гляну.

Индикация то работает надеюсь?


Мой код громоздкий из-за маленького опыта, но он работает.
Индикация работает!
Вы объявили в структуре Int_Key, а как её используете7
rimpocha
Цитата(Anjey_N @ Mar 14 2008, 21:54) *
Ух, ты!
В данном алгоритме кнопка одним концом сидит на выводе МК, а вторым на "земле"?


Если вопрос ко мне, то кнопка чисто гипотетическая.
А гипотетическая функция RawKeyPressed() возвращает 1, если контакт замкнут, иначе 0.
SasaVitebsk
Цитата(Anjey_N @ Mar 14 2008, 19:54) *
Вы объявили в структуре Int_Key, а как её используете7

Просто попытался портировать из своей же библиотеки
http://electronix.ru/forum/index.php?showt...0934&st=120
пост 125

При таком числе кнопок возможно применение нединамического опроса. Правда гашение дребезга всё равно требуется.
Anjey_N
Цитата(rimpocha @ Mar 13 2008, 20:25) *
Эх... smile.gif
Там статья то объемненькая smile.gif

У меня щас есть время только функцию описать.

State = (State<<1) | !RawKeyPressed() | 0xe000;
оно же в двоичном виде: (State<<1) | !RawKeyPressed() | 1110 0000 0000 0000;

State изначально = 16 ноликов.
На этом шаге мы сдвигаем State влево, а на место нулевого бита ставим 0 если кнопка нажата, иначе 1.
При этом старшие три бита всегда единички.
Дергаем нашу функцию каждые 10мс.

Тогда при нажатии кнопки (если она была отпущена) State с каждым шагом будет меняться так:
1111 1111 1111 1111 -- кнопка отпущена
1111 1111 1111 1110 -- нажали кнопку
1111 1111 1111 1100 -- держим
1111 1111 1111 1001 -- пошел дребезг
1111 1111 1111 0010
...
1111 1110 1010 1101 -- вот сколько дребезга дофига было smile.gif
1111 1101 0101 1010 -- вот тут контакты успокоились и пошли к нам нолики ровным строем
1111 1010 1011 0100
...
1111 1101 0000 0000 -- вот сколько уже ноликов пришло и продолжают идти...

Это первая часть алгоритма. А вторая -- это условие
if(State==0xf000)return TRUE;
То есть сравниваем State с 1111 0000 0000 0000.
А состояние 1111 0000 0000 0000 означает, что кнопка нажата уже 12 ноликов подряд, и перед этими 12-ю шагами она как минимум один шаг была не нажата (единичка в 13-м разряде).

Ну вот собственно когда условие выше описанное выполняется регистрируем нажатие кнопки: возвращаем true.

Это все можно заточить под себя меняя 0xe000 и 0xf000.

И вообще алгоритм простой и быстрый, функцию можно по всякому модифицировать. Вот например я так сделал:
//------------------------------------------------------
//--- Debounce switch action
//--- function operate on external debounce-state variable
// работает с внешней переменной состояния чтоб сразу несколько кнопок опрашивать
int DebouncePress(int RawButtonPressed(char), char button, unsigned int *state){
*state = (*state<<1) | !(RawButtonPressed(button)) | 0xe000;
if(*state == 0xf000) return 1; // Pressed Нажата
if(*state == 0xefff) return 0; // Released Отпущена
return -1; // Unstable Идет дребезг
}
//-------------------------------------------------------


А как Вы используете переменную char button ?
rimpocha
Цитата(Anjey_N @ Mar 23 2008, 00:16) *
А как Вы используете переменную char button ?


Это параметр функции RawButtonPressed(char). Код кнопки.
Anjey_N
Цитата(rimpocha @ Mar 22 2008, 22:20) *
Это параметр функции RawButtonPressed(char). Код кнопки.


Меня вводит в заблуждение фраза int DebouncePress(int RawButtonPressed(char), char button, unsigned int *state) Здесь нет ошибки7
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.