Обсуждаем контроллеры компании Atmel.
Ответить

Опрос матричной клавиатуры.

Чт июл 21, 2022 16:09:19

Доброе время суток. Есть код опроса матричной клавиатуры и вывода данных на LCD дисплей. У автора он работал. Я внёс не большое изменения, переключил строки на другой порт и теперь как бы я не старался, код не работает. С автором связаться не смог так как статья 24.08.2013 года. Может кто поможет понять ошибку? Сам код и схема :
Спойлер
Код:
#include <mega8.h>
// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x18 ;PORTB
#endasm
#include <lcd.h>

int i=0,j=0;
char portStateC[4]= {0xEF,0xDF,0xBF,0x7F};
char inputStateD[4]={0x01,0x02,0x04,0x08};
char mass2[4][4]={{'1','2','3','4'},
                  {'5','6','7','8'},
                  {'9','A','B','C'},
                  {'D','E','F','D'}};

interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
    for(i=0; i<4; i++)
    {
       PORTD=portStateC[i];
       for(j=0; j<4; j++)
       {
          if(((PIND&inputStateD[j])==0) && (PINC&inputStateD[j]))
          {
             while((PIND&inputStateD[j])!=inputStateD[j]){};
             lcd_putchar(mass2[i][j]);                                     
          } 
       }                         
    } 
}

void main(void)
{


PORTC=0xFF;
DDRC=0x0F;


PORTD=0xFF;
DDRD=0xF0;


ASSR=0x00;
TCCR2=0x0F;
TCNT2=0x00;
OCR2=0xC3;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x80;


lcd_init(8);

// Global enable interrupts
#asm("sei")
while (1)
      {
     
      };
}


Изображение

Добавил файлы проекта.
Вложения
key4x4.zip
(18.74 KiB) Скачиваний: 60
Последний раз редактировалось azerhud Пт июл 22, 2022 09:30:37, всего редактировалось 2 раз(а).

Re: Опрос матричной клавиатуры.

Чт июл 21, 2022 19:39:09

Проект вместе с протеусом сюда, в архив zip, иначе ни кто вам этот код разбирать не будет.

Re: Опрос матричной клавиатуры.

Чт июл 21, 2022 21:55:42

char portStateC[4]= {0xEF,0xDF,0xBF,0x7F}; здесь смещение нуля в старших разрядах, но в схеме подключено к младшим.
char inputStateD[4]={0x01,0x02,0x04,0x08}; здесь смещение единицы в младших разрядах, но в схеме подключено к старшим.
PORTD=portStateC[i] здесь к D происходит подключение того, что для C, и 1это вроде бы делает логичным нелогичное выше, но нелогично в целом.
if(((PIND&inputStateD[j])==0) && (PINC&inputStateD[j])) - inputStateD как бы намекает, что это для сравнения с D как со входом... но: выше уже всё было перепутано, а тут внезапно сравнивается и PIND и PINC...

И всё это вообще неважно: по схеме порт D является входом для сигнала с порта C. В порту C в младших четырёх разрядах должна бегать единичка, притом, цикл из 4 итераций не нужен, лучше поднять частоту срабатывания таймера. И массив для перемещения единичким тоже не нужен, есть прекрасные короткие сдвиги. А в программе всё наоборот и в кашу

Re: Опрос матричной клавиатуры.

Пт июл 22, 2022 06:30:48

Здесь подправил.
Код:
char portStateC[4]= {0xFE,0xFD,0xFB,0xF7};
char inputStateD[4]={0x01,0x20,0x40,0x80};

//...

interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
    for(i=0; i<4; i++)
    {
       PORTC=portStateC[i];
       for(j=0; j<4; j++)
       {
          if(((PIND&inputStateD[j])==0) && (PINC&inputStateD[j]))
          {
             while((PIND&inputStateD[j])!=inputStateD[j]){};
             lcd_putchar(mass2[i][j]);                                     
          }
       }                         
    }
}
//...


Но похоже опять я сделал что то не так
Последний раз редактировалось azerhud Пт июл 22, 2022 13:59:44, всего редактировалось 1 раз.

Re: Опрос матричной клавиатуры.

Пт июл 22, 2022 09:48:02

А я тоже ошибся, в логике. Прошу прощения.
Сканирующим портом всё-таки является порт D и там должен бегать лог. 0 - тогда при нажатии двух и более кнопок исключается закорачивание выходов, если бы сканирование было на порту С

то есть, скан должен быть так (как и было в самом начале, за исключением несовпадающих по логике наименований):
Код:
char portStateD[4]= {0xEF,0xDF,0xBF,0x7F};
char portStateD[4]= {0xEF,0xDF,0xBF,0x7F};
//...
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
    for(i=0; i<4; i++)
    {
       PORTD=portStateD[i];
       for(j=0; j<4; j++)
       {
          //...
       }                         
    }
}


