Свежие обсуждения
Микроконтроллеры

Индикация нажатой кнопки

1 4 5

У Вас на порту B кроме кнопок, висит еще что-нибудь? Линии 0, 4, 5, 6, 7? Если да, вместо PINB сделайте везде (PINB & 0x0E)

 

Нет, эти выводы свободные и сконфигурированы как входы с внутренней подтяжкой (может ещё повешу на них другие кнопки, но пока не заняты). Попробовал маскировать 0x0E - тоже самое. Может быть глюк какой vmlab? Надо будет программу вообще до одних кнопок урезать и тогда попробовать.

 

Может быть и глюк. По идее, вроде, все правильно.

 

Правильно, что не работает.
Дело в том, что когда на каком-либо выводе PORTB устанавливается 0, то на этом же выводе, но регистра PINB тоже устанавливается 0, даже, если вы и отпустили кнопку, т. к. PINB соединен с PORTB напрямую. Поэтому, когда вы нажимаете другую кнопку, на PINB уже два нуля. Один соответствует кнопке, которую вы сейчас нажали, другой - остался от прежнего нажатия. А далее все будет зависеть от очередности ваших проверок if(...). Если первой была нажата кнопка 0b11111101, то какую бы вы кнопку потом не нажимали, у вас всегда первой идет процедура
if((newkey&0x02)==0) {DDRB=0x02;PORTB=0b11111101;}
Она и будет всегда срабатывать на тот самый ноль, оставшийся от первого нажатия. Ну и т. д.

 

Krug: и плюсом в обработке прерывания отслеживаю, что состояние ноги остается неизменным в течение какого-то разумного времени (напр. 10-20 мс для частоты сети).

Ну вот и выясняется, что вы "зависаете" в обработчике прерывания на целых 20 мс! Жуткая расточительность. Если же обрабатывать нажатие кнопки в прерывании по таймеру, то это отнимет единицы мкс - только чисто на выполнение нескольких команд.

 

Zandy: Поэтому, когда вы нажимаете другую кнопку, на PINB уже два нуля.
Хм.. нда, посмотрел состояния портов в vmlab, получается: нажатия 3-2-1 на PINB ноль один перемещается, а вот когда жмешь потом в обратном порядке, то последний ноль остается и добавляется другой ещё (но не фиксируется) и всё.... приехали, всегда активна последняя процедура. А что тут можно сделать, какой алгоритм борьбы с этим "безобразием"? Как то исключать из проверки последнее значение по PINB, но это мне кажется вообще нереально реализовать?

 

При чтении PINB руками добавляйте лог.1 для последней нажатой кнопки. Например, так:

void main(void)
{
oldkey=PINB; lastKey = 0;
while(1)
{
newkey = lastKey | PINB;
if(newkey!=oldkey)
{
oldkey=newkey;
if((newkey&0x02)==0) {lastKey = DDRB=0x02;PORTB=0b11111101;}
else
if((newkey&0x04)==0) {lastKey = DDRB=0x04;PORTB=0b11111011;}
else
if((newkey&0x08)==0) {lastKey = DDRB=0x08;PORTB=0b11110111;}
}
}
}

Код, правда, умозрительный, его нужно проверить

 

А я бы, если антидребезг игнорировать напрочь, а также игнорировать мои любимые прерывания по таймеру сделал бы еще проще:

void main(void){
while (1)
{
if (PINB != PORTB) {
DDRB = 0;
PORTB = 0xFF;
PORTB = PINB;
DDRB = ~PINB;
};
};
}
Такой код имеет еще преимущество. Можно нажать, например одновременно на две или несколько кнопок и будут гореть два или несколько диодов. Правда, если нажать одновременно на все восемь, то система войдет в клинч.
Ну..., код тоже умозрительный.

 

chav1961: Код, правда, умозрительный, его нужно проверить.
Zandy: Ну..., код тоже умозрительный.
Спасибо, ничего страшного, поразбираюсь, проверю, главное понятно где копать.

 

Оба кода проверил, оба работают