Матричная клавиатура и прерывания в arduino due

max_sl
Offline
Зарегистрирован: 15.08.2016

Добрый день, возникла проблема подключения матричной клавиатуры к arduino due с использованием прерываний (точнее, адекватного снятия состояния кнопок)

Клавиатура использовалась вот такая: http://i.ebayimg.com/images/g/oMEAAOSwstxVE6y6/s-l300.jpg

Программа писалась по вот этой вот статье, только соответсвенно диоды\резисторы не напаивались, т.к. прерывания на дью можно снимать с любого пина, что и делалось.

http://robots4life.ru/matrichnaya-klaviatura-preryvani

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

В чем может быть ошибка?

Pyotr
Offline
Зарегистрирован: 12.03.2014

Для подключения матричной клавиатуры 4х4 выделяю порт МК. Вся схема это сама клава и 4 транзистора.
Достаточно раз в 10-50 мс опрашивать порт.

key = PINx; 

Для клавы 4х5 нужен ещё один пин другого порта.

max_sl
Offline
Зарегистрирован: 15.08.2016

А без транзисторов никак? Может посмотрите ссылки, что я прикрепил

Pyotr
Offline
Зарегистрирован: 12.03.2014

Выкладывайте скетч и подключение клавиатуры. У Вас 4х5, а в примере 4х4.

max_sl
Offline
Зарегистрирован: 15.08.2016

Тот скетч, что работает? Или тот, что нет?)

Саму схему, я так понимаю, вам сфоткать надо

Pyotr
Offline
Зарегистрирован: 12.03.2014

Если скетч работает, какие могут быть вопросы?

А схему, чтоб всем было понятно куда что подключено.

max_sl
Offline
Зарегистрирован: 15.08.2016

Вот схема подключения:

https://cloud.mail.ru/public/MLAC/pPGn7KmuG

А вот нерабочий скетч:

int PinOut[4] {7, 6, 5, 4}; // пины выходы
 
int PinIn[5] {12, 11, 10, 9, 8}; // пины входа
 
const char value[4][5]
 
 
{ {'1', '4', '7', '*', '$'},
  {'2', '5', '8', '0', '&'},
  {'3', '6', '9', '#', '?'},
  {'A', 'B', 'C', 'D', '@'}
};
// двойной массив, обозначающий кнопку
 
int b = 0; // переменная, куда кладется число из массива(номер кнопки)
void matrix (); 
void setup()
{
  pinMode (4, OUTPUT); // инициализируем порты на выход (подают нули на столбцы)
  pinMode (5, OUTPUT);
  pinMode (6, OUTPUT);
  pinMode (7, OUTPUT);
 
  pinMode (8, INPUT); // инициализируем порты на вход с подтяжкой к плюсу (принимают нули на строках)
  digitalWrite(8, HIGH);
  pinMode (9, INPUT);
  digitalWrite(9, HIGH);
  pinMode (10, INPUT);
  digitalWrite(10, HIGH);
  pinMode (11, INPUT);
  digitalWrite(11, HIGH);
  pinMode (12, INPUT);
  digitalWrite(12, HIGH);
  attachInterrupt(8, matrix, RISING); //подключаем прерывания для каждой строки
  attachInterrupt(9, matrix, RISING);
  attachInterrupt(10, matrix, RISING);
  attachInterrupt(11, matrix, RISING);
  attachInterrupt(12, matrix, RISING);
  Serial.begin(9600); // открываем Serial порт
}
 
void matrix () // создаем функцию для чтения кнопок
{
  for (int i = 1; i <= 4; i++) // цикл, передающий 0 по всем столбцам
  {
    digitalWrite(PinOut[i - 1], LOW); // если i меньше 4 , то отправляем 0 на ножку
    for (int j = 1; j <= 5; j++) // цикл, принимающих 0 по строкам, j заменено с 4 на 5 т.к строк 5.
    {
      if (digitalRead(PinIn[j - 1]) == LOW) // если один из указанных портов входа равен 0, то..
      {
        Serial.println( value[i - 1][j - 1]); // то b равно значению из двойного массива
        delay(175);
      }
    }
    digitalWrite(PinOut[i - 1], HIGH); // подаём обратно высокий уровень
  }
}
 

