My calculator in the Arduino serial monitor

Hello programmers!

I am pretty new to arduino, don't understand much really, but every day I learn a little more and more. Now I have a project where I am making a "simple" serial monitor calculator, with some extra features. I have some basic understanding of coding, but in reality I'm pretty clueless and in need of some expert help.

The last days I have googled codes, read texts and tutorials and watched a whole lot of youtube-films to get me started. And this is my code as of now:

#include <math.h>
#include <stdio.h>

/*float addisjon        (float num1, float num2); This part is to looked past, I think it does nothing.
float subtraksjon     (float num1, float num2);
float multiplikasjon  (float num1, float num2);
float divisjon        (float num1, float num2);
*/
void setup() {
  Serial.begin(9600);
  Serial.println("Velg kalkulatorbruk ved aa skrive inn: 1, 2, 3, 4, 5, 6, 7, 8 eller 9"); // It says "choose calculator usage by selecting from these numbers"
  Serial.println(""); // 1 til 4 skulle helst ha vært 1 case hvor jeg selv velger operator, nå er den på forhånd bestemt for case 1 til 4. 
  Serial.println("1) Enkel addisjon med to variabler");//To variabler og en operator - Simple addition with two variables and an operator
  Serial.println("2) Enkel subtraksjon med to variabler");//To variabler og en operator - Simple subtraction with two variables and an operator
  Serial.println("3) Enkel multiplikasjon med to variabler");//To variabler og en operator - Simple multiplication with two variables and an operator
  Serial.println("4) Enkel divisjon med to variabler");//To variabler og en operator - Simple division with two variables and an operator
  Serial.println("5) Utrykk med parenteser og bruk av desimaltall");//Hva som helst skal kunne brukes her - This case I have written more about further down in my post
  Serial.println("6) Lose potenser"); //Grunntall opphoyet i en eksponent - Eksponential value/numbers
  Serial.println("7) Lose kvadratrotter");//kvadratroten av et tall med desimaler - Square root
  Serial.println("8) Sinus til X"); //med desimaler og pluss/minus - Sin(x)
  Serial.println("9) Cosinus til X");//med desimaler og pluss/minus - Cos(x)
  Serial.println("........................................");

}

int lesAvPC() { //vil ha float her - This is where I want float
  while (Serial.available() == 0); //Do I need to do something to "while?"

  return Serial.parseInt(); //vil ha parseFloat her, får ikke til...- is parse.Float() possible?
}

