Форум программистов, компьютерный форум, киберфорум
Электроника для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.57/37: Рейтинг темы: голосов - 37, средняя оценка - 4.57
sout

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

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

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


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

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
    #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;
}
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
25.10.2016, 11:38
Ответы с готовыми решениями:

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

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

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

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

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

С одним портом - точно так же, как с двумя:
- выставляете 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
Цитата Сообщение от sout
Почему же, сначала я подаю 1 на все 3 столбца, таким образом нахожу строку в которой нажата кнопка. Затем подаю 1 на все строки и нахожу столбец. Так и вычисляю нажатую кнопку.
pouse убрал, использую delay.
Уже перечитал гору статей по данному вопросу, почти все используют разные порты для строк и столбцов, что мне не подходит. Как реализовать опрос используя один порт не могу понять.
А судя по коду подаёте нули.
Поэтому проверки надо заменить на что-то вроде:
Code
1
if ((PINC & 0x08) == 0) i=0;      //Если нажата клавиша в 0й строке, i=0
0
0 / 0 / 0
Регистрация: 16.02.2016
Сообщений: 150
25.10.2016, 13:12
Цитата Сообщение от oomomstir
- выставляете DDRC=7 (C0-C2 - выходы, остальные входы)
- по очереди пишете в PORTC числа ~1, ~2, ~4 (установлены все биты, кроме бита нужного выхода).
Если нажать одновременно две и более кнопки в определённых комбинациях, то это приведет к сгоранию порта или контроллера в целом. Выходным нужно делать только один пин (отвечающий за строку или колонку, которую хотим опросить), а остальные должны быть настроены на вход.
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,864
25.10.2016, 13:24
Mitzsshtomki, спасибо, я был неправ.
0
sout
25.10.2016, 13:32
Mitzsshtomki,
Чтобы не сгорели порты у меня стоят резисторы R1-R8, должно спасти в случае чего.
Изменил код, как вы посоветовали, теперь зависает цикл проверки как-будто какая-то кнопка нажата.
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
     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
Все-таки зря не читаете
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
Цитата Сообщение от sout
Mitzsshtomki,
Чтобы не сгорели порты у меня стоят резисторы R1-R8, должно спасти в случае чего.
Изменил код, как вы посоветовали, теперь зависает цикл проверки как-будто какая-то кнопка нажата.
Да, резисторы с нужными номиналами спасут.
А как определяете, что зависает именно в этом цикле?

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

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

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

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
    #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
Цитата Сообщение от sout
В дебаггере все работает правильно, а на железе нет!
Судя по одному из предыдущих постов (со скринами процесса отладки) Вы дебагером пользоваться не умеете. Поэтому утверждение "в дебагере работает правильно" не соответствуют реальному положению дел.
Цитата Сообщение от sout
Я все-таки порт сжег, или в коде ошибка?
Одновременно две кнопки нажимали? Если да, то номиналы резисторов какие? Каждый пин может выдержать до 40 мА (номинал 20 мА).
А в коде есть ошибки:
- раз уж стали опрашивать строки -- в цикле устанавливать низкий уровень на одном из пинов порта С -- то только этот один пин должен быть выходным, а остальные входными (регистр DDRC должен меняться вместе с регистром PORTC);
- в цикле проверка нажатия кнопки не правильная -- на сроку подаёте низкий уровень, а ищите колонки с высоким уровнем;
- в том же цикле проверка отжатия кнопки так же не правильная -- цикл while будет бесконечно крутиться при отжатой кнопке, т.е. пока кнопку не нажмёте.

Ваш первый вариант (хоть и был своеобразным, но всё же имел право на существование) после всех внесённых исправлений по виду был рабочим, Вы его на железе проверяли?
0
sout
26.10.2016, 10:59
Цитата Сообщение от Mitzsshtomki
Вы дебагером пользоваться не умеете.
Согласен. Впервые после 5 лет перерыва занялся программированием)
Цитата Сообщение от Mitzsshtomki
Одновременно две кнопки нажимали?
Да, резисторы по 100 Ом, видимо этого мало, нужно было около 1k.
Цитата Сообщение от Mitzsshtomki
Вы его на железе проверяли?
Проверял, не работало. Возможно по причине нерабочего порта.
sout
26.10.2016, 11:57
Проверил мегу, похоже все-таки спалил первые 4 вывода порта С
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
26.10.2016, 12:09
Отключите фьюз JTAG
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
26.10.2016, 12:09
Помогаю со студенческими работами здесь

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка SDL3 и Box2D из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru