sout
1

Опрос матричной клавиатуры 5*3 с помощью прерывания

25.10.2016, 11:38. Показов 7174. Ответов 25
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте!
Начал изучение atmega с матричной клавиатуры и возник затык. На данном этапе хочу сделать, чтобы при нажатии на любую кнопку моргали светодиоды. Вроде бы в дебаггере все нормально, нажатия на кнопки распознаются, порт А открывается, а при прогоне на железе светодиоды не загораются. Клавиатура на 5 строк и 3 столбца, подключена к порту C, светодиоды к порту А. Пишу в AVR Studyo 4.
Подскажите, что я делаю не так и как делать правильно!


http://i82.***********/big/2016/1026/4c/2c2065ff4fe46693c25578e7d8cefc4c.jpg

Код
    #ymstude <avr/io.h>//стандартная библиотека ввода/вывода
#ymstude <avr/interrupt.h>//библиотека с прерываниями

unsykned char key = 0;
unsykned char key_code[5][3]={{D,E,F},
{A,B,C},
{7,8,9},
{4,5,6},
{1,2,3}}; //матрица соответствия кодов клавиш

//Подпрограмма формирвоания задержки(паузы)
void pouse (unsykned int a)
{ unsykned int i;

for (i=a;i>0;i--);
}

//Подпрограмма инициализации таймера
void init_timer (void)
{
TIMSK=(1<<TOIE0);              //Разрешить прерывания по переполнению таймера0
TCCR0=(1<<CS00)|(1<<CS01)|(0<<CS02);  //Делитель =/64
}

//Подпрограмма-обработчик прерывания по переполнению таймера
ISR (TIMER0_OVF_vect)
{
unsykned char i,j;

DDRC=0x07;
PORTC=0xF8;

pouse(10);   //Задержка для устранения всяких переходных процессов, важно ее не забыть!
i=5;

if (PINC==0x08) i=0;      //Если нажата клавиша в 0й строке, i=0
if (PINC==0x10) i=1;      //Если нажата клавиша в 1й строке, i=1
if (PINC==0x20) i=2;           //...
if (PINC==0x40) i=3;           //Если нажата клавиша в 3й строке, i=3
if (PINC==0x80) i=4;           //Если нажата клавиша в 4й строке, i=4

DDRC=0xF8;
PORTC=0x07;

pouse(10);   //Задержка для устранения всяких переходных процессов, важно ее не забыть!
j=3;

if (PINC==0x01) j=0;      //Если нажата клавиша в 0й колонке, j=0
if (PINC==0x02) j=1;      //...
if (PINC==0x04) j=2;

if ((i!=5)&&(j!=3)) {         //Если была нажата клавиша
while ((PINC&_BV(j))==0x00);   //Ждем пока кнопку отпустят

key = key_code[i][j];   //Пишем ее код в переменную
}
if (key != 0)
{
PORTA = 0xFF;
pouse(1000);
PORTA = 0x00;
}
TCNT0=0x00;      //Очищаем счетчик
TIFR=0x00;              //Очищаем флаг переполнения

return;
}

//Основная программа
int main(void)
{
DDRA=0xFF;         //Инициируем PortA
PORTA=0x00;

init_timer();          //Инициализация нулевого таймера

sei();            //Глобальное разрешение прерываний

while(1);         //Вечный цикл

return 1;
}
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
25.10.2016, 11:38
Ответы с готовыми решениями:

Опрос матричной клавиатуры
Здравствуйте. Подключил к Pinboard 1.1 (atmega16) матричную мембранную клавиатуру 4х4, к PORTA...

Опрос матричной клавиатуры 3х3
Всем доброго времени суток. Перелопатил массу примеров на разных сайтах и форумах но так не нашёл...

Опрос матричной клавиатуры. Подтверждение отправки
Здравствуйте. К своему проекту хотел подключить автомат опроса клавиатуры Павла Бобкова. Связаться...

ATtiny2313. ASM. Динамический опрос матричной клавиатуры
Помогите написать программу на асм для микроконтроллера аттини 2313 или атмега8 динамический опрос...