то есть, осталось всего лишь правильно определить во втором цикле, где на порту С образовался 0.
Кстати, порт С должен обязательно быть сконфигурирован с внутренней подтяжкой к питанию.
например, так:
Код:
char portStateD[4]= {0xEF,0xDF,0xBF,0x7F};
//...
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
    for(i=0; i<4; i++)
    {
       PORTD=portStateD[i];
       for(j=0; j<4; j++)
       {
          if(!(PORTС & (1 << j))
          {
                   //здесь получили координаты i и j кнопки
           }
       }                         
    }
}

Re: Опрос матричной клавиатуры.

Пт июл 22, 2022 10:05:53

Не совсем понял этот момент.
...
то есть, скан должен быть так (как и было в самом начале, за исключением несовпадающих по логике наименований):
Код:
char portStateD[4]= {0xEF,0xDF,0xBF,0x7F};
char portStateD[4]= {0xEF,0xDF,0xBF,0x7F};
//...
   


мне нужно дважды задать этот массив?
Код:
har portStateD[4]= {0xEF,0xDF,0xBF,0x7F};
char portStateD[4]= {0xEF,0xDF,0xBF,0x7F};


Весь код.
Спойлер
Код:
#include <mega8.h>
// Alphanumeric LCD Module functions
#asm
.equ __lcd_port = 0x18 ; PORTB
#endasm
#include <lcd.h>

int i = 0, j = 0;
char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};
char inputStateC[4] = {0x01, 0x02, 0x04, 0x08};
char mass2[4][4] = {{'1', '2', '3', '4'},
   {'5', '6', '7', '8'},
   {'9', 'A', 'B', 'C'},
   {'D', 'E', 'F', 'D'}
};

interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
   for(i = 0; i < 4; i++)
      {
      PORTD = portStateD[i];
      for(j = 0; j < 4; j++)
         {
         if((!(PORTC) & (1 << j)))
            {
            if(((PIND & inputStateC[j]) == 0) && (PINC & inputStateC[j]))
               {
               while((PIND & inputStateC[j]) != inputStateC[j]) {};
               lcd_putchar(mass2[i][j]);
               }
            }
         }
      }
}

void main(void)
{


   PORTC = 0xFF;
   DDRC = 0x0F;


   PORTD = 0xFF;
   DDRD = 0xF0;


   ASSR = 0x00;
   TCCR2 = 0x0F;
   TCNT2 = 0x00;
   OCR2 = 0xC3;

   // Timer(s)/Counter(s) Interrupt(s) initialization
   TIMSK = 0x80;


   lcd_init(8);

   // Global enable interrupts
#asm("sei")
   while (1)
      ;
}

Re: Опрос матричной клавиатуры.

Пт июл 22, 2022 11:47:49

Вам же дали готовую процедуру
Вот так попробуйте
Код:
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
  for(i = 0; i < 4; i++) {
    PORTD = portStateD[i];
    for(j = 0; j < 4; j++) {
     if((!(PINC) & (1 << j)))
       lcd_putchar(mass2[i][j]);
    }
  }
}

char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F}; //только один раз, конечно нужно объявлять
char inputStateC[4] = {0x01, 0x02, 0x04, 0x08}; // в предлагаемом варианте вообще не нужен

И да, вам еще сказали, что младшие линии порта опроса (PORTC) должны быть настроены на вход с подтяжкой. И посмотрите, как у вас. Чтобы не путаться, избегайте магических цифр, или хотя бы дополняйте их подробным комментарием, куда, что и как настраивается. Хотя бы как визард это делает:
Код:
// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=P State6=P State5=P State4=P State3=P State2=P State1=P State0=P
PORTB=0xFF;
DDRB=0x00;

Re: Опрос матричной клавиатуры.

Пт июл 22, 2022 13:23:17

Уже не знаю что делать, вроде перепробовал все Ваши варианты.
Спойлер
Код:
#include <mega8.h>
// Alphanumeric LCD Module functions
#asm
.equ __lcd_port = 0x18 ; PORTB
#endasm
#include <lcd.h>

int i = 0, j = 0;
char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};

char mass2[4][4] = {{'1', '2', '3', '4'},
   {'5', '6', '7', '8'},
   {'9', 'A', 'B', 'C'},
   {'D', 'E', 'F', 'D'}
};

interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
  for(i = 0; i < 4; i++) {
    PORTD = portStateD[i];
    for(j = 0; j < 4; j++) {
     if((!(PINC) & (1 << j)))
       lcd_putchar(mass2[i][j]);
    }
  }
}

