|
|
|
|
У Вас на порту 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: Ну..., код тоже умозрительный. Спасибо, ничего страшного, поразбираюсь, проверю, главное понятно где копать.
|
|
|
Оба кода проверил, оба работают |
|
|
|
|