void loop()
{
}

 

Pyotr
Offline
Зарегистрирован: 12.03.2014

У Вас прерывание должно при смене 1->0, а не наоборот.
Вместо RISING  нужно FALLING.

attachInterrupt(xx, matrix, FALLING);

max_sl
Offline
Зарегистрирован: 15.08.2016

Pyotr пишет:

У Вас прерывание должно при смене 1->0, а не наоборот.
Вместо RISING  нужно FALLING.

attachInterrupt(xx, matrix, FALLING);

 

Не работает, пробовали и FALLING и CHANGE и RISING

Pyotr
Offline
Зарегистрирован: 12.03.2014

А без прерываний пробовали?

max_sl
Offline
Зарегистрирован: 15.08.2016

Pyotr пишет:

А без прерываний пробовали?

Без прерываний пробовали. Работает. Но нам это не подходит.

P.S 

Может быть на due особенности какие-то в работе прерываний, вроде у людей на uno работает все

Pyotr
Offline
Зарегистрирован: 12.03.2014

Строка 16

max_sl
Offline
Зарегистрирован: 15.08.2016

Pyotr пишет:

Строка 16

Что там? Без инициализации функции в начале, не работает скетч. Пишет что вне зоны видимости эта функция

p/s

Хотя не, на моем ide компилируется без 16-й строки, но результат все тот же - не работает программа

Pyotr
Offline
Зарегистрирован: 12.03.2014

Пины выходные в "1" нужно выставить.

max_sl
Offline
Зарегистрирован: 15.08.2016

И на вход и на выход 1? а платку не спалим?

Pyotr
Offline
Зарегистрирован: 12.03.2014

И кто так скетчи пишет...

Пробуйте так 

const byte PinOut[4] = {7, 6, 5, 4}; // пины выходы
const byte PinIn[5] = {12, 11, 10, 9, 8}; // пины входа
const char value[4][5] = {
  {'1', '4', '7', '*', '$'},
  {'2', '5', '8', '0', '&'},
  {'3', '6', '9', '#', '?'},
  {'A', 'B', 'C', 'D', '@'}
};
// двойной массив, обозначающий кнопку
char b = 0; // переменная, куда кладется число из массива(номер кнопки)
volatile byte flag;
void setup()
{
  for(byte i=0; i<4; i++){
    pinMode (PinOut[i], OUTPUT);
    digitalWrite(PinOut[i], HIGH);

  }
  for(byte i=0; i<5; i++){
    pinMode (PinIn[i], INPUT_PULLUP);
  }
  attachInterrupt(8, matrix, FALLING); //подключаем прерывания для каждой строки
  attachInterrupt(9, matrix, FALLING);
  attachInterrupt(10, matrix, FALLING);
  attachInterrupt(11, matrix, FALLING);
  attachInterrupt(12, matrix, FALLING);
  Serial.begin(9600); // открываем Serial порт
}
 
void matrix () // создаем функцию для чтения кнопок
{
  for (byte i = 0; i<4; i++) // цикл, передающий 0 по всем столбцам
  {
    digitalWrite(PinOut[i], LOW); // если i меньше 4 , то отправляем 0 на ножку
    for (byte j=0; j<5; j++) // цикл, принимающих 0 по строкам, j заменено с 4 на 5 т.к строк 5.
    {
      if (digitalRead(PinIn[j]) == LOW) // если один из указанных портов входа равен 0, то..
      {
        b = value[i][j]; // то b равно значению из двойного массива
        flag = 1;
        //delay(175);
      }
    }
    digitalWrite(PinOut[i], HIGH); // подаём обратно высокий уровень
  }
}
 

void loop()
{
  if(flag){
    flag = 0;
    Serial.println(b); // то b равно значению из двойного массива
  }
}

 

Pyotr
Offline
Зарегистрирован: 12.03.2014

Не, тоже не правильно...

max_sl
Offline
Зарегистрирован: 15.08.2016

Не, все равно в монитор ничего по нажатиям не выводит с вашим кодом

Pyotr
Offline
Зарегистрирован: 12.03.2014

Никогда так не опрашивал матричную клаву. Такая возня....

Пробуйте...