Как организовать опрос матричной клавиатуры + DS18B20?
Господа, подскажите, пожалуйста, каким образом организовать опрос матричной клавиатуры и при этом...

25
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,864
25.10.2016, 12:26 2
Совет: сотрите и начните сначала, с чтения какой-нибудь статьи про матричную клавиатуру. Вы только читаете все 7 пинов - а надо по очереди занулять столбцы и читать строки (или наоборот).

Бонусом: а pouse у вас вообще работает? Не должна: оптимизатор точно заметит, что она ничего не делает.
0
sout
25.10.2016, 12:37 3
Почему же, сначала я подаю 1 на все 3 столбца, таким образом нахожу строку в которой нажата кнопка. Затем подаю 1 на все строки и нахожу столбец. Так и вычисляю нажатую кнопку.
pouse убрал, использую delay.
Уже перечитал гору статей по данному вопросу, почти все используют разные порты для строк и столбцов, что мне не подходит. Как реализовать опрос используя один порт не могу понять.
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 886
25.10.2016, 12:54 4
Наберите в гуглопоиске
arduino matrix keyboard
и изучите первые три ссылки (библиотеку и пример без неё)
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,864
25.10.2016, 13:05 5
А, виноват, невнимательно прочитал.

С одним портом - точно так же, как с двумя:
- выставляете DDRC=7 (C0-C2 - выходы, остальные входы)
- по очереди пишете в PORTC числа ~1, ~2, ~4 (установлены все биты, кроме бита нужного выхода)
- после записи - читаете PINC и проверяете биты C3-C7, если какой-то из них 0 - кнопка нажата
if( !(PINC&8) ) кнопка нажата
if( !(PINC&16) ) кнопка нажата
Сорри, налажал, ниже меня поправили... Но всё равно точно так же, как с двумя =)

А с вашим алгоритмом - просто надо всё наоборот делать: надо подавать 0 на все три столбца (и 1 на все строки), и искать строку, в которую придёт этот 0. И наоборот. Потому как подтяжка есть только вверх.
Но общепринятый алгоритм всё-таки другой.
0
0 / 0 / 0
Регистрация: 16.02.2016
Сообщений: 150
25.10.2016, 13:08 6
Цитата Сообщение от sout
Почему же, сначала я подаю 1 на все 3 столбца, таким образом нахожу строку в которой нажата кнопка. Затем подаю 1 на все строки и нахожу столбец. Так и вычисляю нажатую кнопку.
pouse убрал, использую delay.
Уже перечитал гору статей по данному вопросу, почти все используют разные порты для строк и столбцов, что мне не подходит. Как реализовать опрос используя один порт не могу понять.
А судя по коду подаёте нули.
Поэтому проверки надо заменить на что-то вроде:
Код
if ((PINC & 0x08) == 0) i=0;      //Если нажата клавиша в 0й строке, i=0
0
0 / 0 / 0
Регистрация: 16.02.2016
Сообщений: 150
25.10.2016, 13:12 7
Цитата Сообщение от oomomstir
- выставляете DDRC=7 (C0-C2 - выходы, остальные входы)
- по очереди пишете в PORTC числа ~1, ~2, ~4 (установлены все биты, кроме бита нужного выхода).
Если нажать одновременно две и более кнопки в определённых комбинациях, то это приведет к сгоранию порта или контроллера в целом. Выходным нужно делать только один пин (отвечающий за строку или колонку, которую хотим опросить), а остальные должны быть настроены на вход.
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,864
25.10.2016, 13:24 8
Mitzsshtomki, спасибо, я был неправ.
0
sout
25.10.2016, 13:32 9
Mitzsshtomki,
Чтобы не сгорели порты у меня стоят резисторы R1-R8, должно спасти в случае чего.
Изменил код, как вы посоветовали, теперь зависает цикл проверки как-будто какая-то кнопка нажата.
Код
     DDRC=0x07;
PORTC=0xF8;

_delay_ms(10);
i=5;