void loop() { //what to do, switch gir problemer - Switch is giving me problems as I have written in my post
  switch (lesAvPC())
  {
    case 1:
      {

        Serial.print("1) Skriv forste tall: "); // Write the first number
        float num1 = lesAvPC();
        Serial.println(num1);
        Serial.println("   Operatoren bruker:  +"); //ikke sqrt men en operator som+-*/
        Serial.print("    Skriv siste tall: "); // Write the last number
        float num2 = lesAvPC();
        Serial.println(num2);
        Serial.println(" ");
        Serial.print("           Svaret er: "); // The answer is:
        float fasit = num1 + num2;//Ønsker å få til en if med alle operasjonene her i stedet for 4 cases. - Would like all the first 4 cases to be one case which includes all operators
        Serial.println(fasit); //answer
        Serial.println(" ");
        // Serial.print("(num1 + num2) = (fasit())"); // Her ønsker jeg at hele funksjonen skal stå
        Serial.println("........................................"); //Jeg vil at den skal kunne printe hele regnestykket på en linje med + og = og variablene
        break;
      }

    case 2:
      {
        Serial.print("2) Skriv forste tall: ");
        float num1 = lesAvPC();
        Serial.println(num1);
        Serial.println("   Operatoren bruker:  -"); //ikke sqrt men en operator som+-*/
        Serial.print("    Skriv siste tall: ");
        float num2 = lesAvPC();
        Serial.println(num2);
        Serial.println(" ");
        Serial.print("           Svaret er: ");
        float fasit = num1 - num2;
        Serial.println(fasit);
        Serial.println(" ");
        // Serial.print("(num1 - num2) = (fasit())"); // Her ønsker jeg at hele funksjonen skal stå
        Serial.println("........................................"); //Jeg vil at den skal kunne printe hele regnestykket på en linje med + og = og variablene
        break;
      }
    case 3:
      {
        Serial.print("3) Skriv forste tall: ");
        float num1 = lesAvPC();
        Serial.println(num1);
        Serial.println("   Operatoren bruker:  *"); //ikke sqrt men en operator som+-*/
        Serial.print("    Skriv siste tall: ");
        float num2 = lesAvPC();
        Serial.println(num2);
        Serial.println(" ");
        Serial.print("           Svaret er: ");
        float fasit = num1 * num2;
        Serial.println(fasit);
        Serial.println(" ");
        // Serial.print("(num1 * num2) = (fasit())"); // Her ønsker jeg at hele funksjonen skal stå
        Serial.println("........................................"); //Jeg vil at den skal kunne printe hele regnestykket på en linje med + og = og variablene
        break;
      }
    case 4:
      {
        Serial.print("4) Skriv forste tall: ");
        float num1 = lesAvPC();
        Serial.println(num1);
        Serial.println("   Operatoren bruker:  /"); //ikke sqrt men en operator som+-*/
        Serial.print("    Skriv siste tall: ");
        float num2 = lesAvPC();
        Serial.println(num2);
        Serial.println(" ");
        Serial.print("           Svaret er: ");
        float fasit = num1 / num2;
        Serial.println(fasit);
        Serial.println(" ");
        // Serial.print("(num1 / num2) = (fasit())"); // Her ønsker jeg at hele funksjonen skal stå
        Serial.println("........................................"); //Jeg vil at den skal kunne printe hele regnestykket på en linje med + og = og variablene
        break;
      }
    case 5: {
        Serial.print("5) Skriv fullt funksjonsutrykk: "); // Nothing is happening here, but that is OK at the moment. But I would like to write a full function in the future.
        Serial.println("Svaret er: sqrt(lesAvPC())");//svaret også tallene fra pcen
        Serial.println("........................................");
        break;
      }

    case 6: {
        Serial.print("6) Skriv onsket grunntall: ");
        float grunntall = lesAvPC();
        Serial.println(grunntall);

        Serial.print("   Skriv onsket eksponentiell verdi: ");
        float eksponent = lesAvPC();
        Serial.println(eksponent);

        Serial.print("   Svaret er: ");
        float fasit = pow(grunntall, eksponent);
        Serial.println(fasit);
        Serial.println("........................................");
        break;
      }

    case 7: {
        Serial.print("7) Skriv onsket verdi for kvadratrot: ");
        Serial.println(sqrt(lesAvPC()));
        Serial.println("........................................");
        break;
      }

    case 8: {
        Serial.print("8) Skriv onsket tallverdi for sin(x), svaret gis i radianer: ");
        Serial.println(sin(lesAvPC()));
        Serial.println("........................................");
        break;
      }
    case 9: {
        Serial.print("9) Skriv onsket tallverdi for cos(x), svaret gis i radianer: ");
        Serial.println(cos(lesAvPC()));
        Serial.println("........................................");
        break;
      }


  }
}

I have added some extra info to the code so that it will be easier for you to read it, and understand it since I have written it in my native language.

I just need to say that my message exceeded the maximum allowed length so I will post two messages at the start here. First the code and then some information. Thank you!

OK-so where do I start. Well, first I want this calculator to be able to solve the simplest of mathematical tasks. I want to be able to write "first number" and press enter then an "operator (+-*/)" press enter and then the "last number" and press enter and get the answer. And this works decent as of this moment. But the way I have ended up making this code I now have four cases dedicated to this simple math, where the first is addition and the "+" automatically comes after the first number I write in. This goes for cases 2,3,4(subtraction, multiplication, division) also. What I really want is only 1 case instead of 4, more like a real calculator, but I couldn't make it work like I wanted when I tried. So in case 1 where the code is something like "Answer = number1 + number2" how can I simply delete the cases 2,3 and 4 and change case 1 to a code that says Answer = number1 + or - or * or / number 2. Would "+ || - || * || /" work? I have tried it, and I couldn't make it work, but I probably forgot more than one thing.