void main(void)
{     
   DDRC = 0x0F; // Единица младших разрядах, порт настроен как выход,
   PORTC = 0xFF; // Включаем подтягивающие резисторы

   DDRD = 0xF0; // Ноль младших разрядах, порт настроен как вход,
   PORTD = 0xFF; // Включаем подтягивающие резисторы

   ASSR = 0x00;
   TCCR2 = 0x0F;
   TCNT2 = 0x00;
   OCR2 = 0xC3;

   TIMSK = 0x80;


   lcd_init(8);

   // Global enable interrupts
#asm("sei")
   while (1)
      ;
}


Опишу проблему. Исходная статья по адресу http://avr-start.ru/?p=1244&cpage=1#comments
Всё работает отлично, но мне нужно подключить клавиатуру 4х5 и передавать символы нажатой кнопки по UART. Для этого я и решил разделить строки и столбцы. Но как бы я не пытался не удаётся мне запустить программу. Может найдётся человек который напишет мне рабочую программу с подробным описанием. Готов заплатить. Бюджет не большой :(

У самого уже мозги кипят. :(

Re: Опрос матричной клавиатуры.

Пт июл 22, 2022 14:19:49

Спойлер
Код:
char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};
char inputStateC[4] = {0x01, 0x02, 0x04, 0x08};
char mass2[4][4] = {{'1', '2', '3', '4'},
   {'5', '6', '7', '8'},
   {'9', 'A', 'B', 'C'},
   {'D', 'E', 'F', 'D'}
};

interrupt [TIM2_COMP] void timer2_comp_isr(void)
{   char i,j;
    for(i=0; i<4; i++)
    {
       PORTD=portStateD[i];
       for(j=0; j<4; j++)
       {
          if(((PINC&inputStateC[j])==0))
          {
             while((PINC&inputStateC[j])!=inputStateC[j]){};
             lcd_putchar(mass2[i][j]);                                     
          } 
       }                         
    } 
}

void main(void)
{     
   DDRC = 0x00;
   PORTC = 0xFF;

   DDRD = 0xF0;
   PORTD = 0xFF;

   ASSR = 0x00;
   TCCR2 = 0x0F;
   TCNT2 = 0x00;
   OCR2 = 0xC3;

   TIMSK = 0x80;

   lcd_init(8);

#asm("sei")
   while (1)
      ;
}

Re: Опрос матричной клавиатуры.

Пт июл 22, 2022 15:33:13

Dimon456, Огромное СПАСИБО за помощь

Re: Опрос матричной клавиатуры.

Пт июл 22, 2022 15:37:29

azerhud писал(а): DDRC = 0x0F; // Единица младших разрядах, порт настроен как выход,
   PORTC = 0xFF; // Включаем подтягивающие резисторы

metan писал(а):И да, вам еще сказали, что младшие линии порта опроса (PORTC) должны быть настроены на вход с подтяжкой. И посмотрите, как у вас.

Dimon456 писал(а): DDRC = 0x00;
   PORTC = 0xFF;

Re: Опрос матричной клавиатуры.

Пт июл 22, 2022 18:28:51

metan, Dimon456, Спасибо. Пытаюсь поставить плюс но мне сообщают что менять карму ещё рано.

Добавлено after 1 hour 9 minutes 44 seconds:
Вроде всё получилось благодаря Вам.
Схема проекта.
Изображение

Код проекта:
Спойлер
Код:
#include <mega8.h>
#include <delay.h>
// Alphanumeric LCD Module functions
#asm
.equ __lcd_port = 0x18 ; PORTB
#endasm
#include <lcd.h>

char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};
char inputStateC[5] = {0x01, 0x02, 0x04, 0x08, 0x10};
char key;
int temp = 0;
char mass2[4][5] =
{
   {'1', '2', '3', '4', '5'},
   {'6', '7', '8', '9', '0'},
   {'A', 'B', 'C', 'D', 'E'},
   {'F', 'G', 'I', 'K', 'L'}

};
//отправка символа по usart`у
void USART_SendChar(unsigned char sym)
{
   while(!(UCSRA & (1 << UDRE)));
   UDR = sym;
}



interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
   char i, j;
   for(i = 0; i < 4; i++)
      {
      PORTD = portStateD[i];
      for(j = 0; j < 5; j++)
         {
         if(((PINC & inputStateC[j]) == 0))
            {
            while((PINC & inputStateC[j]) != inputStateC[j]) {};
            lcd_putchar(mass2[i][j]);
            key = (mass2[i][j]);
            temp = 1;
            }
         }
      }
}

void main(void)
{
   DDRC = 0x00;
   PORTC = 0xFF;

   DDRD = 0xF0;
   PORTD = 0xFF;

   //инициализация USART`a
   UBRRH = 0;
   UBRRL = 51; //скорость обмена 9600 бод при Fcpu = 8MГц
   UCSRB = (1 << TXEN); // разр передачи.
   UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0); //размер слова 8 разрядов

   ASSR = 0x00;
   TCCR2 = 0x0F;
   TCNT2 = 0x00;
   OCR2 = 0xC3;

   TIMSK = 0x80;

   lcd_init(16);
    PORTB.3=0;

#asm("sei")
   while(1)
      {
      //если зафиксировано нажатие,
      //отправить код кнопки в терминал
      if ((key) && (temp == 1))
         {
             DDRD |= 1<<2;
         USART_SendChar(key);

         temp = 0;
            delay_ms(200);
            DDRD &= ~(1<<2);
         }
      }
}

Если не трудно, проверьте пожалуйста, нет ли ошибок и недочётов.

;)

Re: Опрос матричной клавиатуры.

Пт июл 22, 2022 20:33:07

Начнем наверное, как уже выше подметили, с включения подтягивающих резисторов там где это необходимо
Спойлер
Код:
   PORTC = 0x0F;
   DDRC = 0x00;

   PORTD = 0xF0 | (1<<2) ;
   DDRD = 0xF0;
Переменная temp должна быть объявлена как volatile, так как изменяется в прерывании, да и не зачем ее int делать, то есть volatile char , если переменная будет принимать значение 0 и 1, то достаточно ее объявить как volatile bit
Код:
volatile bit temp = 0;
Какой смысл проверять key?
Код:
if ((key) && (temp == 1))
Вы с key дальше ни чего не делаете.
Достаточно проверить
Код:
if (temp == 1)
У вас массив mass2 объявлен как тип char, соответственно функция USART_SendChar() должна так же принимать тип char
Код:
void USART_SendChar(char sym)
С MAX487 я не работал, не знаю как правильно, подскажут другие.

Re: Опрос матричной клавиатуры.

Ср июл 27, 2022 15:25:37

Всё что смог на данный момент:
Изображение

Спойлер
Код:
#include <mega8.h>
#include <delay.h>

// Alphanumeric LCD Module functions
#asm
.equ __lcd_port = 0x18 ; PORTB
#endasm
#include <lcd.h>

char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};
char inputStateC[5] = {0x01, 0x02, 0x04, 0x08, 0x10};
char key;
volatile bit temp = 0;

char mass2[4][5] = {
   {'1', '2', '3', '4', '5'},
   {'6', '7', '8', '9', '0'},
   {'A', 'B', 'C', 'D', 'E'},
   {'F', 'G', 'I', 'K', 'L'}

};
//отправка символа по usart`у
void USART_SendChar(char sym)
{
   while(!(UCSRA & (1 << UDRE)));
   UDR = sym;
}



interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
   char i, j;
   for(i = 0; i < 4; i++) {
      PORTD = portStateD[i];
      for(j = 0; j < 5; j++) {
         if(((PINC & inputStateC[j]) == 0)) {
            while((PINC & inputStateC[j]) != inputStateC[j]) {};

            key = (mass2[i][j]);

            switch(key) {
               case '1':  lcd_puts("TOT"); delay_ms(500); lcd_clear(); break;
               case '2':  lcd_puts("TIM"); delay_ms(500); lcd_clear(); break;
               case '3':  lcd_puts("DAY"); delay_ms(500); lcd_clear(); break;
               case '4':  lcd_puts("MTH"); delay_ms(500); lcd_clear(); break;
               case '5':  lcd_puts("RES"); delay_ms(500); lcd_clear(); break;
               case '6':  lcd_puts("COU"); delay_ms(500); lcd_clear(); break;
               case '7':  lcd_puts("1"); break;
               case '8':  lcd_puts("4"); break;
               case '9':  lcd_puts("7"); break;
               case '0':  lcd_puts("*"); delay_ms(500); lcd_clear(); break;
               case 'A':  lcd_puts("<"); delay_ms(500); lcd_clear(); break;
               case 'B':  lcd_puts("2"); break;
               case 'C':  lcd_puts("5"); break;
               case 'D':  lcd_puts("8"); break;
               case 'E':  lcd_puts("0"); break;
               case 'F':  lcd_puts(">"); delay_ms(500); lcd_clear(); break;
               case 'G':  lcd_puts("3"); break;
               case 'I':  lcd_puts("6"); break;
               case 'K':  lcd_puts("9"); break;
               case 'L':  lcd_puts(" OK"); break;
            }
            temp = 1;
         }
      }
   }
}

void main(void)
{
   PORTC = 0x0F;
   DDRC = 0x00;

   PORTD = 0xF0 | (1 << 2) ;
   DDRD = 0xF0;

   //инициализация USART`a
   UBRRH = 0;
   UBRRL = 51; //скорость обмена 9600 бод при Fcpu = 8MГц
   UCSRB = (1<<RXEN) | (1<<TXEN); // разр приём и передачи.
   UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0); //размер слова 8 разрядов

   ASSR = 0x00;
   TCCR2 = 0x0F;
   TCNT2 = 0x00;
   OCR2 = 0xC3;

   TIMSK = 0x80;

   lcd_init(16);
   PORTB.3 = 0;

#asm("sei")
   while(1) {
      //если зафиксировано нажатие,
      //отправить код кнопки в терминал
      if(temp == 1) {
         DDRD |= 1 << 2;
         USART_SendChar(key);
         temp = 0;
         delay_ms(200);
         DDRD &= ~(1 << 2);
         if((key == '5') || (key == 'L')) {
            delay_ms(500);
            lcd_clear();
         }
      }
   }
}
Вложения
key201_main.zip
(32.59 KiB) Скачиваний: 54

Re: Опрос матричной клавиатуры.

Ср июл 27, 2022 23:41:12

for(j = 0; j < 5; j++) можно переписать так, что inputStateC станет лишним, а значит, и тройное обращение к нему в условиях - тоже.

Re: Опрос матричной клавиатуры.

Чт июл 28, 2022 09:08:37

Martian писал(а):for(j = 0; j < 5; j++) можно переписать
Это конечно, так, но это пустяки по сравнению с конскими задержками внутри прерывания, как мне кажется :)
Я бы перенес проверку значения key внутрь главного цикла.

Re: Опрос матричной клавиатуры.

Сб июл 30, 2022 18:58:45

Пока только так смог:
Спойлер
Код:
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
   char i, j;
   for(i = 0; i < 4; i++) {
      PORTD = portStateD[i];
      for(j = 0; j < 5; j++) {
         if(((PINC & inputStateC[j]) == 0)) {
            while((PINC & inputStateC[j]) != inputStateC[j]) {};

            key = (mass2[i][j]);

            switch(key) {
               case '1': lcd_clear(); lcd_puts("TOT");   break;
               case '2': lcd_clear(); lcd_puts("TIM");   break;
               case '3': lcd_clear(); lcd_puts("DAY");   break;
               case '4': lcd_clear(); lcd_puts("MTH");   break;
               case '5': lcd_clear(); lcd_puts("RES");  break;
               case '6': lcd_clear(); lcd_puts("COU");   break;
               case '7':  lcd_puts("1"); break;
               case '8':  lcd_puts("4"); break;
               case '9':  lcd_puts("7"); break;
               case '0':  lcd_puts("*");   break;
               case 'A':  lcd_puts("<");   break;
               case 'B':  lcd_puts("2"); break;
               case 'C':  lcd_puts("5"); break;
               case 'D':  lcd_puts("8"); break;
               case 'E':  lcd_puts("0"); break;
               case 'F':  lcd_puts(">");   break;
               case 'G':  lcd_puts("3"); break;
               case 'I':  lcd_puts("6"); break;
               case 'K':  lcd_puts("9"); break;
               case 'L': lcd_clear(); lcd_puts(" OK"); break;
            }
            temp = 1;
         }
      }
   }
}

Re: Опрос матричной клавиатуры.

Чт авг 04, 2022 10:08:49

azerhud, вот такой код, поиграйся
Спойлер
Код:
#include <mega8.h>
#include <delay.h>

// Alphanumeric LCD Module functions
#asm
.equ __lcd_port = 0x18 ; PORTB
#endasm
#include <lcd.h>

char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};
char inputStateC[4] = {0x01, 0x02, 0x04, 0x08};

char mass2[4][4] = {{'1', '2', '3', '4'},
   {'5', '6', '7', '8'},
   {'9', 'A', 'B', 'C'},
   {'D', 'E', 'F', 'D'}
};

//отправка символа по usart`у
void USART_SendChar(char sym)
{
   while(!(UCSRA & (1 << UDRE)));
   UDR = sym;
}

#include <string.h>

#define MAX_DMA_BUFFERS_COUNT 16     // 4 8 16 32 64 128
#define BUFFER_MASK (MAX_DMA_BUFFERS_COUNT-1)
volatile unsigned char BUFF_RX_BUF[MAX_DMA_BUFFERS_COUNT]={0};
volatile unsigned char DMA_WR_BUF = 0;
volatile unsigned char DMA_RD_BUF = 0;

// Timer 2 output compare interrupt service routine
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{   char key;
   
    char i,j;
    for(i=0; i<4; i++)
    {
       PORTD=portStateD[i];
       for(j=0; j<4; j++)
       {
          if(((PINC&inputStateC[j])==0))
          {
             while((PINC&inputStateC[j])!=inputStateC[j]){};
             key = (mass2[i][j]);
             
          DMA_WR_BUF++;
          DMA_WR_BUF &= BUFFER_MASK;
           
            BUFF_RX_BUF[DMA_WR_BUF] = key; 
       }                         
    } 
  }
}

void main(void)
{  char key_x;

   PORTC = 0x0F;
   DDRC = 0x00;

   PORTD = 0xF0 | (1 << 2) ;
   DDRD = 0xF0;

   //инициализация USART`a
   UBRRH = 0;
   UBRRL = 51; //скорость обмена 9600 бод при Fcpu = 8MГц
   UCSRB = (1<<RXEN) | (1<<TXEN); // разр приём и передачи.
   UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0); //размер слова 8 разрядов

   ASSR = 0x00;
   TCCR2 = 0x0F;
   TCNT2 = 0x00;
   OCR2 = 0xC3;

   TIMSK = 0x80;

   lcd_init(16);
   PORTB.3 = 0;
   
#asm("sei")

   while(1)
   {
      //если зафиксировано нажатие     
      while (DMA_RD_BUF != DMA_WR_BUF) {

            DMA_RD_BUF++;
       DMA_RD_BUF &= BUFFER_MASK;
      
            key_x = BUFF_RX_BUF[DMA_RD_BUF];

            switch(key_x) {
               case '1':  lcd_puts("TOT"); delay_ms(500); lcd_clear(); break;
               case '2':  lcd_puts("TIM"); delay_ms(500); lcd_clear(); break;
               case '3':  lcd_puts("DAY"); delay_ms(500); lcd_clear(); break;
               case '4':  lcd_puts("MTH"); delay_ms(500); lcd_clear(); break;
               case '5':  lcd_puts("RES"); delay_ms(500); lcd_clear(); break;
               case '6':  lcd_puts("COU"); delay_ms(500); lcd_clear(); break;
               case '7':  lcd_puts("1"); break;
               case '8':  lcd_puts("4"); break;
               case '9':  lcd_puts("7"); break;
               case '0':  lcd_puts("*"); delay_ms(500); lcd_clear(); break;
               case 'A':  lcd_puts("<"); delay_ms(500); lcd_clear(); break;
               case 'B':  lcd_puts("2"); break;
               case 'C':  lcd_puts("5"); break;
               case 'D':  lcd_puts("8"); break;
               case 'E':  lcd_puts("0"); break;
               case 'F':  lcd_puts(">"); delay_ms(500); lcd_clear(); break;
               case 'G':  lcd_puts("3"); break;
               case 'I':  lcd_puts("6"); break;
               case 'K':  lcd_puts("9"); break;
               case 'L':  lcd_puts(" OK"); break;
            }         

           DDRD |= 1 << 2;
           USART_SendChar(key_x);
           delay_ms(200);
           DDRD &= ~(1 << 2);
           if((key_x == '5') || (key_x == 'L')) {
            delay_ms(500);
            lcd_clear();
           }       
        }
       
   };       
         
}



Re: Опрос матричной клавиатуры.

Пт авг 12, 2022 20:59:32

вот такой код, поиграйся

Спасибо. Применил Ваш код.
Но боюсь вновь намудрил.
Спойлер
Код:
//*** Пример работы с USART интерфейсом микроконтроллеров AVR ***

#include <avr/io.h>
#include <avr/interrupt.h>

#define BAUDRATE 9600 // Скорость обмена данными
#define F_CPU 8000000UL // Рабочая частота контроллера
#define PAUSE PAUSE_ms(100);
#include <string.h>

#define MAX_DMA_BUFFERS_COUNT 16     // 4 8 16 32 64 128
#define BUFFER_MASK (MAX_DMA_BUFFERS_COUNT-1)
volatile unsigned char BUFF_RX_BUF[MAX_DMA_BUFFERS_COUNT] = {0};
volatile unsigned char DMA_WR_BUF = 0;
volatile unsigned char DMA_RD_BUF = 0;

unsigned char NUM = 0;
unsigned char count = 0;
unsigned char byte_receive = 0;
unsigned char i = 1;
char portStateD[4] = {0xEF, 0xDF, 0xBF, 0x7F};
char inputStateC[5] = {0x01, 0x02, 0x04, 0x08, 0x10};
char key;
volatile int temp = 0;

char mass2[4][5] =
{
   {'1', '2', '3', '4', '5'},
   {'6', '7', '8', '9', '0'},
   {'A', 'B', 'C', 'D', 'E'},
   {'F', 'G', 'I', 'K', 'L'}

};

// Функция задержки в мкс
void PAUSE_us(unsigned char time_us)
{
   register unsigned char i;

   for(i = 0; i < time_us; i++)
      {
      asm volatile(" PUSH  R0 ");
      asm volatile(" POP   R0 ");
      }
}

// Функция задержки в мс
void PAUSE_ms(unsigned int time_ms)
{
   register unsigned int i;

   for(i = 0; i < time_ms; i++)
      {
      PAUSE_us(250);
      PAUSE_us(250);
      PAUSE_us(250);
      PAUSE_us(250);
      }
}

#define RS PB2
#define EN PB3

// Функция передачи команды
void lcd_com(unsigned char p)
{
   PORTB &= ~(1 << RS); // RS = 0 (запись команд)
   PORTB |= (1 << EN); // EN = 1 (начало записи команды в LCD)
   PORTB &= 0x0F; PORTB |= (p & 0xF0); // старший нибл
   PAUSE_us(100);
   PORTB &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
   PAUSE_us(100);
   PORTB |= (1 << EN); // EN = 1 (начало записи команды в LCD)
   PORTB &= 0x0F; PORTB |= (p << 4); // младший нибл
   PAUSE_us(100);
   PORTB &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
   PAUSE_us(100);
}

// Функция передачи данных
void lcd_data(unsigned char p)
{
   PORTB |= (1 << RS) | (1 << EN); // RS = 1 (запись данных), EN - 1 (начало записи команды в LCD)
   PORTB &= 0x0F; PORTB |= (p & 0xF0); // старший нибл
   PAUSE_us(100);
   PORTB &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
   PAUSE_us(100);
   PORTB |= (1 << EN); // EN = 1 (начало записи команды в LCD)
   PORTB &= 0x0F; PORTB |= (p << 4); // младший нибл
   PAUSE_us(100);
   PORTB &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
   PAUSE_us(100);
}

// Функция инициализации LCD
void lcd_init(void)
{
   PAUSE_ms(50); // Ожидание готовности ЖК-модуля

   // Конфигурирование четырехразрядного режима
   PORTB |= (1 << PB5);
   PORTB &= ~(1 << PB4);

   // Активизация четырехразрядного режима
   PORTB |= (1 << EN);
   PORTB &= ~(1 << EN);
   PAUSE_ms(5);

   lcd_com(0x28); // шина 4 бит, LCD - 2 строки
   lcd_com(0x08); // полное выключение дисплея
   lcd_com(0x01); // очистка дисплея
   PAUSE_us(100);
   lcd_com(0x06); // сдвиг курсора вправо
   lcd_com(0x0C); // включение дисплея, курсор не видим
}

// Функция вывода строки на LCD
void lcd_string(unsigned char command, char *string)
{
   lcd_com(0x0C);
   lcd_com(command);
   while(*string != '\0')
      {
      lcd_data(*string);
      string++;
      }
}

// Функция передачи данных по USART
void uart_send(char data)
{
   while(!( UCSRA & (1 << UDRE)));   // Ожидаем когда очистится буфер передачи
   UDR = data; // Помещаем данные в буфер, начинаем передачу
}

// Функция передачи строки по USART
void str_uart_send(char *string)
{
   while(*string != '\0')
      {
      uart_send(*string);
      string++;
      }
}

// Функция приема данных по USART
int uart_receive(void)
{
   while(!(UCSRA & (1 << RXC))); // Ожидаем, когда данные будут получены
   return UDR; // Читаем данные из буфера и возвращаем их при выходе из подпрограммы
}

// Функция инициализации USART
void uart_init(void)
{
   // Параметры соединения: 8 бит данные, 1 стоповый бит, нет контроля четности
   // USART Приемник: Включен
   // USART Передатчик: Включен
   // USART Режим: Асинхронный
   // USART Скорость обмена: 9600

   UBRRL = (F_CPU / BAUDRATE / 16 - 1); // Вычисляем скорость обмена данными
   UBRRH = (F_CPU / BAUDRATE / 16 - 1) >> 8;

   UCSRB |= (1 << RXCIE) | // Разрешаем прерывание по завершению приема данных
          (1 << RXEN) | (1 << TXEN); // Включаем приемник и передатчик

   UCSRC |= (1 << URSEL) | // Для доступа к регистру UCSRC выставляем бит URSEL
          (1 << UCSZ1) | (1 << UCSZ0); // Размер посылки в кадре 8 бит
}

// Прерывание по окончанию приема данных по USART
ISR(USART_RXC_vect)
{
   NUM = UDR; // Принимаем символ по USART
   byte_receive = 1;
   uart_send(NUM); // Посылаем символ по USART


}

ISR(TIMER2_COMP_vect)
{
   char key;

   int i, j;
   for(i = 0; i < 4; i++)
      {
      PORTD = portStateD[i];
      for(j = 0; j < 5; j++)
         {
         if(((PINC & inputStateC[j]) == 0))
            {
            while((PINC & inputStateC[j]) != inputStateC[j]) {};
            key = (mass2[i][j]);

            DMA_WR_BUF++;
            DMA_WR_BUF &= BUFFER_MASK;

            BUFF_RX_BUF[DMA_WR_BUF] = key;
            }
         }
      }


   temp = 1;
}

// Главная функция
int main(void)
{
   char key_x;

   PORTC = 0x1F;
   DDRC = 0x00;

   PORTD = 0xF0 | (1 << 2) ;
   DDRD = 0xF0;
       
   DDRB  = 0b11111110;
   PORTB = 0x00;


   ASSR = 0x00;
   TCCR2 = 0x0F;
   TCNT2 = 0x00;
   OCR2 = 0xC3;

   TIMSK = 0x80;

   lcd_init(); // Инициализация LCD
   uart_init(); // Инициализация USART

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

   str_uart_send("Initialization system\r\n"); // Передаем строку по USART
   lcd_string(0x80, " AVR USART TEST "); // Выводим строку на LCD
   PAUSE_ms(2500);
   lcd_com(0x01); // Очищаем LCD

   while(1)
      {

      while (DMA_RD_BUF != DMA_WR_BUF)
         {

         DMA_RD_BUF++;
         DMA_RD_BUF &= BUFFER_MASK;

         key_x = BUFF_RX_BUF[DMA_RD_BUF];

         switch(key_x)
            {
            case '1':  str_uart_send( "1"); lcd_string(0x80, "TOT"); PAUSE_ms(500); lcd_com(0x01);  break;
            case '2':  str_uart_send( "2");  lcd_string(0x80, "TIM"); PAUSE_ms(500); lcd_com(0x01);  break;
            case '3':  str_uart_send( "3"); lcd_string(0x80, "DAY"); PAUSE_ms(500); lcd_com(0x01);  break;
            case '4':  str_uart_send( "4");  lcd_string(0x80, "MTH"); PAUSE_ms(500); lcd_com(0x01);  break;
            case '5':  str_uart_send( "5");  lcd_string(0x80, "RES"); PAUSE_ms(500); lcd_com(0x01);  break;
            case '6':  str_uart_send( "6");  lcd_string(0x80, "COU"); PAUSE_ms(500); lcd_com(0x01);  break;
            case '7':  str_uart_send( "7"); lcd_string(0x80, "1"); PAUSE_ms(500); break;
            case '8':  str_uart_send( "8"); lcd_string(0x80, "4"); PAUSE_ms(500); break;
            case '9':  str_uart_send( "9"); lcd_string(0x80, "7"); PAUSE_ms(500); break;
            case '0':  str_uart_send( "0"); lcd_string(0x80, "*"); PAUSE_ms(500);  PAUSE_ms(500); lcd_com(0x01);  break;
            case 'A':  str_uart_send( "A");  lcd_string(0x80, "<"); PAUSE_ms(500); PAUSE_ms(500); lcd_com(0x01);  break;
            case 'B':  str_uart_send( "B"); lcd_string(0x80, "2"); PAUSE_ms(500); break;
            case 'C':  str_uart_send( "C"); lcd_string(0x80, "5"); PAUSE_ms(500); break;
            case 'D':  str_uart_send( "D"); lcd_string(0x80, "8"); PAUSE_ms(500); break;
            case 'E':  str_uart_send( "E"); lcd_string(0x80, "0"); PAUSE_ms(500); break;
            case 'F':  str_uart_send( "F");  lcd_string(0x80, ">"); PAUSE_ms(500);  PAUSE_ms(500); lcd_com(0x01);  break;
            case 'G':  str_uart_send( "G"); lcd_string(0x80, "3"); PAUSE_ms(500); break;
            case 'I':  str_uart_send( "I"); lcd_string(0x80, "6"); PAUSE_ms(500); break;
            case 'K':  str_uart_send( "K"); lcd_string(0x80, "9"); PAUSE_ms(500); break;
            case 'L':  str_uart_send( "L"); lcd_string(0x80, " OK"); PAUSE_ms(500); PAUSE_ms(500); lcd_com(0x01);  break;

            }


         if(byte_receive)
            {
            byte_receive = 0;
            count++;
            //USART_SendChar(key_x);
            lcd_data(NUM); // Выводим символ на LCD
            if(count > 16) // Если строка заполнена
               {
               count = 0;
               lcd_com(0x01); // Очищаем LCD
               }
            }
         }
      }
}

Re: Опрос матричной клавиатуры.

Пт авг 12, 2022 21:56:00

azerhud писал(а):Но боюсь вновь намудрил.
Да уж, намудрили так намудрили.
Особенно Функцию задержки, откуда вы это только берете?
У avr-gcc и так нормальный delay.
Ответить