const byte PinOut[4] = {7, 6, 5, 4}; // пины выходы
const byte PinIn[5] = {12, 11, 10, 9, 8}; // пины входа
const char value[4][5] = {
  {'1', '4', '7', '*', '$'},
  {'2', '5', '8', '0', '&'},
  {'3', '6', '9', '#', '?'},
  {'A', 'B', 'C', 'D', '@'}
};
// двойной массив, обозначающий кнопку
char b = 0; // переменная, куда кладется число из массива(номер кнопки)
volatile byte flag;

void setup(){
  for(byte i=0; i<4; i++){
    pinMode (PinOut[i], OUTPUT);
  }
  for(byte i=0; i<5; i++){
    pinMode (PinIn[i], INPUT_PULLUP);
    attachInterrupt(PinIn[i], matrix, FALLING); //подключаем прерывания для каждой строки
  }
  Serial.begin(9600); // открываем Serial порт
}
 
void matrix (){ // создаем функцию для чтения кнопок
  byte j;
  byte i;
  for (j=0; j<5; j++){ // цикл, принимающих 0 по строкам, j заменено с 4 на 5 т.к строк 5.
    if(digitalRead(PinIn[j]) == LOW){ // если один из указанных портов входа равен 0, то..
      digitalWrite(PinIn[j], LOW);//откл. подтяжку
      pinMode (PinIn[i], OUTPUT);  //устан. на выход в "0"
      for(byte i = 0; i<4; i++){ 
         pinMode (PinOut[i], INPUT_PULLUP);//выходы перекл.на входы в "1"
         if(digitalRead(PinOut[i]) == LOW){ 
           b = value[i][j]; // то b равно значению из двойного массива
           flag = 1; //нужно вывести в сериал
           for(byte i=0; i<5; i++){
              pinMode (PinIn[i], INPUT_PULLUP);//входы снова на вход в "1"
           }
           for(byte i=0; i<4; i++){
             pinMode (PinOut[i], OUTPUT);//выходы снова на выход в "0"
           }
         }
      }
    }
  }
}
    
void loop(){
  if(flag){
    flag = 0;
    Serial.println(b); // то b равно значению из двойного массива
  }
}

 

Pyotr
Offline
Зарегистрирован: 12.03.2014

Кажись с переменными немного напутал...
Скетч с исправлениями.

const byte PinOut[4] = {7, 6, 5, 4}; // пины выходы
const byte PinIn[5] = {12, 11, 10, 9, 8}; // пины входа
const char value[4][5] = {
  {'1', '4', '7', '*', '$'},
  {'2', '5', '8', '0', '&'},
  {'3', '6', '9', '#', '?'},
  {'A', 'B', 'C', 'D', '@'}
};
// двойной массив, обозначающий кнопку
volatile char b = 0; // переменная, куда кладется число из массива(номер кнопки)
volatile byte flag;

void setup(){
  for(byte i=0; i<4; i++){
    pinMode (PinOut[i], OUTPUT);
  }
  for(byte i=0; i<5; i++){
    pinMode (PinIn[i], INPUT_PULLUP);
    attachInterrupt(PinIn[i], matrix, FALLING); //подключаем прерывания для каждой строки
  }
  Serial.begin(9600); // открываем Serial порт
}
 
void matrix (){ // создаем функцию для чтения кнопок
  byte j;
  byte i;
  for (j=0; j<5; j++){ // цикл, принимающих 0 по строкам, j заменено с 4 на 5 т.к строк 5.
    if(digitalRead(PinIn[j]) == LOW){ // если один из указанных портов входа равен 0, то..
      digitalWrite(PinIn[j], LOW);//откл. подтяжку
      pinMode (PinIn[j], OUTPUT);  //устан. на выход в "0"
      for(i=0; i<4; i++){ 
         pinMode (PinOut[i], INPUT_PULLUP);//выходы перекл.на входы в "1"
         if(digitalRead(PinOut[i]) == LOW){ 
           b = value[i][j]; // то b равно значению из двойного массива
           flag = 1; //нужно вывести в сериал
           for(i=0; i<5; i++){
              pinMode (PinIn[i], INPUT_PULLUP);//входы снова на вход в "1"
           }
           for(i=0; i<4; i++){
             pinMode (PinOut[i], OUTPUT);//выходы снова на выход в "0"
           }
         }
      }
    }
  }
}
    
void loop(){
  if(flag){
    flag = 0;
    Serial.println(b); // то b равно значению из двойного массива
  }
}

 

max_sl
Offline
Зарегистрирован: 15.08.2016

Эм. Трудно описать что происходит. Иногда сразу после загрузки скетч в мк и запуска монитора, в него вываливается несколько произвольных символов. Потом нажимаю на кнопку - проходит прерывание, правда кнопки не соответствуют, ну это ладно. В лупе при этом крутится наше значение и оно отображается в мониторе столько раз, сколько прокрутилось. Потом нажимаю на другие кнопки, и в монитор уже выводится цикл из того что было нажато, допустим жму "5" - понеслась "5 5 5 5 5 5 5 ...", жму затем 2 понеслась "5 2 5 2 5"

и так далее

UPD вот так уже лучше, сейчас попробую разобраться только со строками и столбцами)

max_sl
Offline
Зарегистрирован: 15.08.2016

Так, отчитываюсь.

Скетч работает, в мониторе печатаются введенные с клавиатуры символы единожды, но после примерно 5 раз печататся в монитор перестают. После этого я жму на МК кнопку reset, снова ввожу с клавиатуры несколько символов, и снова приходится жать ресет чтобы что-то ввести.

Еще иногда построчно символы путаются (то бишь нажатый символ может отобразится некоторым иным с данной строки)

Pyotr
Offline
Зарегистрирован: 12.03.2014

Скетч проверить не могу - Due у меня нет.

Почему Вам именно через прерывания нужно опрашивать? 
Могу посоветовать отказаться от такого способа опроса.

max_sl
Offline
Зарегистрирован: 15.08.2016

Клавиатура будет прилажена к другой Due, уже рабочему прибору с LCD экраном, который постоянно снимает показания с датчиков вибрации и других. Соответсвенно там в loop крутятся измерения, и вот была идея прикрутить к ней клавиатуру, реализуемую через прерывания.

Pyotr
Offline
Зарегистрирован: 12.03.2014

Так ЛУП то крутится, а не стоит. И что страшного если он на 10 мкс дольше будет крутится?

max_sl
Offline
Зарегистрирован: 15.08.2016

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

inspiritus
Offline
Зарегистрирован: 17.12.2012

Ооо дааа НАЧАЛЬНИК СКАЗАЛ. Ваш начальник если специалист, пусть сам делает, а если Вы специалист то пошлите его рекомендации и сделайте ПРАВИЛЬНО! 

Можно подумать, что прерывания громоздким вычислениям не помеха :)))) при уходе в прерывание главный цикл вооюще стоит, пока прерывание не кончится. 

Сделайте горячую кнопку ухода в меню и опрашивайте только ее, а при нажатии соответственно все тормозите и обрабатываете меню. Это аналогично прерыванию, но без переподвывертов. 

А если основной цикл тормозить нельзя .... Делайте отдельный контроллер клавиатуры и дружите его с вычислителем по ... Например i2c.

Pyotr
Offline
Зарегистрирован: 12.03.2014

Чуть допилил... Пробуйте.

const byte PinOut[4] = {7, 6, 5, 4}; // пины выходы
const byte PinIn[5] = {12, 11, 10, 9, 8}; // пины входа
const char value[4][5] = {
  {'1', '4', '7', '*', '$'},
  {'2', '5', '8', '0', '&'},
  {'3', '6', '9', '#', '?'},
  {'A', 'B', 'C', 'D', '@'}
};
// двойной массив, обозначающий кнопку
volatile char b; // переменная, куда кладется число из массива(номер кнопки)
volatile byte flag;

void setup(){
  for(byte i=0; i<4; i++){
    pinMode (PinOut[i], OUTPUT);
  }
  for(byte i=0; i<5; i++){
    pinMode (PinIn[i], INPUT_PULLUP);
    attachInterrupt(PinIn[i], matrix, FALLING); //подключаем прерывания для каждой строки
  }
  Serial.begin(9600); // открываем Serial порт
}
 
void matrix (){ // создаем функцию для чтения кнопок
  byte j;
  byte i;
  for (j=0; j<5; j++){ // цикл, принимающих 0 по строкам, j заменено с 4 на 5 т.к строк 5.
    if(digitalRead(PinIn[j]) == LOW){ // если один из указанных портов входа равен 0, то..
      digitalWrite(PinIn[j], LOW);//откл. подтяжку
      pinMode (PinIn[j], OUTPUT);  //устан. на выход в "0"
      break;
    }
  }
  for(i=0; i<4; i++){ 
     pinMode (PinOut[i], INPUT_PULLUP);//выходы перекл.на входы в "1"
     if(digitalRead(PinOut[i]) == LOW){ 
       b = value[i][j]; // то b равно значению из двойного массива
       flag = 1; //нужно вывести в сериал
       break;
     }
  }
   for(i=0; i<5; i++){
      pinMode (PinIn[i], INPUT_PULLUP);//входы снова на вход в "1"
   }
   for(i=0; i<4; i++){
     pinMode (PinOut[i], OUTPUT);//выходы снова на выход в "0"
   }
}
    
void loop(){
  if(flag){
    flag = 0;
    Serial.println(b); // то b равно значению из двойного массива
  }
}

 

max_sl
Offline
Зарегистрирован: 15.08.2016

Теперь кнопки путает) Но зато можно ввести 6 раз вместо 5 без reseta

diakin
diakin аватар
Offline
Зарегистрирован: 04.06.2016

Вот так должно работать )


const byte PinOut[4] = {7, 6, 5, 4}; // пины выходы
const byte PinIn[5] = {12, 11, 10, 9, 8}; // пины входа
const char value[4][5] = {
  {'1', '4', '7', '*', '$'},
  {'2', '5', '8', '0', '&'},
  {'3', '6', '9', '#', '?'},
  {'A', 'B', 'C', 'D', '@'}
};
// двойной массив, обозначающий кнопку
volatile char btn; // переменная, куда кладется число из массива(номер кнопки)
volatile byte flag,row, col; // номер строки и столбца нажатой кнопки

void setup(){
  for(byte i=0; i<4; i++){
    pinMode (PinOut[i], OUTPUT); //устанавливаем столбцы в 0
  }
  for(byte i=0; i<5; i++){
    pinMode (PinIn[i], INPUT_PULLUP); //входы (строки) подтянуты к 1
    attachInterrupt(PinIn[i], matrix, FALLING); //подключаем прерывания для каждой строки
  }
  Serial.begin(9600); // открываем Serial порт
}
 
void matrix (){ // создаем функцию для чтения кнопок
  byte j;
  byte i;
  for (j=0; j<5; j++){ // перебираем по строкам, ищем в какой строке 0
    if(digitalRead(PinIn[j]) == LOW){ // если один из указанных портов входа равен 0, то..
    row=j; //запоминаем номер строки, в которой 0
      break;
    }
  }
  for(i=0; i<4; i++) //перебираем по столбцам, переключаем их в 1 и читаем найденную выше строку
{ 
     pinMode (PinOut[i], INPUT_PULLUP);//выходы перекл.на входы в "1"
     if(digitalRead(PinIn[row]) == LOW){ 
       col=i; // запоминаем столбец
       flag=1;
       break;
     }
  }
   for(i=0; i<4; i++){
     pinMode (PinOut[i], OUTPUT);//выходы снова на выход в "0"
   }
}
    
void loop(){
  if(flag){
    flag = 0;
    Serial.println(value[col][row]); // то b равно значению из двойного массива
  }
}


 

max_sl
Offline
Зарегистрирован: 15.08.2016

По этому коду выводит первое значениие в строке, то есть *,U,D,E,N

(наименования символов поправил согласно нашей клавиатуре)

diakin
diakin аватар
Offline
Зарегистрирован: 04.06.2016

Проблема может быть в том, что когда мы возвращаем стобцы в 0 процедуре прерывания, кнопка все еще остается нажатой и прерывание снова срабатывает? Или не срабатывает, т.е. флаг прерывания повторно не взводится?)
 

for(i=0; i<4; i++){
	     pinMode (PinOut[i], OUTPUT);//выходы снова на выход в "0"
	   }

 

diakin
diakin аватар
Offline
Зарегистрирован: 04.06.2016

то есть строки нормально, а столбец всегда первый?
а как все остальное? reset жать не надо?