So, over to my second question, decimals. I would really like the entire calculator to work with decimal numbers. Don't really care if it uses more time to use and load, I prefer the usage of decimal number all around. And It does not work now. If I in case 1 write 4.5 or 4,5 in the serial monitor it thinks I mean 4+5 and gives me 9 as the answer. Now, hear me out, because in case 4, where the operator is division, if I write 4.5 it believes I wrote "4 / 5" and gives me 0.8 as the answer. So it can give me decimal answers as the output, but the input doesn't accept it, and converts it.

What I know from my code is that float = decimal numbers while int = whole numbers. And I have only used "int" one time. This part:

int lesAvPC() { //it says int readFromPC()
  while (Serial.available() == 0); // can or should I do something with my while?

  return Serial.parseInt();
}

void loop() { 
  switch (lesAvPC()) // switch (readFromPC())
  {
    case 1:

Since I know that it's my only int, my idea was to replace "int readFromPC()" with "float readFromPC()" and the same 2 lines under where "return Serial.parseInt();" probably should be "return Serial.parseFloat();". But when I do this, an error occurs at "switch (readFromPC())" telling me: "exit status 1, switch quantity not an integer". So I understand that by doing this change it won't work because switch isn't an integer, but a float now, and it can't work with a float? How do I fix this? I have read some info on the internet, but I simply don't understand how to change and write it. I read something about if/else if and someone mentioned enum possibleStates. My mind is blown at this point.

Allright, so next is case 5. If I get the first 4 cases to work like I want and merge into one case, then this should be case 2 instead of case 5. This is the least important part of my calculator, simply because I have done nothing with it. The code so far is just to be ignored. My idea is that this case will contain several operators and several numbers and even be able to place parenthesises(?) wherever I would want it to. Examples like 2(4-3.2)*((2/2)+8) or ((((-2)-2.5)-2.5)*3)/4. Really whatever. (written in serial monitor) But I have this placed on ice as of this moment, because I need the simple basic math to work as I want first. I feel like it probably isn't any point to making this before I can make case 1 work as I want. But If there is some standard code to get me started, please let me know!

Case 6 and 7 sort of works like I want it to, except for the decimal problem. Case 6 is the exponential function with base and power (I think this is what it's called in English?). If I enter 6 in the serial monitor it chooses exponential value, and asks me for base value, if I give it "2" it asks me for power value, and if I write 3 it gives me 8. So that is superb. 2^3 = 8. But here also, decimals do not work. Case 7 is square root. Which works quite good. I can give the serial monitor the value of "8" and it will return "2.83". Which I find simply amazing. This also blew my mind, but this time, in a good way. Of course, I can't write "8.5", because it has decimal problems, so it would be great to be able to find the sqrt of f.ex 3.14 also, instead of having it automatically convert it to sqrt of 3 and return the answer to me that I don't want.

We are closing in on the end of my "novel", and if your still here; Thank you! Case 8 and case 9 is the sinus and cosinus functions. Here, I'm not quite sure what I want, much like a woman in a shoe-store. I think I want it to do two things. If I write sin(1) it returns 0.84. (Hey! That's the same as my Casio calculator when it's turned into radians!). But my slow-witted mind thinks this return is sort of boring. So could I try to write sin(PI/2) and somehow get it to return both "1" and a degree answer? F.ex "sin(PI/2)= 90degrees". Keep in mind the decimal-problem making sin(3.14) automatically turn into sin(3).
Maybe it's even better if I merge it with case 9 (the cosinus) and write (PI/2) in the serial monitor and it returns something like this:

sin (PI/2) = 1(rad)
sin (PI/2) = 90degrees
cos (PI/2) = 0(rad)
cos (PI/2) = 90degrees

Or...maybe not. I just don't know. I did try it, to merge the code of case 8 and 9 into one code, and it did not work. Looking at it know I think it is better if it's separated cases.

Lastly, I probably need a restart button, in the serial monitor. Instead of exiting and entering the monitor a lot to not loose control it would be awesome to write "R"(restart) or "C"(Clear) and the monitor would just refresh so that the top text always is visible even though I continuously write different tasks for different cases.
Also I included two libraries, I suppose they are the reason it works. Am I supposed to copy the code that I use from the library into my own code? F.ex. the sqrt code?

Thank you so much for all your thoughts, ideas, help and support in advance. My head, which usually is surrounded only by football has finally started to enjoy the arduino use/programming and now that at least some of the things works allright, I am really enjoying myself!
Please keep in mind that my mental capacity is somewhere between a power cable not connected to a socket and a really smart dog.

I included some fast translations:

lesAVPC = readFromPC
fasit = answer
forste = first
siste = last
tall = number
grunntall = base
eksponent = power
Svaret er = The answer is

Okay, that was long and confusing!
It would be better if you create a function which takes 2 floats and a char(the operator, +,-,*,/,^ or something else) and returns a float as answer. Switch case only works with integers and chars, so you just create cases for each operator like so:

float calc(float num1, float num2, char oprt){
    switch(oprt){
     case '+':
         return (num1 + num2)

     ...
    }
}

In this way you can work with decimals all along.
Also, you mentioned somewhere integers=whole numbers, which is not true mathematically. whole numbers don't have negative values.

After that you can use your function to accept inputs like "2(4-3.2)*((2/2)+8) or ((((-2)-2.5)-2.5)3)/4". You just need to read character by character and use a whole bunch of if statements to decide, like for e.g. if "(" after a number, then oprt = '', but if ")" after a number, close the product term, or a syntax error. It would be better if you write an algorithm or pseudo code on paper first.

For Reset, just add it in the outermost decision block so that it has the most priority. For square root, you can find help here.

And btw, Arduino is not meant for this kind of stuff so it would be better if you do this on CodeBlocks or some C/C++ IDE. You can though take it up as a challenge and you will learn things about the Serial Monitor and C but there are better projects to do with Arduino! Please let us know if you are not clear about some part.

And keep up the humor! :smiley:

Thank you for your answers Srijal97!

I have so many questions :slight_smile:

I understand the float and char part, and what they represent. But I'm not entirely sure where I should place your code. Do I place it under "case: 1" or do I replace "case: 1" with the code? Or is it to be placed over the void loop and void setup? What do I do with the "int readFromPC()" and the switch, do I delete it? The code you wrote, is it supposed to go inside the case: 1 (four times, one time per operation) or replace it?

Sorry about the integer part, I probably just explained it bad/wrong. I know int uses 2 bytes and has a range from -32768 to 32767. This is the first part in my arduino cookbook I bookmarked. I just meant that I wanted decimals. In my head whole numbers meant numbers without decimals. But, yeah, I'm on page with you here now!

About the last part of your first post, does that mean I have to make an insane amount of "potential" functions. Just simply make num1, num2, num3, num4 and switch them around in hundreds of different positions with different operators and parentheses place all over the place?

I will try the Reset idea, and I will let you know if I don't manage to make it work :smiley:

Thanks again, and I translated and attached a photo of the serial monitor as it looks now.

btw, the "Karma" button on the left side, is that some sort of "thank you"? Cause you surely deserve one!

Boltup:
I understand the float and char part, and what they represent. But I'm not entirely sure where I should place your code. Do I place it under "case: 1" or do I replace "case: 1" with the code? Or is it to be placed over the void loop and void setup? What do I do with the "int readFromPC()" and the switch, do I delete it? The code you wrote, is it supposed to go inside the case: 1 (four times, one time per operation) or replace it?

First of all, the code I wrote is incomplete, and you have to write similar cases for every operator you want to use. As you can see, the function simply takes two numbers(float), the operation to be performed, does the operation and returns the answer. Now, in your current code, you select which operation you want initially, enter the number, and get the result. What I'm saying is, combine all operations in a single mode, so get rid of all your cases. You write the code in the following manner:
1- ask user to enter first number (operand), take it and store as float
2- ask user to enter operator (+,-,*,/,^), take it and store as char
3- ask user to enter second operand, store as float
4- call the function and pass the values, print result - the function takes care of the operation based on the operator passed.
The function definition will be placed above setup() and loop() and rest everything in loop().

Boltup:
About the last part of your first post, does that mean I have to make an insane amount of "potential" functions. Just simply make num1, num2, num3, num4 and switch them around in hundreds of different positions with different operators and parentheses place all over the place?

You'll have to make an insane amount of if/else statements and possibly functions and keep switching them here and there. As I said earlier, running this on an Arduino will limit your options. It would be better if you write a pure C++ code on a C++ IDE.

And yes, that's what karma is :slight_smile: