Перейти к содержанию
    

клавиатура 4х4

Программа работы микроконтроллера с матричной клавиатурой 4х4.

#asm 
   .equ __lcd_port=0x15 
#endasm 

#include <lcd.h> 
#include <stdio.h> 
#include <delay.h> 
#include <mega16.h> 

// quartz crystal frequency [Hz] 
#define F_XTAL 3686400L 
// PIND0..3 will be row inputs 
#define KEYIN PIND 
// PORTD4..7 will be column outputs 
#define KEYOUT PORTD 
// used for TIMER0 count initialization 
#define INIT_TIMER0 TCNT0=0x100L-F_XTAL/64L/500L 
#define FIRST_COLUMN 0x80 
#define LAST_COLUMN 0x10 

typedef unsigned char byte; 
// store here every key state as a bit, 
// bit 0 will be KEY0, bit 1 KEY1,... 
unsigned keys; 
// LCD display buffer 
char buf[33]; 

// TIMER 0 interrupt at every 2 ms 
interrupt [TIM0_OVF] void timer0_int(void) 
{ 
static byte key_pressed_counter=20; 
static byte key_released_counter,column=FIRST_COLUMN; 
static unsigned row_data,crt_key; 
// reinitialize TIMER0 
INIT_TIMER0; 
row_data<<=4; 
// get a group of 4 keys in in row_data 
row_data|=~KEYIN&0xf; 
column>>=1; 
if (column==(LAST_COLUMN>>1)) 
  { 
  column=FIRST_COLUMN; 
  if (row_data==0) goto new_key; 
  if (key_released_counter) --key_released_counter; 
  else 
     { 
     if (--key_pressed_counter==9) crt_key=row_data; 
     else 
        { 
        if (row_data!=crt_key) 
           { 
           new_key: 
           key_pressed_counter=10; 
           key_released_counter=0; 
           goto end_key; 
           }; 
        if (!key_pressed_counter) 
           { 
           keys=row_data; 
           key_released_counter=20; 
           }; 
        }; 
     }; 
  end_key:; 
  row_data=0; 
  }; 
// select next column, inputs will be with pull-up 
KEYOUT=~column; 
} 

// test if a key was pressed 
unsigned inkey(void) 
{ 
unsigned k; 
if (k=keys) keys=0; 
return k; 
} 

void init_keypad(void) 
{ 
DDRD=0xf0; 
INIT_TIMER0; 
TCCR0=3; 
TIMSK=2; 
#asm("sei") 
} 

main() { 
unsigned k; 
init_keypad(); 
lcd_init(20); 
lcd_putsf("CVAVR Keypad"); 
// read keys and display key code 
while (1) 
     { 
     lcd_gotoxy(0,1); 
     if (k=inkey()) 
        { 
        sprintf(buf,"Key code=%Xh",k); 
        lcd_puts(buf); 
        } 
     else lcd_putsf("NO KEY        "); 
     delay_ms(500); 
     } 
} 

Здравствуйте помогите пожалуйста понять алгоритм работы выделенного жирным шрифтом фрагмента кода. Мне нужно его понять, чтоб написать свою программу. Иначе не выходит((( Насколько я понял там происходит чтение - нажата ли кнопка на определенной строке. Для этого взяли выходы порта D 7...4, как выходы столбцов. Но мне не понятно это условие if (column==(LAST_COLUMN>>1))

При самом первом вызове прерывания, там будет if(64==8) условие не выполняется, мы пропускаем все скобки и перемещаемся к строке KEYOUT=~column; И на этом всё, чтения не было. А как же тогда происходит считывание нажатых клавиш?

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Программа работы микроконтроллера с матричной клавиатурой 4х4.

 
....
static byte key_released_counter,column=FIRST_COLUMN; 
...
column>>=1; 
if (column==(LAST_COLUMN>>1)) 
...

...понять алгоритм работы...это условие if (column==(LAST_COLUMN>>1)) ...будет if(64==8) ...

пропускаем все скобки...А как же тогда происходит считывание нажатых клавиш?

 

Всё очень просто...

Прерывание от таймера. Т.е. оно происходит с определённым интервалом постоянно.

Обратите внимание на переменную column она статична - т.е. её значение сохраняется между вызовами

обработчика прерывания.

т.е. вначале условие будет 64==8, в следующее прерывание 32==8, затем 16==8, 8==8...

так же инверсия от column засылается на пины сканирования матрицы (получаем бегущий ноль) - см. конец обработчика.

 

при этом на каждом проходе идёт запоминание пинов - см. raw_data (она так же статичная переменная)

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо за ответ)))

 

Я хочу разобрать прерывание по переполнению таймера отдельно. Вот такой код я сделал, тут в случае срабатывания прерывания на всех ножках порта С будет логическая "1". Но прерывание не срабатывает, что нужно мне сделать, что прерывание происходило?

#include <mega16.h>
#include <delay.h>
interrupt [TIM0_OVF] void timer0_int(void)//прерывание по переполнению Таймера/Счетчика 0
{
DDRC=0xFF;
PORTC=0xFF;
}
void main(void)
{
SREG=0b10000000;
TCCR0=0b00000001;
while(1)
{
delay_ms(500);
}
}

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот такой код я сделал, тут в случае срабатывания прерывания на всех ножках порта С будет логическая "1". Но прерывание не срабатывает, что нужно мне сделать, что прерывание происходило?

 

Добавьте:

TIFR = 1;

TIMSK = 1;

 

А при

TCCR0=1;

прерывания по таймеру будут происходить слишком часто - Меге тяжело.

Поставьте лучше

TCCR0=5; // делитель 1:1024

все равно ведь кнопки пальцами давят, а потому милисекунды роли не играют.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добавьте:

TIFR = 1;

TIMSK = 1;

Отлично,Великолепно))) Заработало))) Да вы просто Небожитель))) Великий)))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Отлично,Великолепно))) Заработало)))

 

Чтобы в самом деле было великолепно, было бы лучше заменить ATmega16 на какую-нибудь по современнее, у которых прерывание бывает не только от таймеров, но и от изменения уровней в порту (PCINT). Тогда прерывание будет происходить экономно - лишь в моменты, когда какая-то кнопка замыкает контакт или его размыкает (обычно это одно прерывание на весь порт). Скажем что-то вроде ATmega88/168.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Пока еще никакая микросхема))) Теоретически пока ещё всё)))

 

А как же тогда она у вас "заработала"? :)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В Proteus 7 смоделировал))) Там по умолчанию DIP корпус, таким и оставил

Изменено пользователем Джигрудязь

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В Proteus 7 смоделировал))) Там по умолчанию DIP корпус, таким и оставил.

 

А что? Я корпус DIP Тоже люблю :).

 

bigger-avr-mcu-atmega1284p.jpg

 

Но раз оно у вас пока не в железе, то рекомендую все-таки присмотреться к тем Мегам, у которых имеется прерывание PCINT (от изменения уровней на всём порту). Их список нетрудно вытащить из хидеров, поиском на слово "PCINT". У меня получился такой список (преамбулу "ATmega" для краткости опускаю):

1280, 1281, 1284(p), 162, 164(a,p,pa), 165(a,p,pa), 168(a,p,pa), 169(a,p,pa), 2560, 2561, 324(a,p,pa), 325(a,p,pa), 3250(a,p,pa), 328(p), 329(a,p,pa), 3290(a,p,pa), 406, 48(a,p,pa), 640, 644(a,p,pa), 645(a,p,pa), 6450(a,p,pa), 649(a,p,pa), 6490(a,p), 88(a,p,pa).

 

Если вы затрудняетесь выбрать сами, то могу посоветовать ATmega88a, если вам только для клавиатуры надо, и ATmega1284p, если для души :) (она же на фото изображена). Те и другие бывают в разных корпусах, в том числе и DIP.

 

Остерегайтесь присохнуть к первой попавшейся, т.к. примерами изобилуют, как правило, самые старые. А то многие, как начали осваивать с 8515 или 8535, так и присохли к ним, хотя эти МК давно уже пора выбросить на свалку истории. :)

 

P.S. На худой случай (если сами изготавливать платы не умеете) можно купить готовую Ардуинку, например, Arduino Uno, которая и подходящую (в смысле PCINT) микросхему содержит, и ардуинову прошивку позволяет заменить на свою.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...