diakin
diakin аватар
Offline
Зарегистрирован: 04.06.2016

max_sl пишет:

По этому коду выводит первое значениие в строке, то есть *,U,D,E,N

(наименования символов поправил согласно нашей клавиатуре)

Там надо HIGH, а не LOW в 36 строке. Т.е. переключам столбцы в 1 и проверяем на каком столбце в нашей строке появится 1.

33

    for(i=0; i<4; i++) //перебираем по столбцам, переключаем их в 1 и читаем найденную выше строку
34 {
35      pinMode (PinOut[i], INPUT_PULLUP);//выходы перекл.на входы в "1"
36      if(digitalRead(PinIn[row]) == HIGH){
37        col=i; // запоминаем столбец
38        flag=1;
39        break;
40      }
41   }

 

max_sl
Offline
Зарегистрирован: 15.08.2016

Да,насчет HIGH уже заметил. Но все равно определяет нажатую кнопку неверно

ресет жать не надо

p/s

Может,подключить библиотеку от дребезга контактов?

 

diakin
diakin аватар
Offline
Зарегистрирован: 04.06.2016

проблема-то не в дребезге. А что значит - неверно? После замены Low на High поменнялось что-нибудь?

ps в 35 строке тоже надо digitalWrite(PinOut[i], HIGH);
То есть переключаем выход в 1.
 

max_sl
Offline
Зарегистрирован: 15.08.2016

Ну не ту кнопку выводит в монитор, хоть и с той строки

А почему не в дребзге? Мы же по FALLING ловим, а в дребзге одного нажатия одной кнопки этих самых FALLING по идее будет несколько...

diakin
diakin аватар
Offline
Зарегистрирован: 04.06.2016

то есть строки определяет правильно, а столцы нет? Но хоть разные столбцы или все время первый?

зы. Столбцы-то неправильно определяет не из-за дребезга.

max_sl
Offline
Зарегистрирован: 15.08.2016

Столбцы разные. Насчет дребзга появилась идея, т.к во время нажатия успевал вывести в монитор несколько значений (2-3) и все неправильные)

max_sl
Offline
Зарегистрирован: 15.08.2016
const byte PinOut[4] = {7, 6, 5, 4}; // пины выходы
const byte PinIn[5] = {12, 11, 10, 9, 8}; // пины входа
const char value[4][5] = {
  {'1', '4', '7', '*', '$'},
  {'2', '5', '8', '0', '&'},
  {'3', '6', '9', '#', '?'},
  {'A', 'B', 'C', 'D', '@'}
};
// двойной массив, обозначающий кнопку
volatile static char btn; // переменная, куда кладется число из массива(номер кнопки)
volatile static int flag, row = -1, col = -1; // номер строки и столбца нажатой кнопки

void setup() {
  for (byte i = 0; i < 4; i++) {
    pinMode (PinOut[i], OUTPUT); //устанавливаем столбцы в 0
  }
  for (byte i = 0; i < 5; i++) {
    pinMode (PinIn[i], INPUT_PULLUP); //входы (строки) подтянуты к 1
    attachInterrupt(PinIn[i], matrix, FALLING); //подключаем прерывания для каждой строки
  }
  Serial.begin(9600); // открываем Serial порт
}



//****************************************
void matrix () { // создаем функцию для чтения кнопок
  byte j;
  byte i;
  flag = 1;
  //  noInterrupts();
  for (j = 0; j < 5; j++) { // перебираем по строкам, ищем в какой строке 0
    if (digitalRead(PinIn[j]) == LOW) { // если один из указанных портов входа равен 0, то..
      row = j; //запоминаем номер строки, в которой 0
      flag = 1;
      break;
    }
  }
  for (i = 0; i < 4; i++) //перебираем по столбцам, переключаем их в 1 и читаем найденную выше строку
  {
    digitalWrite(PinOut[i], HIGH);//выходы перекл.на входы в "1"
    if (digitalRead(PinIn[row]) == HIGH)
    {
      col = i; // запоминаем столбец
      flag = 1;
      break;
    }

  }
  //  for (i = 0; i < 4; i++) {
  //    digitalWrite(PinOut[i], LOW);;//выходы снова на выход в "0"
  //  }
  //  interrupts();

}

