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

Запись значения нажатой кнопки в массив

Пт окт 13, 2023 08:22:16

Здравствуйте. Есть код опроса матричной клавиатуры. Работает отлично. Но в нем нажатая кнопка отправляется по символьно через UART. У меня же задача записать каждый символ в массив и считать этот массив в переменную в виде числа. Но как это сделать, не пойму. В интернете много тем с таким же вопросом но решение не нашёл.

Сам код опроса матричной клавиатуры:
СпойлерФАЙЛ MAIN.C
Код:
//***************************************************************************
//
//  Author(s)...: Pashgan    http://ChipEnable.Ru   
//
//  Target(s)...: ATMega8
//
//  Compiler....: GNU GCC
//
//  Description.: Опрос матричной клавиатуры. Использование конечного автомата.
//
//  Data........: 06.03.10
//
//***************************************************************************
#include <avr/io.h>
#include <avr/interrupt.h>
#include "keyboard.h"

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

//прерывание таймера Т0 - опрос клавиатуры
ISR(TIMER0_OVF_vect)
{
   TCNT0 = 0x83;
   ScanKeyboard();   
}

int main( void )
{
  unsigned char key;
 
  //инициализация USART`a
  UBRRH = 0;
  UBRRL = 51; //скорость обмена 9600 бод при Fcpu = 8MГц
  UCSRB = (1<<TXEN); // разр передачи.
  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); //размер слова 8 разрядов
 
  //инициализация таймера Т0
  TIMSK = (1<<TOIE0); //разрешение прерывания по переполнению
  TCCR0 = (1<<CS02)|(0<<CS01)|(0<<CS00); //предделитель 256
  TCNT0 = 0x83; //прерывания каждые 4 мс
 
  //инициализация портов и переменных
  InitKeyboard();
  sei();
 
  while(1){
    //если зафиксировано нажатие,
    //отправить код кнопки в терминал
    key = GetKey();
    if (key)
      USART_SendChar(key);
  }
  return 0;
}




ФАЙЛ KEYBOARD.H
Код:
//***************************************************************************
//
//  Author(s)...: Pashgan    http://ChipEnable.Ru   
//
//  Target(s)...: ATMega8
//
//  Compiler....: GNU GCC
//
//  Description.: Опрос матричной клавиатуры. Использование конечного автомата.
//
//  Data........: 06.03.10
//
//***************************************************************************
#ifndef KEYBOARD_H
#define KEYBOARD_H

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


//инициализация портов и внутренних переменных
void InitKeyboard(void);

//сканирование клавиатуры
void ScanKeyboard(void);

//возвращает код нажатой кнопки
unsigned char GetKey(void);

#endif //KEYBOARD_H


ФАЙЛ KEYBOARD.C
Код:
#include "keyboard.h"

//хранит текущее состояние автомата
unsigned char keyState;
//хранит код нажатой кнопки
unsigned char keyCode;
//хранит символьное значение нажатой кнопки
unsigned char keyValue;
//флаговая переменная - устанавливается, если кнопка удерживается
unsigned char keyDown;
//флаговая переменная -  устанавливается, когда нажата новая кнопка
unsigned char keyNew;

//таблица перекодировки
PROGMEM unsigned char keyTable[][2] = {
{ 0x11, '1'},
{ 0x12, '2'},
{ 0x14, '3'},
{ 0x21, '4'},
{ 0x22, '5'},
{ 0x24, '6'},
{ 0x41, '7'},
{ 0x42, '8'},
{ 0x44, '9'},
{ 0x81, '*'},
{ 0x82, '0'},
{ 0x84, '#'}
};

//прототипы функций используемых автоматом
unsigned char AnyKey(void);
unsigned char SameKey(void);
void ScanKey(void);
unsigned char FindKey(void);
void ClearKey(void);

//инициализация портов, обнуление переменных
void InitKeyboard(void)
{
  DDRD |= 0xf0;
  PORTD &= 0x0f;
  DDRC &= ~0x07;
  PORTC &= ~0x07;
 
  keyState = 0;
  keyCode = 0;
  keyValue = 0;
  keyDown = 0;
  keyNew = 0;
}

//автомат реализующий опрос клавиатуры, защиту от дребезга
// и распознование нажатой кнопки
void ScanKeyboard(void)
{
   switch (keyState){
     case 0:
       if (AnyKey()) {
         ScanKey();
         keyState = 1;
       }
       break;

     case 1:
       if (SameKey()) {
           FindKey();
           keyState = 2;
       }
       else keyState = 0;
       break;
     
     case 2:
        if (SameKey()){}
        else keyState = 3;
        break;
   
     case 3:
       if (SameKey()) {
         keyState = 2;
       }
       else {
         ClearKey();
         keyState = 0;
       }
       break;
     
     default:
        break;
   }
   
}

//возвращает true если какая-нибудь кнопка нажата
unsigned char AnyKey(void)
{
  PORTD |= 0xf0;
  return (PINC & 0x07);
}

// возвращает true если удерживается та же кнопка
//что и в предыдущем цикле опроса
unsigned char SameKey(void)
{
  PORTD = (PORTD & 0x0f) | ( keyCode & 0xf0);
  return ((PINC & keyCode) & 0x07);
}

//Генерирует нужные сигналы на линиях
//считывает код нажатой кнопки
void ScanKey(void)
{
  unsigned char activeRow = (1<<4);
  while (activeRow) {
    PORTD = (PORTD & 0x0f)|activeRow;
    if (PINC & 0x07) {
      keyCode = (PINC & 0x07);
      keyCode |= (PORTD & 0xf0);
    }
    activeRow <<= 1;
  }
}

// преобразует код кнопки в соответствующий символ
// устанавивает флаги
unsigned char FindKey(void)
{
  unsigned char index;
  for (index = 0; index < 12; index++) {
    if (pgm_read_byte(&keyTable [index][0]) == keyCode) {
      keyValue = pgm_read_byte(&keyTable [index][1]);
      keyDown = 1;
      keyNew = 1;
      return 1;
    }
  }
  return 0;
}

//сбрасывает флаг
void ClearKey(void)
{
  keyDown = 0;
}

//если зафиксировано нажатие кнопки
//возвращает ее код
unsigned char GetKey(void)
{
  if (keyNew){
    keyNew = 0;
    return keyValue;
  }
  else
    return 0;
}


Надеюсь что найдётся человек готовый помочь и объяснить что и как не только для меня но и для множества юзеров вроде меня ищущих решения этой задачи :)

Re: Запись значения нажатой кнопки в массив

Пт окт 13, 2023 11:32:36

У меня же задача записать каждый символ в массив и считать этот массив в переменную в виде числа.


Массив каких размеров? Переменная какого типа?

Re: Запись значения нажатой кнопки в массив

Пт окт 13, 2023 11:48:00

Код:
union
{
   unsigned char arr[8];
   unsigned long long chislo;
}keys;

Re: Запись значения нажатой кнопки в массив

Пт окт 13, 2023 16:10:31

Поражаюсь таким вопросам.
Человек смог передать данные по UART, но не может записать данные в переменную (массив). Как такое может быть вообще ?

Re: Запись значения нажатой кнопки в массив

Пт окт 13, 2023 16:13:32

Аlex, дык может не он написал, unsigned char FindKey(void) на это очень толсто намекает

Re: Запись значения нажатой кнопки в массив

Сб окт 14, 2023 19:34:01

Код писал не я, в заголовке указан источник.
Код:
//  Author(s)...: Pashgan    http://ChipEnable.Ru

В массиве будет 4 числа.
переменная типа int.
По логике, при нажатии кнопки первый символ должен записаться в массив, при нажатии второй кнопки нужно проверить свободен ли нулевой адрес массива, если нет то прибавляем единицы к нулевому адресу и записываем значение кнопки в массив по адресу 1. Таки образом нужно записать последующие символы. После того как массив заполнен передаём все символы массива в переменную за одно преобразовав символы в цифры.
Но как это всё реализовать в виде кода никак не соображу.

Re: Запись значения нажатой кнопки в массив

Сб окт 14, 2023 19:57:31

Основная переработка чужого программного кода на самом деле представляет собой напр. "тройную работу":
1. Найти подходящий код, который в некоторой степени выполняет данную работу
2. Разобраться (с головой автора) в принципе работы/используемый алгоритм
3. Внести изменения и дополнения для использования в собств. задании
4. Тестирование и исправлений модифицированного кода на реальном устройстве
3-4-3-4 несколько раз, иногда - переход на 1 ...

Зачастую проще написать собственный код: разбиваете задачи на части, пишете код для каждой части, объединяете их, устраняете несоответствия - и готово. Начните с простого: блок-схемы. Если не графически, то хотя бы четко описан устно/писменно алгоритм. Портирование в среду программирования потом будет простым. (частично пользуюсь переводчиком бг->ру)

Re: Запись значения нажатой кнопки в массив

Сб окт 14, 2023 20:06:34

Но как это всё реализовать в виде кода никак не соображу.

Я тоже. Непонятно, что за символы пишутся в массив, как они преобразуются в цифры, как проверить свободу нулевого адреса в массиве... Что значит "нажатии кнопки" и "нажатии второй кнопки", а если первая будет нажата второй раз, это всё ещё первое нажатие или нажатие второй кнопки, хотя она - первая?

veso74 совершенно прав. Опишите всю желаемую программу в виде блок-схемы. Затем, совместно с книжкой по программированию, попытайтесь самостоятельно перевести в код. И вот если начнутся трудности, тогда имеет смысл обращаться за помощью.
Если же Вы не собираетесь становиться программистом даже на любительском уровне, нужно просто решение, тогда описывайте полное и подробное техническое задание, понимающееся однозначно и не вызывающее вопросы, которые я задал выше.

Re: Запись значения нажатой кнопки в массив

Вс окт 15, 2023 17:17:04

Внёс следующие изменения в код:
Код:

int main( void )
{
  unsigned char key;
  char buttons[4]; // массив нажатых кнопок
  int k = 0; // счетчик нажатий
  int j;

...............
...............
...............
  while(1){
    //если зафиксировано нажатие,

    key = GetKey();
    if ((key)&&(key!= '*')){

     buttons[k] = key; // сохраняем значение кнопки в массиве
     k = k + 1; // увеличиваем счётчик нажатий на 1
      }
      else if(key == '*')
      {
      for(j=0; j<4; j++){
      USART_SendChar(buttons[j]); //отправить код кнопки в терминал
      }}
  }
  return 0;
}


При нажатии на * в терминал отправляется значения нажатых кнопок 1111 при нажатии четыре раза на 1 и 1234 при нажатии на 1234, но при отправке символов меньше четырёх получаю 1^] при отправке 1,
12] при отправке 1 и 2, 123] при отправке 1,2 и 3 можно ли это каким то образом исправить?

Re: Запись значения нажатой кнопки в массив

Вс окт 15, 2023 17:53:43

попробуйте
Код:
for(j=0; j<4; j++) ...

на
Код:
for(j=0; j<k; j++) ...

Re: Запись значения нажатой кнопки в массив

Вс окт 15, 2023 17:57:06

попробуйте
Код:
for(j=0; j<4; j++) ...

на
Код:
for(j=0; j<k; j++) ...


Спасибо. Сработало.

Re: Запись значения нажатой кнопки в массив

Вс окт 15, 2023 18:45:16

а если пятый раз нажать, что будет со счётчиком и последующей адресацией к массиву? стоит проверить, что счётчик не превышает размерность массива, или изначально не допустить превышения.

Re: Запись значения нажатой кнопки в массив

Вс окт 15, 2023 19:11:13

а если пятый раз нажать, что будет со счётчиком и последующей адресацией к массиву? стоит проверить, что счётчик не превышает размерность массива, или изначально не допустить превышения.

Да, столкнулся с проблемой описанный Вами.
Решил таким образом:
Спойлер
Код:
//***************************************************************************
//
//  Author(s)...: Pashgan    http://ChipEnable.Ru
//
//  Target(s)...: ATMega8
//
//  Compiler....: GNU GCC
//
//  Description.: Опрос матричной клавиатуры. Использование конечного автомата.
//
//  Data........: 06.03.10
//
//***************************************************************************
#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
#include "keyboard.h"
#include <util/delay.h>

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

//прерывание таймера Т0 - опрос клавиатуры
ISR(TIMER0_OVF_vect)
{
    TCNT0 = 0x83;
    ScanKeyboard();
}

int main( void )
{
    unsigned char key;
    char buttons[4]; // массив нажатых кнопок
    int k = 0; // счетчик нажатий
    int j;

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

    //инициализация таймера Т0
    TIMSK = (1<<TOIE0); //разрешение прерывания по переполнению
    TCCR0 = (1<<CS02)|(0<<CS01)|(0<<CS00); //предделитель 256
    TCNT0 = 0x83; //прерывания каждые 4 мс

    //инициализация портов и переменных
    InitKeyboard();
    sei();

    while(1)
        {

            key = GetKey(); //если зафиксировано нажатие,
            if ((key)&&(key!= '*')&&(key != '#'))
                {
                    buttons[k] = key; // сохраняем значение кнопки в массиве
                    k = k + 1; // увеличиваем счётчик нажатий на 1
                }
            else if(key == '*')
                {
                    for(j=0; j<k; ++j)
                        {
                            if(k>5)k=0;

                            USART_SendChar(buttons[j]); //отправить код кнопки в терминал
                        }
                    memset(buttons, '\0', sizeof(buttons) / sizeof(buttons[0]));
                }
            else if(key == '#')
                {
                    memset(buttons, '\0', sizeof(buttons) / sizeof(buttons[0]));
                }
        }
    return 0;
}

Re: Запись значения нажатой кнопки в массив

Вс окт 15, 2023 19:31:19

это половинчатое решение, для случая key = '*'
проверку надо делать либо в момент увеличения счётчика, например:
Код:
if (k < 3)
{
   k++; // увеличиваем счётчик нажатий на 1
}
else
{
// делаем что-то в случае переполнения счётчика, например, обнуляем его
}

или перед обращением к массиву:
Код:
if (k < 4)
{
    buttons[k] = key; // сохраняем значение кнопки в массиве
}
else
{
// делаем что-то в случае выхода за границы массива
}

ну или комбинируя:
Код:
if (k > 3)
{
    // делаем что-то в случае выхода за границы массива
}
else
{
   buttons[k++] = key; // сохраняем значение кнопки в массиве и затем увеличиваем счётчик нажатий на 1
}


Код:
++
это оператор инкремента. (декремент, соответственно --). Если написать k++, то сначала будет взято старое значение k, затем увеличено на 1. Если написать ++k, то сначала будет увеличено значение k.
То есть, если k = 0, то buttons[k++] будет выглядеть так:
Код:
buttons[0]
k=k+1

а buttons[++k] так:
Код:
k=k+1
buttons[1]

Re: Запись значения нажатой кнопки в массив

Пн окт 16, 2023 13:57:40

Немного подправил по свету Martian,
Код:
while(1)
        {

            key = GetKey(); //если зафиксировано нажатие,


            if ((key)&&(key!='*'))
                {
                    buttons[k] = key; // сохраняем значение кнопки в массиве
                    k = k + 1; // увеличиваем счётчик нажатий на 1
                }
            if(key == '*')
                {
                    if(k<5)
                        {
                            for(j=0; j<k; j++)
                                {
                                    USART_SendChar(buttons[j]); //отправить код кнопки в терминал
                                }

                            memset(buttons, '\0', sizeof(buttons) / sizeof(buttons[0])); //очистить массив
                            k=0; //сбросить счётчик нажатий
                        }
                    else // если в массиве больше 4 символов
                        {
                            memset(buttons, '\0', sizeof(buttons) / sizeof(buttons[0])); //очистить массив
                            k=0;//сбросить счётчик нажатий
                        }
                }
        }

    return 0;
}

Re: Запись значения нажатой кнопки в массив

Пн окт 16, 2023 14:11:47

неправильно.
если пятым нажатием будет какая-то кнопка не "*", будет ошибка.
и будет ошибка при k = 4, так как if(k<5) это значение пропустит, но 4 - это пятый элемент, а массив всего из четырёх. В общем, всё, что писал выше - напрасно...

Re: Запись значения нажатой кнопки в массив

Пн окт 16, 2023 15:31:51

неправильно.
если пятым нажатием будет какая-то кнопка не "*", будет ошибка.
и будет ошибка при k = 4, так как if(k<5) это значение пропустит, но 4 - это пятый элемент, а массив всего из четырёх. В общем, всё, что писал выше - напрасно...

В том то и проблема. Если пишу if(k<4) то у меня отправляются 3 символа а при наборе четырёх символов идёт сброс. а при if(k<5) всё работает.

Re: Запись значения нажатой кнопки в массив

Пн окт 16, 2023 15:35:59

да, верно, это уже я ошибся, что там получается два раза меньше... и это путает.

Re: Запись значения нажатой кнопки в массив

Пн окт 16, 2023 15:42:39

А по моему, совсем необязательно такую фигню писать на форум. Это же азы - и этому нужно учиться самому. А не так что сделайте мне вот это. Я бы даже постеснялся бы (когда был маленьким)...

Re: Запись значения нажатой кнопки в массив

Пн окт 16, 2023 15:50:50

OKF, ну, может, глядя на примеры, что-то стронется в голове.
Код:
while(1)
{
     key = GetKey(); //если зафиксировано нажатие,
 
      if (key)
      {
          if (k > 3)
          {
               k=0; //сбросить счётчик нажатий
          }
          if (key!='*')
          {
              buttons[k++] = key; // сохраняем значение кнопки в массиве и увеличиваем счётчик нажатий на 1
          }
          else
          {
             for(j=0; j<k; j++)
             {
                  USART_SendChar(buttons[j]); //отправить код кнопки в терминал
             }
          }
      }
}
Ответить