Помогите криворукому начинающему ;(

Тема в разделе "Arduino & Shields", создана пользователем ИванL, 27 дек 2017.

  1. ИванL

    ИванL Нуб

    Имеется у меня Iskra Neo, мембранная клавиатура 4х4 и дисплей на ST7920. Захотелось мне сделать простенький калькулятор. Насмотревшись всякого разного, понял, что стоит использовать для сего чудного дисплея использовать библиотеку U8glib. Вооружившись своим стандартным набором (паяльник, слабоумие и отвага) все подключил. Осталось дело, как казалось, за малым - скетчем. Изучив всемирную паутину, я понял, что так и не смог найти примера калькулятора с использованием библиотеки u8glib. Найдя пример обычного калькулятора с дисплеем 16х2, попытался переиначить его под свои нужды:
    Код (C++):
    #include <U8glib.h>
    #include <Keypad.h>
    U8GLIB_ST7920_128X64 u8g(10, 11, 12, U8G_PIN_NONE); // настройка пинов
    long num1,num2 ;
    double total;
    char operation,button;

    const byte ROWS = 4;
    const byte COLS = 4;

    char keys[ROWS][COLS] = {
      {'1','2','3','+'},
      {'4','5','6','-'},
      {'7','8','9','*'},
      {'C','0','=','/'}
    };
    byte rowPins[ROWS] = {0,1,2,3}; // подключение к строкам клавиатуры
    byte colPins[COLS] = {4,5,6,7};     // подключение к столбцам клавиатуры
    Keypad customKeypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);

    // Этот код выполняется только один раз: при включении платы
    void setup()
    {
       u8g.setFont(u8g_font_6x10); // Выбор шрифта

    }

    void loop()
    {
      sprintf(num1, "%d",num2); // функция sprintf переведёт число в строковый массив
     
      // Циклы удобны для чтения нажатых кнопок клавиатуры
      while(1)
      {
        // Первый цикл. Здесь мы читаем клавиатуру и составляем наше первое число.
      // Он выполняется, пока мы не нажмем кнопку оператора, и цикл прервется,
      // или, если будет нажата кнопка 'C', всё начнется с начала.
           
        button = customKeypad.getKey(); // Чтение кнопки
        if (button=='C') // Если пользователь хочет сбросить набор первого числа
        {
          num1=0;
          num2=0;
          total=0;
          operation=0;
       
        }
           
        if (button >='0' && button <='9') // Если пользователь нажал на числовое значение, один символ за раз
        {
          num1 = num1*10 + (button -'0');
          // Наши числовые значения лежат в диапазоне от 0 до 9, что означает, что это единицы.
          // Когда мы умножаем на 10, мы, по сути, добавляем 0 после числа.
          // Затем мы добавляем новое введенное число на место нуля.
          // Что касается (button -'0'), это простой трюк с таблице ASCII. Цифры 0...9 в таблице ASCII
          // это 48...57 (в десятичном виде), поэтому, вычитание '0' из любого из этих символов дает
          // соответствующее значение в десятичном виде. Например, символ '5' = 53 в десятичной системе
          // минус 48 (символ нуля) дает нам значение 5.
          // Если наше предыдущее число было, например, 25, мы получили 250 умножением его на 10,
          // а затем добавили 5, и получили 255, что и будет выведено на U8G.
          do
       {
          u8g.setPrintPos(0,10); // Выбор первой строки на U8G
          u8g.print(num1);    // Печать текущего значения числа num1
          }
       
      while(u8g.nextPage());
        }
       
      if (num1 !=0 && (button=='-' || button=='+' || button=='*' || button=='/'))
        {
          // Если пользователь завершил ввод цифр
          operation = button;   // запоминаем, какое математическое действие пользователь хочет выполнить
         do {
          u8g.setPrintPos(0,20);   // установить курсор на строку 2
          u8g.print(operation); // напечатать наш оператор
          }
       
      while(u8g.nextPage());
          break;
        }

      }
       
      while(1)
      {
        // Второй цикл, он выполняется пока пользователь не нажмет '=' или 'C'.
        // И тогда будет выведен результат или сброшена программа.
        if (button =='C')
          break; // Это обрабатывает случай, когда пользователь нажал кнопку оператора и захотел сбросить
        button = customKeypad.getKey();
        if (button=='C') // Еще раз проверяем, не хочет ли пользователь сбросить
        {
          num1=0;
          num2=0;
          total=0;
          operation=0;
         
          break;
        }
        if (button >='0' && button <='9') // Получение символов от клавиатуры для числа 2
        {
          num2 = num2*10 + (button -'0');
          do {
          u8g.setPrintPos(10,10);
          u8g.print(num2);
          }
       
      while(u8g.nextPage());
          }
        }
        if (button == '=' && num2 !=0)
        { // Если нажата кнопка '=', то это конец пути. Вызываем функцию domath(), выполняющую расчет
          // и выводим результат.    
          domath();            
          break;
        }
      }
       
      while(1)
      {
        // Когда всё выполнено, этот цикл ждет нажатия кнопки 'C', чтобы сбросить программу и начать с начала.
         
        // Это побочный эффект от предыдущего цикла, когда пользователь нажал 'C', предыдущий цикл прерывается
        // и переходит сюда. Поэтому мы должны также прервать и текущий цикл, иначе пользователю придется
        // нажимать 'C' дважды.    
        if (button =='C')
          break;

        button = customKeypad.getKey();
        if (button =='C')
        {    
          u8g.setPrintPos(0,0);
          num1=0;
          num2=0;
          total=0;
          operation=0;
          break;
        }
      }

    }


    void domath()
    {
      switch(operation)
      {
        case '+': // Сложение
          total = num1+num2;
          break;
         
        case '-': // Вычитание
          total = num1-num2;
          break;
         
        case '/': // Деление
          // Может добавить ошибку деления на ноль, или измените строку во втором цикле,
          // где тот ожидает символа '=' на if (button == '=' && num2 != 0), это остановит программу
          // от дальнейших действий, пока num2 не будет отличаться от нуля.
          total = (float)num1/(float)num2;
          break;
         
        case '*': // Умножение
          total = num1*num2;
          break;
             
      }
        do {
      u8g.setPrintPos(0,10);
      u8g.print('=');
      u8g.setPrintPos(10,10);
      u8g.print(total);
        }
       
      while(u8g.nextPage());    
    }
     
    Прошу помочь и палками не бить!
     
  2. b707

    b707 Гуру

    В вопросе нет главного - собственно вопроса. Если скетч работает неправильно - ПОДРОБНО опишите ошибки
     
  3. ИванL

    ИванL Нуб

    Согласен, как-то о самом вопросе я ничего толком не разъяснил. Вышеизложенный скетч не проходит компиляцию. Выходит ошибка: "C:\Users\CD86~1\AppData\Local\Temp\untitled1662855145.tmp\sketch_dec24a\sketch_dec24a.ino: In function 'void loop()':

    sketch_dec24a:115: error: 'domath' was not declared in this scope

    domath();

    ^

    sketch_dec24a:116: error: break statement not within loop or switch

    break;

    ^

    C:\Users\CD86~1\AppData\Local\Temp\untitled1662855145.tmp\sketch_dec24a\sketch_dec24a.ino: At global scope:

    sketch_dec24a:120: error: expected unqualified-id before 'while'

    while(1)

    ^

    exit status 1
    'domath' was not declared in this scope"
    До того, как я добавил
    Код (C++):
    do {
    }
       
      while(u8g.nextPage());    
    В местах, где что-либо должно выводиться на дисплей, скетч проходил компиляцию, загружался в плату, но дисплей ничего не выводил. До изменений скетч выглядел так:
    Код (C++):
    #include <U8glib.h>
    #include <Keypad.h>
    U8GLIB_ST7920_128X64 u8g(10, 11, 12, U8G_PIN_NONE); // настройка пинов

    long num1,num2 ;
    double total;
    char operation,button;

    const byte ROWS = 4;
    const byte COLS = 4;

    char keys[ROWS][COLS] = {
      {'1','2','3','+'},
      {'4','5','6','-'},
      {'7','8','9','*'},
      {'C','0','=','/'}
    };
    byte rowPins[ROWS] = {A2,A3,A4,A5}; // подключение к строкам клавиатуры
    byte colPins[COLS] = {2,3,4,5};     // подключение к столбцам клавиатуры
    Keypad customKeypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);

    // Этот код выполняется только один раз: при включении платы
    void setup()
    {
      u8g.setFont(u8g_font_6x10); // Выбор шрифта
    }

    void loop()
    {
     
      // Циклы удобны для чтения нажатых кнопок клавиатуры
      while(1)
      {
        // Первый цикл. Здесь мы читаем клавиатуру и составляем наше первое число.
      // Он выполняется, пока мы не нажмем кнопку оператора, и цикл прервется,
      // или, если будет нажата кнопка 'C', всё начнется с начала.
           
        button = customKeypad.getKey(); // Чтение кнопки
        if (button=='C') // Если пользователь хочет сбросить набор первого числа
        {
          num1=0;
          num2=0;
          total=0;
          operation=0;
        }
           
        if (button >='0' && button <='9') // Если пользователь нажал на числовое значение, один символ за раз
        {
          num1 = num1*10 + (button -'0');
          // Наши числовые значения лежат в диапазоне от 0 до 9, что означает, что это единицы.
          // Когда мы умножаем на 10, мы, по сути, добавляем 0 после числа.
          // Затем мы добавляем новое введенное число на место нуля.
          // Что касается (button -'0'), это простой трюк с таблице ASCII. Цифры 0...9 в таблице ASCII
          // это 48...57 (в десятичном виде), поэтому, вычитание '0' из любого из этих символов дает
          // соответствующее значение в десятичном виде. Например, символ '5' = 53 в десятичной системе
          // минус 48 (символ нуля) дает нам значение 5.
          // Если наше предыдущее число было, например, 25, мы получили 250 умножением его на 10,
          // а затем добавили 5, и получили 255, что и будет выведено на U8G.
          u8g.setPrintPos(0,0); // Выбор первой строки на U8G
          u8g.print(num1);    // Печать текущего значения числа num1
        }
       
      if (num1 !=0 && (button=='-' || button=='+' || button=='*' || button=='/'))
        {
          // Если пользователь завершил ввод цифр
          operation = button;   // запоминаем, какое математическое действие пользователь хочет выполнить
          u8g.setPrintPos(0,1);   // установить курсор на строку 2
          u8g.print(operation); // напечатать наш оператор
          break;
        }

      }
       
      while(1)
      {
        // Второй цикл, он выполняется пока пользователь не нажмет '=' или 'C'.
        // И тогда будет выведен результат или сброшена программа.
        if (button =='C')
          break; // Это обрабатывает случай, когда пользователь нажал кнопку оператора и захотел сбросить
        button = customKeypad.getKey();
        if (button=='C') // Еще раз проверяем, не хочет ли пользователь сбросить
        {
          num1=0;
          num2=0;
          total=0;
          operation=0;

          break;
        }
        if (button >='0' && button <='9') // Получение символов от клавиатуры для числа 2
        {
          num2 = num2*10 + (button -'0');
          u8g.setPrintPos(1,1);
          u8g.print(num2);
        }
        if (button == '=' && num2 !=0)
        { // Если нажата кнопка '=', то это конец пути. Вызываем функцию domath(), выполняющую расчет
          // и выводим результат.    
          domath();            
          break;
        }
      }
       
      while(1)
      {
        // Когда всё выполнено, этот цикл ждет нажатия кнопки 'C', чтобы сбросить программу и начать с начала.
         
        // Это побочный эффект от предыдущего цикла, когда пользователь нажал 'C', предыдущий цикл прерывается
        // и переходит сюда. Поэтому мы должны также прервать и текущий цикл, иначе пользователю придется
        // нажимать 'C' дважды.    
        if (button =='C')
          break;

        button = customKeypad.getKey();
        if (button =='C')
        {    
          u8g.setPrintPos(0,0);
          num1=0;
          num2=0;
          total=0;
          operation=0;
          break;
        }
      }

    }


    void domath()
    {
      switch(operation)
      {
        case '+': // Сложение
          total = num1+num2;
          break;
         
        case '-': // Вычитание
          total = num1-num2;
          break;
         
        case '/': // Деление
          // Может добавить ошибку деления на ноль, или измените строку во втором цикле,
          // где тот ожидает символа '=' на if (button == '=' && num2 != 0), это остановит программу
          // от дальнейших действий, пока num2 не будет отличаться от нуля.
          total = (float)num1/(float)num2;
          break;
         
        case '*': // Умножение
          total = num1*num2;
          break;
             
      }
       
      u8g.setPrintPos(0,1);
      u8g.print('=');
      u8g.setPrintPos(1,1);
      u8g.print(total);  
    }
     
     
  4. b707

    b707 Гуру

    первым делом переставьте код функции domath() выше - между setup и loop. Возможно, что после этого и две другие ошибки исчезнут, потому как я не вижу, почему они возникают.
    Но вообще код, конечно, кривоватый. Автор похоже не понимает, зачем нужна функция loop и как она работает...
     
  5. akl

    akl Гуру

    функция должна быть объявлена раньше чем использована - надо где-нибудь в начале (до лупа и сетапа) написать строчку
    void domath(void);
     
  6. ИванL

    ИванL Нуб

    Переместил. Ругается компилятор.

    C:\Users\CD86~1\AppData\Local\Temp\untitled1662855145.tmp\sketch_dec24a\sketch_dec24a.ino: In function 'void loop()':

    sketch_dec24a:150: error: break statement not within loop or switch

    break;

    ^

    C:\Users\CD86~1\AppData\Local\Temp\untitled1662855145.tmp\sketch_dec24a\sketch_dec24a.ino: At global scope:

    sketch_dec24a:154: error: expected unqualified-id before 'while'

    while(1)

    ^

    exit status 1
    break statement not within loop or switch
     
  7. b707

    b707 Гуру

    эта ошибка чаще всего возникает, если у вас в программе непарное число открывающих и закрывающих скобок. По коду в форуме довольно трудно это проверить, так что попробуйте найти сами.
     
  8. akl

    akl Гуру

    вот тут скобка лишняя
    Код (C++):
    while(1)
      {
        // Второй цикл, он выполняется пока пользователь не нажмет '=' или 'C'.
        // И тогда будет выведен результат или сброшена программа.
        if (button =='C')
          break; // Это обрабатывает случай, когда пользователь нажал кнопку оператора и захотел сбросить
        button = customKeypad.getKey();
        if (button=='C') // Еще раз проверяем, не хочет ли пользователь сбросить
        {
          num1=0;
          num2=0;
          total=0;
          operation=0;
       
          break;
        }
        if (button >='0' && button <='9') // Получение символов от клавиатуры для числа 2
        {
          num2 = num2*10 + (button -'0');
          do {
          u8g.setPrintPos(10,10);
          u8g.print(num2);
          }
     
      while(u8g.nextPage());
          }
        }
        if (button == '=' && num2 !=0)
        { // Если нажата кнопка '=', то это конец пути. Вызываем функцию domath(), выполняющую расчет
          // и выводим результат.  
          domath();          
          break;
        }
      }
    после while(u8g.nextPage());
     
    b707 нравится это.
  9. fogary

    fogary Гик

    Код (C++):
    if (button =='C')
      break; // Это обрабатывает случай, когда пользователь нажал кнопку оператора и захотел сбросить
    Чисто из интереса, каким образом может случиться такой случай???
     
  10. 1Nikolai1

    1Nikolai1 Нуб

    Люди здорово, значит я решил заняться ардуинкой на ноутбуке с Windows XP, вобщем устанавливаю IDE для нее и сталкиваюсь во всех версиях что не запускается программа ну никак, работает только 1.6.3 но она выдает ошибки типо после собки ожидается ";" когда она там стоит что делать??
     
  11. akl

    akl Гуру

    что-то неправильно устанавливается. У меня ардуино 1.8.2 и 1.8.3 работают на ХП и на компе и на ноуте.
     
  12. 1Nikolai1

    1Nikolai1 Нуб

    а можете подсказать я вот с грехом по полам все установил но после загрузки 2 скечей стала показываться такая ошибка что делать ?
    Arduino: 1.8.5 (Windows XP), Плата:"Arduino/Genuino Uno"

    Скетч использует 2090 байт (6%) памяти устройства. Всего доступно 32256 байт.
    Глобальные переменные используют 50 байт (2%) динамической памяти, оставляя 1998 байт для локальных переменных. Максимум: 2048 байт.
    avrdude: ser_open(): can't set com-state for "\\.\COM25"
    Произошла ошибка при загрузке скетча
     
  13. ИванL

    ИванL Нуб

    Спасибо за столь детальное объяснение, но, к сожалению, не все проблемы разрешились. Совсем. Но скетч уже спокойно проходит компиляцию, но после загрузки ничего толком не происходит. При нажатии 6, 7, 8 загораются два пикселя. При нажатии 5 загорается только 1 пиксель. С чем это связано? Чувствую себя каким-то гуманитарием...
    на всякий случай прилагаю финальную версию кода
    Код (C++):
    #include <U8glib.h>
    #include <Keypad.h>
    U8GLIB_ST7920_128X64 u8g(10, 11, 12, U8G_PIN_NONE); // настройка пинов
    long num1,num2 ;
    double total;
    char operation,button;

    const byte ROWS = 4;
    const byte COLS = 4;

    char keys[ROWS][COLS] = {
      {'1','2','3','+'},
      {'4','5','6','-'},
      {'7','8','9','*'},
      {'C','0','=','/'}
    };
    byte rowPins[ROWS] = {0,1,2,3}; // подключение к строкам клавиатуры
    byte colPins[COLS] = {4,5,6,7};     // подключение к столбцам клавиатуры
    Keypad customKeypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);
    void domath(void);
    // Этот код выполняется только один раз: при включении платы
    void setup()
    {
       u8g.setFont(u8g_font_6x12); // Выбор шрифта

    }

    void loop()
    {
      //sprintf(num1, "%d",num2); // функция sprintf переведёт число в строковый массив
      // Циклы удобны для чтения нажатых кнопок клавиатуры
      while(1)
      {
        // Первый цикл. Здесь мы читаем клавиатуру и составляем наше первое число.
      // Он выполняется, пока мы не нажмем кнопку оператора, и цикл прервется,
      // или, если будет нажата кнопка 'C', всё начнется с начала.
         
        button = customKeypad.getKey(); // Чтение кнопки
        if (button=='C') // Если пользователь хочет сбросить набор первого числа
        {
          num1=0;
          num2=0;
          total=0;
          operation=0;
       
        }
         
        if (button >='0' && button <='9') // Если пользователь нажал на числовое значение, один символ за раз
        {
          num1 = num1*10 + (button -'0');
          // Наши числовые значения лежат в диапазоне от 0 до 9, что означает, что это единицы.
          // Когда мы умножаем на 10, мы, по сути, добавляем 0 после числа.
          // Затем мы добавляем новое введенное число на место нуля.
          // Что касается (button -'0'), это простой трюк с таблице ASCII. Цифры 0...9 в таблице ASCII
          // это 48...57 (в десятичном виде), поэтому, вычитание '0' из любого из этих символов дает
          // соответствующее значение в десятичном виде. Например, символ '5' = 53 в десятичной системе
          // минус 48 (символ нуля) дает нам значение 5.
          // Если наше предыдущее число было, например, 25, мы получили 250 умножением его на 10,
          // а затем добавили 5, и получили 255, что и будет выведено на U8G.
          do
       {
          u8g.setPrintPos(0,10); // Выбор первой строки на U8G
          u8g.print(num1);    // Печать текущего значения числа num1
          }
     
      while(u8g.nextPage());
        }
     
      if (num1 !=0 && (button=='-' || button=='+' || button=='*' || button=='/'))
        {
          // Если пользователь завершил ввод цифр
          operation = button;   // запоминаем, какое математическое действие пользователь хочет выполнить
         do {
          u8g.setPrintPos(0,20);   // установить курсор на строку 2
          u8g.print(operation); // напечатать наш оператор
          }
     
      while(u8g.nextPage());
          break;
        }

      }
     
      while(1)
      {
        // Второй цикл, он выполняется пока пользователь не нажмет '=' или 'C'.
        // И тогда будет выведен результат или сброшена программа.
        if (button =='C')
          break; // Это обрабатывает случай, когда пользователь нажал кнопку оператора и захотел сбросить
        button = customKeypad.getKey();
        if (button=='C') // Еще раз проверяем, не хочет ли пользователь сбросить
        {
          num1=0;
          num2=0;
          total=0;
          operation=0;
       
          break;
        }
        if (button >='0' && button <='9') // Получение символов от клавиатуры для числа 2
        {
          num2 = num2*10 + (button -'0');
          do {
          u8g.setPrintPos(10,10);
          u8g.print(num2);
          }
     
      while(u8g.nextPage());
          }
       
        if (button == '=' && num2 !=0)
        { // Если нажата кнопка '=', то это конец пути. Вызываем функцию domath(), выполняющую расчет
          // и выводим результат.    
          domath();          
          break;
        }
      }
     
      while(1)
      {
        // Когда всё выполнено, этот цикл ждет нажатия кнопки 'C', чтобы сбросить программу и начать с начала.
       
        // Это побочный эффект от предыдущего цикла, когда пользователь нажал 'C', предыдущий цикл прерывается
        // и переходит сюда. Поэтому мы должны также прервать и текущий цикл, иначе пользователю придется
        // нажимать 'C' дважды.    
        if (button =='C')
          break;

        button = customKeypad.getKey();
        if (button =='C')
        {    
          u8g.setPrintPos(0,0);
          num1=0;
          num2=0;
          total=0;
          operation=0;
          break;
        }
      }

    }


    void domath()
    {
      switch(operation)
      {
        case '+': // Сложение
          total = num1+num2;
          break;
       
        case '-': // Вычитание
          total = num1-num2;
          break;
       
        case '/': // Деление
          // Может добавить ошибку деления на ноль, или измените строку во втором цикле,
          // где тот ожидает символа '=' на if (button == '=' && num2 != 0), это остановит программу
          // от дальнейших действий, пока num2 не будет отличаться от нуля.
          total = (float)num1/(float)num2;
          break;
       
        case '*': // Умножение
          total = num1*num2;
          break;
           
      }
        do {
      u8g.setPrintPos(0,10);
      u8g.print('=');
      u8g.setPrintPos(10,10);
      u8g.print(total);
        }
     
      while(u8g.nextPage());  
    }
     
  14. ИванL

    ИванL Нуб

    Может вы перепутали операцию
     
  15. Arduino_man

    Arduino_man Гик

    Выбран некорректный COM-порт.