1

I am attempting to make a calculator with arduino using a 16x2 Text-LCD and a 4x4 keypad. I've already programmed the part where the arduino board gets input from the keypad and displays characters on the LCD respectively, but I'm struggling to program the part where the '=' button is pressed and the arduino parses the sum and gives the answer. I'm not using the RW lin to read the LCD, instead I am adding characters pressed to a char[] variable. Can you guys please give me some code to parse the inputted characters? Thanks!

EDIT: Code:

#include <LiquidCrystal.h>
#include <Key.h>
#include <Keypad.h>

char keys[4][4]={
  '/','x','-','+',
  '=','9','6','3',
  '0','8','5','2',
  'C','7','4','1'
};

byte rowPins[4]={7,6,5,4};
byte colPins[4]={3,2,1,0};

Keypad input=Keypad(makeKeymap(keys),rowPins,colPins,4,4);

LiquidCrystal lcd(8,9,10,11,12,13);
int inputSize=1;
char inputSum[16];

int cursorNum=0;

void setup() {
 lcd.begin(16,2);
}
void loop() {
  char key = input.getKey();
  if(key) {
    if(key == 'C') {
      lcd.clear();
    }else if(key == '=') {
      parseInput();
    }

    else{
    lcd.print(key);
    inputSum[cursorNum]=key;
    cursorNum++;
    }
  }
}

int result;
void parseInput() {
  //Parse code goes here

  lcd.setCursor(0,1);
  lcd.print(result);

}
2

2 Answers 2

2

Characters in a char[] variable may be encoded in ASCII or Unicode. You will want to convert them to numbers in this case. Consider subtracting the ascii value of one less than 0 from each char to get the number. Edit: @Matt informed me that 0 is the lowest ASCII number. As he suggested, you can subtract the character '0' from the digit to get the value. You want to specially handle any addition, division, or other operator symbols.

Then you can treat each number like a digit in a number. If you can break up the array of numbers by the operators, you can successively attach the operands to the operators. Keep in mind that each number to the left is a power of ten (assuming this is how it's implemented. This is called Endianess.)

If you post code I may be able to help further.

2
  • "one less than 1" ?? In other words zero? The idea is correct the keypad libraries usually return a char so int number = KeyPad.getChar() - '0'; would work Commented Nov 22, 2016 at 9:10
  • 1
    I was thinking that ''1' was the lowest ascii number. I just checked a ascii table and it looks like '0' is. I'll update my answer. Commented Nov 23, 2016 at 15:55
0

You could parse it with something like this:

int parserr;

int parse(char* input)
{
  parserr = 0;
  if (input == 0) return (0);
  char* ip = input;
  char c = *ip++;
  if (c == 0) return (0);
  int res = 0;
  char op = 1;
  while (1) {
    int num = 0;
    int neg = 0;
    if (c == '-') {
      neg = 1;
      c = *ip++;
    }
    int isnum = isdigit(c);
    while (isdigit(c)) {
      num = (num * 10) + (c - '0');
      c = *ip++;
    }
    if (neg) num = -num;
    if (!isnum) op = 0;
    switch (op) {
    case 1: res = num; break;
    case '+': res = res + num; break;
    case '-': res = res - num; break;
    case '*': res = res * num; break;
    case '/': res = res / num; break;
    default:
      parserr = (ip - input - 1);
      return (res);
    };
    if (c == 0) return (res);
    op = c;
    c = *ip++;
  }
}

The variable parserr holds the error position (+1), zero is no parse error. The function parse() will return the value of the simple expression with no operator priority.

This can be refactored to allow normal operator priority:

#include <ctype.h>

class Calculator {
public:
  int eval(char* input, int& result)
  {
    if (input == 0 || *input == 0) return (0);
    m_ip = input;
    if (expr(result)) return (0);
    return (m_ip - input + 1);
  }

private:
  char* m_ip;

  char getc()
  {
    return (*m_ip++);
  }

  int ungetc(int res)
  {
    m_ip--;
    return (res);
  }

  int number(int& value)
  {
    int neg = 0;
    char c = getc();
    if (c == '-') {
      neg = 1;
      c = getc();
    }
    value = 0;
    if (!isdigit(c)) return (ungetc(0));
    do {
      value = (value * 10) + (c - '0');
      c = getc();
    } while (isdigit(c));
    if (neg) value = -value;
    return (ungetc(1));
  }

  int fact(int& result)
  {
    return (number(result));
  }

  int term(int& result)
  {
    if (!fact(result)) return (0);
    int value = result;
    char op;
    while ((op = getc()) != 0) {
      if (op != '*' && op != '/') return (ungetc(1));
      if (!number(value)) return (0);
      switch (op) {
      case '*': result = result * value; break;
      case '/': result = result / value; break;
      }
    }
    return (ungetc(1));
  }

  int expr(int& result)
  {
    if (!term(result)) return (0);
    int value = result;
    char op;
    while ((op = getc()) != 0) {
      if (op != '+' && op != '-') return (ungetc(0));
      if (!term(value)) return (0);
      switch (op) {
      case '+': result = result + value; break;
      case '-': result = result - value; break;
      }
    }
    return (1);
  }
};

Cheers!

2
  • What if I input "2+5*3”? I believe it should do "5*3+2 = 17", and not (2+5)*3 = 21.
    – aaa
    Commented Nov 24, 2016 at 7:49
  • 1
    That is what "no operator priority" means :). Parsed and executed in order. It is easy to modify for priority operators. Commented Nov 24, 2016 at 9:53