//****************************************
void loop() {

  if (flag) {
    flag = 0;
    //    Serial.println(value[col][row]); // то b равно значению из двойного массива

    Serial.println("col=" + String(col) + " row=" + String(row)); // то b равно значению из двойного массива

  }
  for (int i = 0; i < 1000; i++)
  {
    delay(2);
    if (flag) {
      break;
      functionF2();
    }
  }
  
  
 for (int i = 0; i < 4; i++)
  {
    digitalWrite(PinOut[i], LOW);;//выходы снова на выход в "0"
  }

 

}



Добились более-менее рабочего кода (в монитор идут символы, пока кнопка нажата), если не выставлять значения delay в loop`е

 

diakin
diakin аватар
Offline
Зарегистрирован: 04.06.2016

Смысл в том, что пока кнопка нажата и не отпущена - символы в монитор порта не идут. Только когда кнопка отпускается Serial.println что-то пишет, ( но неправильно).  Это означает, что пока кнопка нажата - непрерывно генерится прерывание и мы постоянно крутимся в обработчике. Видимо потому, что в конце обработчика стоит
//  for (i = 0; i < 4; i++) {

51   //    digitalWrite(PinOut[i], LOW);;//выходы снова на выход в "0"
52   //  }

и установка выхода в 0 при нажатой кнопке воспринимается как FALLING и снова генерится прерывание.  Если бы можно было сконфигурить сброс флага прерывания при выходе из процедуры-обработчика или запретить установку флана прерывания, пока находишься в обработчике, то все работало бы.
В нашем случае
digitalWrite(PinOut[i], LOW);;//выходы снова на выход в "0"
было вынесено в loop(). При нажатой кнопке прерывание конечно генерится снова, когда в loop() доходит до этой строчки, но уже можно обработать события нажатие клавиши.
 

diakin
diakin аватар
Offline
Зарегистрирован: 04.06.2016

Можно кстати опрашивать клавиатуру через прерывание по таймеру. Тогда можно выбрать приемлемую задержку реакции на нажатия кнопки. https://avrlab.com/node/85

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Добрый вечер, заказал для проекта клавиатуру 1 строка 6 столбцов. На прошлой неделе пришла, вна фото(в нее также встроен светодиод, но его не пользовал). На просторах интернета нашел код без библиотек, для моей клавитуры как раз. Смысл такой: по нажатию клавиши в монитор порта выводится символ этой клавиши. Переписал через регистровое представление пинов ардуино ( у меня uno), лично мне так  читабельнее. Все работает, но мешает развитию delay. 

/*** Подключение матричной клавиатуры к микроконтроллеру AVR ***/
#include <avr/io.h> // библиотека в которой находятся определения констант, имен регистров avr

const char value[6] = {'1', '2', '3', '4', '5', '6'};

void setup() {
  /*pinMode (8, OUTPUT);
  pinMode (9, OUTPUT);
  pinMode (10, OUTPUT);
  pinMode (11, OUTPUT);
  pinMode (12, OUTPUT);
  pinMode (13, OUTPUT);
  pinMode (6, INPUT_PULLUP);  // порт на вход с подтяжкой (принимают нули на строках)*/
  DDRB |= (1 << PB5)|(1 << PB4)|(1 << PB3)|(1 << PB2)|(1 << PB1)|(1 << PB0); // инициализируем порты на выход(столбцы)
  DDRC &= ~(1 << PC2); // порт на вход(строка)
  PORTC |= 1 << PC2; // подключить внутренние подтягивающие pull-up резисторы
  
  Serial.begin(9600); // открываем Serial порт
}

void scan_key(){ // создаем функцию для чтения кнопок
  for (byte i = 0; i <= 5; i++) {  // цикл, передающий 0 по всем столбцам
    PORTB &= ~(1 << i);  //digitalWrite(PinOut[i - 1], LOW); // если i меньше 6 , то отправляем 0 на ножку
    if (!(PINC&0x04)) { //if (digitalRead(PinIn) == LOW) { // если порт входа равен 0, то..
        Serial.println(value[i]); 
        delay(175);
    }
        PORTB |= 1 << i;  //digitalWrite(PinOut[i - 1], HIGH); // подаём обратно высокий уровень
  }
}

void loop() {
  scan_key(); // используем функцию опроса матричной клавиатуры
}
BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

"Можно кстати опрашивать клавиатуру через прерывание по таймеру" - Я так и решил действовать. На сайте http://www.instructables.com/id/Arduino-Timer-Interrupts/ вполне понятно объяснено о работе таймеров, конкетно о прерывание по таймеру. Вот код взятый оттуда blink на таймере 1 каждую секунду

//#define F_CPU 16000000UL
#include <avr/io.h> // библиотека в которой находятся определения констант, имен регистров avr
#include <avr/interrupt.h>  

boolean toggle1 =0;

void setup() {
  DDRB |= 1 << PB5;
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0; // начальное значение таймера
  OCR1A = 15624; // 16000000 / (1024 * 1) - 1 = 15624
  TCCR1B |= (1<<CS10)|(1<<CS12)|(1<<WGM12); // делитель f/1024, устанавливаем режим СТС (сброс по совпадению)
  TIMSK1 = (1 << OCIE1A); //устанавливаем бит разрешения прерывания по совпадению с OCR1A
  sei(); // Выставляем бит общего разрешения прерываний
}

ISR(TIMER1_COMPA_vect){ // timer 1
  if(toggle1){
    PORTB |= 1 << PB5;
    toggle1 = 0;
  }
  else {
    PORTB &= ~(1 << PB5);
    toggle1 = 1;
  }
}

void loop() {

}

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Применительно к клаве от сериал соединения отказался сразу поскольку уже где то сталкивался, что в прерывании могут потеряться байты по UART. На основе предыдущего написал код, который задейтвует 5 клавиш клавиатуры, шестую заменил светодиод. Смысл в вызове функции обработчика каждые 50 мс для устранения дребезга, но код не фурычит. А кода - по нажатию любой клавиши должен загореться диод. Подскажите в чем ошибся? 

//#define F_CPU 16000000UL
#include <avr/io.h> // библиотека в которой находятся определения констант, имен регистров avr
#include <avr/interrupt.h>  

volatile byte i;

void setup() {
  DDRB |= (1 << PB5)|(1 << PB4)|(1 << PB3)|(1 << PB2)|(1 << PB1)|(1 << PB0); // инициализируем порты на выход(столбцы)
  DDRC &= ~(1 << PC2); // порт на вход(строка)
  PORTC |= 1 << PC2; // подключить внутренние подтягивающие pull-up резисторы
  
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0; // начальное значение таймера
  OCR1A = 780; // 16000000 / (1024 * 20) - 1 = 780 -> частота опроса клавиатуры 50 мс
  TCCR1B |= (1<<CS10)|(1<<CS12)|(1<<WGM12); // делитель f/1024, устанавливаем режим СТС (сброс по совпадению)
  TIMSK1 = (1 << OCIE1A); //устанавливаем бит разрешения прерывания по совпадению с OCR1A
  sei(); // Выставляем бит общего разрешения прерываний
}

ISR(TIMER1_COMPA_vect){ // timer 1
  for (i = 0; i <= 4; i++) {  // цикл, передающий 0 по всем столбцам
    PORTB &= ~(1 << i);  // если i меньше 6 , то отправляем 0 на ножку
    if (!(PINC&0x04)) {  // если порт входа равен 0, то..
        PORTB |= 1 << PB5;
    }
        PORTB |= 1 << i;  // подаём обратно высокий уровень
  }
}

void loop() {

}

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Мне как новичку не совсем понятно, как правильно организовать обработку клавиатуры за пределами loop

Клапауций 555
Offline
Зарегистрирован: 10.03.2018

BuonanotteMasha пишет:

обработку клавиатуры за пределами loop

это где? - на сеновале? О_О

diakin
diakin аватар
Offline
Зарегистрирован: 04.06.2016

А зачем отсылать байты в прерывании? В прерывании выставляется флаг\записывается значние переменной, а в loop проверяется состояние флага и выполняются нужные операции.
Для проверки можно установить опрос в 500 мс и в прерывании зажигать и гасить светодиод. Тогда будет видно, проходит ли прерывание вообще. А дальше добавить в прерывании проверку нажатия клавиши и зажигать светодиод в зависимости от состояния клавиши.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Спасибо, как освобожусь буду пробывать