реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> клавиатура 4х4, клавиатура 4х4
Джигрудязь
сообщение Sep 5 2014, 16:10
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 5-09-14
Из: Дома
Пользователь №: 82 740



Программа работы микроконтроллера с матричной клавиатурой 4х4.
CODE
#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 - Sep 5 2014, 21:31
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
kolobok0
сообщение Sep 6 2014, 00:04
Сообщение #2


практикующий тех. волшебник
*****

Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417



Цитата(Джигрудязь @ Sep 5 2014, 20:10) *
Программа работы микроконтроллера с матричной клавиатурой 4х4.
CODE

....
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 (она так же статичная переменная)


Go to the top of the page
 
+Quote Post
Джигрудязь
сообщение Sep 7 2014, 08:51
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 5-09-14
Из: Дома
Пользователь №: 82 740



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

Я хочу разобрать прерывание по переполнению таймера отдельно. Вот такой код я сделал, тут в случае срабатывания прерывания на всех ножках порта С будет логическая "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 - Sep 7 2014, 12:17
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
Xenia
сообщение Sep 7 2014, 09:59
Сообщение #4


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(Джигрудязь @ Sep 7 2014, 12:51) *
Вот такой код я сделал, тут в случае срабатывания прерывания на всех ножках порта С будет логическая "1". Но прерывание не срабатывает, что нужно мне сделать, что прерывание происходило?


Добавьте:
TIFR = 1;
TIMSK = 1;

А при
TCCR0=1;
прерывания по таймеру будут происходить слишком часто - Меге тяжело.
Поставьте лучше
TCCR0=5; // делитель 1:1024
все равно ведь кнопки пальцами давят, а потому милисекунды роли не играют.
Go to the top of the page
 
+Quote Post
Джигрудязь
сообщение Sep 7 2014, 10:03
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 5-09-14
Из: Дома
Пользователь №: 82 740



Цитата(Xenia @ Sep 7 2014, 09:59) *
Добавьте:
TIFR = 1;
TIMSK = 1;

Отлично,Великолепно))) Заработало))) Да вы просто Небожитель))) Великий)))
Go to the top of the page
 
+Quote Post
Xenia
сообщение Sep 7 2014, 10:16
Сообщение #6


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(Джигрудязь @ Sep 7 2014, 14:03) *
Отлично,Великолепно))) Заработало)))


Чтобы в самом деле было великолепно, было бы лучше заменить ATmega16 на какую-нибудь по современнее, у которых прерывание бывает не только от таймеров, но и от изменения уровней в порту (PCINT). Тогда прерывание будет происходить экономно - лишь в моменты, когда какая-то кнопка замыкает контакт или его размыкает (обычно это одно прерывание на весь порт). Скажем что-то вроде ATmega88/168.
Go to the top of the page
 
+Quote Post
Джигрудязь
сообщение Sep 7 2014, 10:22
Сообщение #7


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 5-09-14
Из: Дома
Пользователь №: 82 740



Ладно, буду пробовать.
Go to the top of the page
 
+Quote Post
Xenia
сообщение Sep 7 2014, 11:17
Сообщение #8


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



А у вас эта микросхемина в корпусе DIP40 или TQFP44?
Go to the top of the page
 
+Quote Post
Джигрудязь
сообщение Sep 7 2014, 11:26
Сообщение #9


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 5-09-14
Из: Дома
Пользователь №: 82 740



Пока еще никакая микросхема))) Теоретически пока ещё всё)))
Go to the top of the page
 
+Quote Post
Xenia
сообщение Sep 7 2014, 11:28
Сообщение #10


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(Джигрудязь @ Sep 7 2014, 15:26) *
Пока еще никакая микросхема))) Теоретически пока ещё всё)))


А как же тогда она у вас "заработала"? sm.gif
Go to the top of the page
 
+Quote Post
Джигрудязь
сообщение Sep 7 2014, 11:34
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 5-09-14
Из: Дома
Пользователь №: 82 740



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

Сообщение отредактировал Джигрудязь - Sep 7 2014, 11:39
Go to the top of the page
 
+Quote Post
Xenia
сообщение Sep 7 2014, 12:11
Сообщение #12


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(Джигрудязь @ Sep 7 2014, 15:34) *
В Proteus 7 смоделировал))) Там по умолчанию DIP корпус, таким и оставил.


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



Но раз оно у вас пока не в железе, то рекомендую все-таки присмотреться к тем Мегам, у которых имеется прерывание 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, если для души sm.gif (она же на фото изображена). Те и другие бывают в разных корпусах, в том числе и DIP.

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

P.S. На худой случай (если сами изготавливать платы не умеете) можно купить готовую Ардуинку, например, Arduino Uno, которая и подходящую (в смысле PCINT) микросхему содержит, и ардуинову прошивку позволяет заменить на свою.
Go to the top of the page
 
+Quote Post
Джигрудязь
сообщение Sep 7 2014, 13:32
Сообщение #13


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 5-09-14
Из: Дома
Пользователь №: 82 740



Вот оно чё)))))) Хорошо, буду знать))) Спасибо Большое)))))
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 13:06
Рейтинг@Mail.ru


Страница сгенерированна за 0.01456 секунд с 7
ELECTRONIX ©2004-2016