if ((PINC & 0x08) == 0) i=0;      //Если нажата клавиша в 0й строке, i=0
if ((PINC & 0x10) == 0) i=1;      //Если нажата клавиша в 1й строке, i=1
if ((PINC & 0x20) == 0) i=2;           //...
if ((PINC & 0x40) == 0) i=3;           //Если нажата клавиша в 3й строке, i=3
if ((PINC & 0x80) == 0) i=4;           //Если нажата клавиша в 4й строке, i=4

DDRC=0xF8;
PORTC=0x07;

_delay_ms(10);
j=3;

if ((PINC & 0x01) == 0) j=0;      //Если нажата клавиша в 0й колонке, j=0
if ((PINC & 0x02) == 0) j=1;      //...
if ((PINC & 0x04) == 0) j=2;

if ((i!=5)&&(j!=3)) {         //Если была нажата клавиша
while ((PINC&_BV(j))==0x00);   //Ждем пока кнопку отпустят

key = key_code[i][j];   //Пишем ее код в переменную
}
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 886
25.10.2016, 13:42 10
Все-таки зря не читаете
http://chipenable.ru/index.php/programm ... chine.html
http://www.labfor.ru/guidomce/mpu-leso1/3
http://iosyitistromyss.ru/matr... atura.html
http://avr-stort.ru/?p=1244
0
0 / 0 / 0
Регистрация: 16.02.2016
Сообщений: 150
25.10.2016, 14:40 11
Цитата Сообщение от sout
Mitzsshtomki,
Чтобы не сгорели порты у меня стоят резисторы R1-R8, должно спасти в случае чего.
Изменил код, как вы посоветовали, теперь зависает цикл проверки как-будто какая-то кнопка нажата.
Да, резисторы с нужными номиналами спасут.
А как определяете, что зависает именно в этом цикле?

В логике есть ещё одна неточность: переменная key не сбрасывается в 0, поэтому один раз среагировав на нажатие кнопки светодиоды будут моргать с частотой срабатывания прерывания.
0
0 / 0 / 0
Регистрация: 26.01.2009
Сообщений: 3
25.10.2016, 17:06 12
Цитата Сообщение от sout
Код:
ISR (TIMER0_OVF_vect)
{
...
pouse(10); //Задержка для устранения всяких переходных процессов, важно ее не забыть!
...
pouse(10); //Задержка для устранения всяких переходных процессов, важно ее не забыть!
...
while ((PINC&_BV(j))==0x00); //Ждем пока кнопку отпустят
...
}

Не надо так
0
sout
25.10.2016, 17:11 13
В дебаггере выполнение останавливается на этом цикле, но cycle counter растет.
Насчет key я так сделал специально, чтобы проверить, но диоды не загораются.
Все же завтра попробую переписать программу по общепринятому алгоритму.

http://i85.***********/big/2016/1026/af/0e55ad4a06ca50806f498e5c52bfd2af.jpg
sout
25.10.2016, 17:12 14
Цитата Сообщение от div
Не надо так
За тем и пришел, чтобы узнать как надо)
0 / 0 / 0
Регистрация: 16.02.2016
Сообщений: 150
26.10.2016, 00:22 15
Цитата Сообщение от sout
В дебаггере выполнение останавливается на этом цикле, но cycle counter растет.
Насчет key я так сделал специально, чтобы проверить, но диоды не загораются.
Все же завтра попробую переписать программу по общепринятому алгоритму.
Так понятно почему останавливается в цикле -- в регистре PINC все биты сброшены, хотя в реальности при отжатых кнопках значение регистра PINC будет соответствовать значению регистра PORTC (это в контексте эл. схемы из первого поста).
0
sout
26.10.2016, 08:49 16
По совету x893 еще раp перечитал все статьи. По совету oomomstir все переписал с начала, прерывание выкинул. В дебаггере все работает правильно, а на железе нет! Я все-таки порт сжег, или в коде ошибка?

Код
    #ymstude <avr/io.h>
#ymstude <avr/interrupt.h>
#ymstude <avr/delay.h>
int i=0,j=0;
char portState[5]= {0xF7,0xEF,0xDF,0xBF,0x7F};
char inputState[3]={0x01,0x02,0x04};
unsykned char key = 0;
unsykned char key_code[5][3]={{D,E,F},
{A,B,C},
{7,8,9},
{4,5,6},
{1,2,3}}; //матрица соответствия кодов клавиш

// Функция опроса клавиатуры
unsykned char scan_key(void)
{
for(i=0; i<5; i++)
{
PORTC=portState[i];
for(j=0; j<3; j++)
{
if(((PINC&inputState[j])!=0))
{
while((PINC&inputState[j])==inputState[j]){};
key=key_code[i][j];
return (key);
}
}
}
return (key);
}

//Основная программа
int main(void)
{
DDRA=0xFF;         //Инициируем PortA
PORTA=0x00;
DDRC=0xF8;          //Инициируем PortC
PORTC=0xFF;

while(1)
{

if(scan_key()!=0)
{
PORTA = 0xFF;
_delay_ms(500);
PORTA = 0x00;
}
}
}
0 / 0 / 0
Регистрация: 16.02.2016
Сообщений: 150
26.10.2016, 10:14 17
Цитата Сообщение от sout
В дебаггере все работает правильно, а на железе нет!
Судя по одному из предыдущих постов (со скринами процесса отладки) Вы дебагером пользоваться не умеете. Поэтому утверждение "в дебагере работает правильно" не соответствуют реальному положению дел.
Цитата Сообщение от sout
Я все-таки порт сжег, или в коде ошибка?
Одновременно две кнопки нажимали? Если да, то номиналы резисторов какие? Каждый пин может выдержать до 40 мА (номинал 20 мА).
А в коде есть ошибки:
- раз уж стали опрашивать строки -- в цикле устанавливать низкий уровень на одном из пинов порта С -- то только этот один пин должен быть выходным, а остальные входными (регистр DDRC должен меняться вместе с регистром PORTC);
- в цикле проверка нажатия кнопки не правильная -- на сроку подаёте низкий уровень, а ищите колонки с высоким уровнем;
- в том же цикле проверка отжатия кнопки так же не правильная -- цикл while будет бесконечно крутиться при отжатой кнопке, т.е. пока кнопку не нажмёте.

Ваш первый вариант (хоть и был своеобразным, но всё же имел право на существование) после всех внесённых исправлений по виду был рабочим, Вы его на железе проверяли?
0
sout
26.10.2016, 10:59 18
Цитата Сообщение от Mitzsshtomki
Вы дебагером пользоваться не умеете.
Согласен. Впервые после 5 лет перерыва занялся программированием)
Цитата Сообщение от Mitzsshtomki
Одновременно две кнопки нажимали?
Да, резисторы по 100 Ом, видимо этого мало, нужно было около 1k.
Цитата Сообщение от Mitzsshtomki
Вы его на железе проверяли?
Проверял, не работало. Возможно по причине нерабочего порта.
sout
26.10.2016, 11:57 19
Проверил мегу, похоже все-таки спалил первые 4 вывода порта С
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
26.10.2016, 12:09 20
Отключите фьюз JTAG
0
26.10.2016, 12:09
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.10.2016, 12:09
Помогаю со студенческими работами здесь

Сканирование матричной клавиатуры
Здравствуйте! Помогите пожалуйста разобраться. Я пишу опросник матричной клавы 3х4 на СИ в Keil под...

Эквивалентная схема матричной клавиатуры
Здравствуйте. Помогите нарисовать эквивалентную схему для матричной клавиатуры. Голову уже...

Метод опроса матричной клавиатуры.
Добрый день. Возник один вопрос. В моем устройстве используется матричная клавиатура. Опрашиваю я...

Контроллер матричной клавиатуры с выходом на i2c
Нужно подключить матричную клавиатуру (4x4) к raspberry. Использовать непосредственно пины платы...

Программа для матричной клавиатуры стенда SDK-1.1
Очень нужен текст программы, работающей с матричной клавиатурой стенда. Абсолютно любая программа...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru