Калькулятор на Arduino UNO R3
- Войдите на сайт для отправки комментариев
Сб, 11/06/2022 - 13:25
Здравствуйте, имеется скетч программы в который написано код для имитации калькулятора, проблема состоит в том что вывод чисел на экран бывает не тот который хочется, например я нажал на матричной клавиатуре семь раз на кнопку "1", вывелось 1111111, нажимаю ещё раз, а вместо ожидаемой единицы у меня уже стоит 2, это видно очень заметно при десятичной дроби, которую я ввожу, уже после нажатого символа происходит тоже самое, совсем другие числа. Весь ввод происходит в функции fillNumber(float &num).
Скетч прогонял в proteus и на реальном аппарате, все фукнции работают исправно, кроме ввода чисел, выше описал проблему. Вот сама схема в proteus:
// Соответствие кнопок калькулятора по отношений к кнопкам матричной клавиатуры // Кнопка [-=] -> [A] // Кнопка [+=] -> [B] // Кнопка [*] -> [*] // Кнопка [/] -> [#] // Кнопка [C] -> [C] // Кнопка [K] -> [D] // Кнопка [.] -> отдельная кнопка отвечающая за десятичную дробь #include <Keypad.h> // Подключение библиотеки для работы с матричной клавиатурой const byte ROWS = 4; // Определение константы, указывающей на количество рядов клавиатуры const byte COLS = 4; // Определение константы, указывающей на количество столбцов клавиатуры const int decimal = 8;// Определение константы, указывающей на отдельную кнопку // Инициализация двухмерного массива, определяющего раскладку матричной клавиатуры char keys[ROWS][COLS] = { {'1', '2', '3', 'A'}, {'4', '5', '6', 'B'}, {'7', '8', '9', 'C'}, {'*', '0', '#', 'D'} }; byte rowPins[ROWS] = {A0, A1, A2, A3}; // Номера выводов Arduino, к которым подключены линии управления рядами клавиатуры byte colPins[COLS] = {5, 4, 3, 2}; // Номера выводов Arduino, к которым подключены линии управления столбцами клавиатуры Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS); // Создание объекта класса Keypad, инициализация его конструктора согласно вышеуказанным параметрам #include <Wire.h> // Подключение библиотеки для работы с шиной I2C #include <LiquidCrystal_I2C.h> // Подключение библиотеки для работы с дисплеем по шине I2C LiquidCrystal_I2C lcd(0x27, 16, 2); // Создание объекта класса LiquidCrystal_I2C, инициализация его конструктора (адрес на шине 0x27, размер 16 симполов, 2 строки) // ---------- ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ ---------- int globalState = 0; // Переменная для разделения основного цикла на фазы int globalStateNumber = 0; // Переменная смены режима в введение десятичной дроби int digitCursor = 0; // Переменная хранит текущее положение цифры на дисплее int z = 1; float number = 0.0; // Переменная для хранения вводимого числа float tempNumber = 0.0; // Вспомогательная переменная для режима умножения и деления на постоянное число float tempNumberCounter = 0.0; // Вспомогательная переменная для режима умножения и деления на постоянное число float answer = 0.0; // Переменная для хранения ответа char key; // Переменная для хранения кода нажатой клавиши long a; bool flagMultiplication = false; // Вспомогательный флаг для фиксации операции умножения bool flagDivision = false; // Вспомогательный флаг для фиксации операции деления bool flagPlus = false; // Вспомогательный флаг для фиксации операции сложения bool flagFirstNumber = true; // Вспомогательный флаг для фиксации ввода первого числа после сброса bool flagEnterNumber = false; // Вспомогательный флаг для фиксации момента ввода числа с клавиатуры bool flagDecimal = false; // Вспомогательный флаг для фиксации нажатия на отдельную кнопку uint32_t btnTimer = 0; // Таймер для предотвращения дребезга контактов чтобы алгоритм лишний раз не прогонялся // ---------- ФУНКЦИЯ ВЫВОДА РЕЗУЛЬТАТОВ ВЫЧИСЛЕНИЙ ---------- void showResult(float num, bool point = false) { digitCursor = 0; lcd.setCursor(digitCursor, 0); lcd.clear(); delay(300); if((num - int(num)) > 0 || point) lcd.print(num, 7); else { lcd.print(num, 0); lcd.print("."); } } // ---------- ФУНКЦИЯ ПРЕДВАРИТЕЛЬНЫХ УСТАНОВОК ---------- void setup() { pinMode(decimal,INPUT_PULLUP); lcd.init(); // Инициализация дисплея lcd.backlight(); // Включение подсветки дисплея lcd.clear(); // Очистка дисплея } // ---------- БЕСКОНЕЧНЫЙ ЦИКЛ ----------- void loop() { key = keypad.getKey(); // Чтение состояния клавиатуры bool btnState = !digitalRead(8); // ----------[ C ]---------- if(globalState == 0) { if(key != NO_KEY) { // Если зафиксировано нажатие на какую-либо кнопку... if(key == 'C') { // Если нажата клавиша [С]... showResult(0); // Очистка буфера, подготовка к вводу первого числа globalState = 1; // Переход к следующей программной фазе } } } else if(globalState == 1) { if(key != NO_KEY) { // Если зафиксировано нажатие на какую-либо кнопку... fillNumber(number); // Если пользователь нажимает цифры - вводим и запоминаем это число // ----------[ += ]---------- if(key == 'B') { // Если нажата кнопка [ += ]... if(flagFirstNumber) { // Если вводимое число является первым по счёту... answer = number; // Приравниваем результату вычислений вводимое число flagFirstNumber = false; // Деактивируем флаг фиксации ввода первого числа после сброса flagPlus = true; // Устанавливаем флаг фиксации операции сложения showResult(answer); // Выводим результат на дисплей } else { // Если вводимое число не является первым... if(flagPlus) { // Если флаг фиксации операции сложения активен... answer += number; // Выполняем операцию сложения showResult(answer); // Выводим результат на дисплей } if(flagMultiplication) { // Если до операции сложения была операция умножения... answer *= number; // Выполняем операцию умножения flagPlus = true; // Устанавливаем флаг фиксации операции сложения flagMultiplication = false; // Деактивируем флаг фиксации операции умножения showResult(answer); // Выводим результат на дисплей } if(flagDivision) { // Если до операции сложения была операция деления... answer /= number; // Выполняем операцию деления flagPlus = true; // Устанавливаем флаг фиксации операции сложения flagDivision = false; // Деактивируем флаг фиксации операции деления showResult(answer); // Выводим результат на дисплей } } if(flagDecimal) { flagDecimal = false; // Деактивируем флаг фиксации ввода десятичной дроби, если она была нажата } flagEnterNumber = false; // Деактивируем флаг фиксации момента ввода числа с клавиатуры globalStateNumber = 0; z = 1; } // ----------[ * ]---------- if(key == '*') { // Если нажата кнопка [ * ]... if(flagPlus && !flagEnterNumber) { // Если до операции умножения была операция сложения, но не было введено второе число... flagPlus = false; // Деактивируем флаг фиксации операции сложения flagMultiplication = true; // Устанавливаем флаг фиксации операции умножения number = 1.0; // Присваеваем значение по умолчанию вместо вводимого числа } if(flagFirstNumber) { // Если вводимое число является первым по счёту... answer = number; // Приравниваем результату вычислений вводимое число flagFirstNumber = false; // Деактивируем флаг фиксации ввода первого числа после сброса flagMultiplication = true; // Устанавливаем флаг фиксации операции умножения showResult(answer); // Выводим результат на дисплей } else { // Если вводимое число не является первым... if(flagMultiplication) { // Если флаг фиксации операции умножения активен... answer *= number; // Выполняем операцию умножения showResult(answer); // Выводим результат на дисплей } if(flagDivision) { // Если до операции умножения была операция деления... answer /= number; // Выполняем операцию деления flagDivision = false; // Деактивируем флаг фиксации операции деления showResult(answer); // Выводим результат на дисплей flagMultiplication = true; // Устанавливаем флаг фиксации операции умножения } if(flagPlus) { // Если до операции умножения была операция сложения... answer += number; // Выполняем операцию сложения flagPlus = false; // Деактивируем флаг фиксации операции сложения showResult(answer); // Выводим результат на дисплей flagMultiplication = true; // Устанавливаем флаг фиксации операции умножения } } if(flagDecimal){ flagDecimal = false; // Деактивируем флаг фиксации ввода десятичной дроби, если она была нажата } flagEnterNumber = false; // Деактивируем флаг фиксации момента ввода числа с клавиатуры } // ----------[ # ]---------- if(key == '#') { // Если нажата кнопка [ # ]... if(flagPlus && !flagEnterNumber) { // Если до операции деления была операция сложения, но не было введено второе число... flagPlus = false; // Деактивируем флаг фиксации операции сложения flagDivision = true; // Устанавливаем флаг фиксации операции деления number = 1.0; // Присваеваем значение по умолчанию вместо вводимого числа } if(flagFirstNumber) { // Если вводимое число является первым по счёту... answer = number; // Приравниваем результату вычислений вводимое число flagFirstNumber = false; // Деактивируем флаг фиксации ввода первого числа после сброса flagDivision = true; // Устанавливаем флаг фиксации операции деления showResult(answer); // Выводим результат на дисплей } else { // Если вводимое число не является первым... if(flagDivision) { // Если флаг фиксации операции деления активен... answer /= number; // Выполняем операцию деления showResult(answer); // Выводим результат на дисплей } if(flagMultiplication) { // Если до операции деления была операция умножения... answer *= number; // Выполняем операцию умножения flagMultiplication = false; // Деактивируем флаг фиксации операции умножения showResult(answer); // Выводим результат на дисплей flagDivision = true; // Устанавливаем флаг фиксации операции деления } if(flagPlus) { // Если до операции деления была операция сложения... answer += number; // Выполняем операцию сложения flagPlus = false; // Деактивируем флаг фиксации операции умножения showResult(answer); // Выводим результат на дисплей flagDivision = true; // Устанавливаем флаг фиксации операции деления } } if(flagDecimal) { flagDecimal = false; // Деактивируем флаг фиксации ввода десятичной дроби, если она была нажата } flagEnterNumber = false; // Деактивируем флаг фиксации момента ввода числа с клавиатуры globalStateNumber = 0; z = 1; } // ----------[ -= ]---------- if(key == 'A') { // Если нажата кнопка [ А ]... answer -= number; // Выполняем операцию вычитания showResult(answer); // Выводим результат на дисплей if(flagDecimal) { flagDecimal = false; // Деактивируем флаг фиксации ввода десятичной дроби, если она была нажата } flagEnterNumber = false; // Деактивируем флаг фиксации момента ввода числа с клавиатуры globalStateNumber = 0; z = 1; } // ----------[ C ]---------- else if(key == 'C') { // Если нажата кнопка [ С ] -> сбрасываем все параметры number = 0.0; answer = 0.0; tempNumber = 0.0; tempNumberCounter = 0.0; flagMultiplication = false; flagDivision = false; flagPlus = false; flagFirstNumber = true; flagDecimal = false; showResult(0); globalState = 1; globalStateNumber = 0; z = 1; } // Если нажата кнопка [К] сразу после кнопки [C] - переходим в режим умножения или деления на постоянное число else if(key == 'D' && !flagMultiplication && !flagDivision && !flagPlus && number == 0.0 && answer == 0.0) { globalState = 2; } } // ----------[ . ]---------- if(btnState && !flagDecimal && millis() - btnTimer > 100) { flagDecimal = true; btnTimer = millis(); globalStateNumber++; } } // globalState = 1 else if(globalState == 2) { fillNumber(number); // Если пользователь вводит число - записываем его в переменную Number // Если нажата кнопка [+=] if(key == 'B') { if(flagMultiplication) { // Если мы работаем с умножением answer = tempNumber * number++; // Вычисляем результат умножения и автоматически увеличиваем число на единицу showResult(answer); // Выводим результат на дисплей } else if(flagDivision) { // Если мы работаем с делением answer = tempNumber / number; // Вычисляем результат деления showResult(answer); // Выводим результат на дисплей //tempNumber += tempNumberCounter; // Автоматически увеличиваем число на величину первоначального значения } } // Если нажата кнопка [*] else if(key == '*') { z = 1; if(answer == 0.0) { tempNumber = number; // Запоминаем число, с которым будем в дальнейшем работать answer = number; showResult(answer); // Выводим результат на дисплей } flagMultiplication = true; } // Если нажата кнопка [#] else if(key == '#') { z = 1; if(answer == 0.0) { tempNumber = number; // Запоминаем число, с которым будем в дальнейшем работать answer = number; //tempNumberCounter = number; showResult(answer); // Выводим результат на дисплей } flagDivision = true; } // ----------[ . ]---------- else if(btnState && !flagDecimal && millis() - btnTimer > 100) { flagDecimal = true; btnTimer = millis(); globalStateNumber++; } // Если нажата кнопка [ С ] -> сбрасываем все параметры else if(key == 'C') { number = 0.0; answer = 0.0; tempNumber = 0.0; tempNumberCounter = 0.0; flagMultiplication = false; flagDivision = false; flagPlus = false; flagFirstNumber = true; flagDecimal = false; showResult(0); globalState = 1; globalStateNumber = 0; z = 1; } } // globalState = 2 } // ---------- ФУНКЦИЯ ВЫЧИСЛЯЕТ ЧИСЛО, ВВОДИМОЕ ПОЛЬЗОВАТЕЛЕМ И СОХРАНЯЕТ ЕГО В ПЕРЕМЕННУЮ ПО ССЫЛКЕ С ПОСЛЕДУЮЩИМ ВЫВОДОМ НА ЭКРАН ---------- void fillNumber(float &num) { if((key == '0' || key == '1' || key == '2' || key == '3' || key == '4' || key == '5' || key == '6' || key == '7' || key == '8' || key == '9') && (digitCursor < 8)) { flagEnterNumber = true; if(digitCursor == 0) num = (key - 48); else if(globalStateNumber == 0){ a = pow(10, z); num = num * (float)a + key - 48; } else if(globalStateNumber == 1){ a = pow(10, z); num = (num * (float)a + (key - 48))/(float)a; z++; } lcd.clear(); lcd.setCursor(0, 0); lcd.print(num, z-1); if (globalStateNumber == 0) lcd.print("."); digitCursor++; } }
Конечно же писал не сам? "Надергал" откуда-то из интернета?
Потому что ты пытаешься оперировать с числами с плавающей точкой как с десятичными.
Вводи текст, в числа переводи уже в момент операции, будет нормально выглядеть. (работать будет всё так же).
Спасибо за совет, исправил, стало получше всё выглядить.
нажимаю ещё раз, а вместо ожидаемой единицы у меня уже стоит 2, это видно очень заметно при десятичной дроби
Дребезг контактов клавиатуры? Стандартная задача студентам.
Не, не дребезг контактов, если ранее вводилось всё точно.