Building a simple calculator using potentiometer and pushbuttons only

Dear Arduino Community,

I am writing to ask for your help in this confusing assignment that I have got in my first year of university.

I have been learning Arduino uno using C and C++ languages for 2 weeks now.

Our teacher has given us an assignment. This assignment, requires us to do the following:

This is a special calculator without a keypad, but it is using the rich shield. It uses one button (left button) and
the potentiometer for input, and the four LEDs and the 4-digit display for output.
 The values, operator and result are shown on the display. The value 1 and value 2 are shown as integer values between -10 and 10. The result is shown as a floating point value with one decimal point
(e.g. 1.2 or 1.6). The operator is one of the characters ‘a’ (add), ‘s’ (subtract), ‘t’ (times), ‘d’ (divide)
for respectively ‘+’, ‘-‘, ‘*’ and ‘/’; the display does not support these symbols.
 The button is used to switch between four modes: (1) input value 1, (2) input operator, (3) input
value 2 and (4) output result. The user can repeatedly press the button to alternate the modes in a
cyclic fashion (1)  (2)  (3)  (4)  (1)  (2)  etc.
 In modes (1), (2) and (3) the blue LED is on. The other LEDs are off.
 In mode (1) and (3), the potentiometer is used to choose a value between -10 and 10 by turning theEmbedded Systems Oriented Assignment 1
2 / 2
potentiometer. The centre of the potentiometer should be 0. Tip: Use the map() function to map the
potentiometer values to useful integer values.
 In mode (2), the potentiometer is used to choose ‘a’, ‘s’, ‘t’ and ‘d’ by turning the potentiometer.
 In mode (4),
 the yellow LED is on when the result does not perfectly fit on the display;
 the red LED is on when the result cannot be calculated, e.g. 6 / 0. In this case the display
should show “Err ”;
 the green LED is on when the yellow and red LEDs are off;
 the blue LED is off.
 The calculator should only react on pressing buttons and not holding buttons.
The interaction sequence of the calculator is described as follows:
1. After turning on the calculator, the display shows “ - - - -". The user must press the button to turn on
the calculator. After pressing the button, all four LEDs light up for 2 seconds.
2. Then the display shows the first value. The value is associated to the angle of the potentiometer. By
turning the potentiometer, the value can be changed. The calculator is in input value 1 mode (1).
3. After pressing the button again, the value is selected and the calculator goes into input operator
mode (2). The first operator ‘p’ is shown. The user can switch between the operators using the potentiometer; ‘a’ (0-25%), ‘s’ (25-50%), ‘t’ (50-75%) and ‘d’ (75-100%).
4. After pressing the button again, the displayed operator is selected, and the calculator goes into the
input value 2 (3) mode. The value is associated to the angle of the potentiometer.
5. After pressing the button, the value is selected, and the calculator will calculate the result.
6. After pressing the button, all LEDs are off and the calculator starts again at step 2.

I don't know if this is a lot for you Arduino Community, but for a person like me who has just started learning Arduino, I find this really challenging.

This is my code so far and I have been stuck for days on how to toggle a button to a potentiometer range in order to choose from value 1, 2, operation and the outcome OR at least press a button to pick a value from the potentiometer range (range of numbers)

CODE:

#include "Display.h"
const int potpin = 14;
const int max_potvalue = 10;
const int min_potvalue = -10;
const int BUTTON2 = 9;
/*int firstnum;
  int secondnum;
  char add = 'a';
  char subtract = 's';
  char multiply = 't';
  char divide = 'd';
*/

void setup()
{
  pinMode(potpin, INPUT); //pinMode(BUTTON2, INPUT)
}

int knobvalue1()
{
  int value1 = analogRead(potpin);
  int range1 = map(value1, 0, 1023, min_potvalue, max_potvalue);
  return range1;
}
/*char knobvalue2()
  {
  char value2 = analogRead(potpin);
  char range2 = map(value2, add, subtract, multiply, divide);
  return range2;
  }
*/


void loop()
{ int range1 = knobvalue1();
  Display.show(range1);
  delay(50);

  /*char range2 = knobvalue2
    Display.show(

you have a hint

Tip: Use the map() function to map the potentiometer values to useful integer values.

If this is your first project after 2 weeks, that's already pretty hard, depends what you've seen and if you have been spending full weeks on arduino or just an hour here and there.
(EDIT: seems there is a library for your shield abstracting many of the feature --> use that)

I've found the rich Shield pinout is described here

Pinout

Description               Pin

Potentiometer            A0
NTC temperature sensor    A1
Light dependent resistor  A2
voltage sensor            A3
Infrared reciever        D3
Buzzer                    D4
LED1 (RED)                D5
LED2 (GREEN)              D6
LED3 (BLUE)              D7
LED4 (YELLOW)            D8
KEY0 (K1)                D9
KEY1 (K2)                D10
CLK (TM1637)              D11
DIO (TM1637)              D12
DHT11                    D13

Try this and look at the result in the serial monitor (set at 115200 bauds)

const byte potentiometerPin = A0; // same as pin 14 on UNO but more portable

void setup() {
  Serial.begin(115200);
}

void loop() {
  int potValue = analogRead(potentiometerPin);
  int selectionValue = map(potValue, 0, 1024, 0, 4); // 1024 won't be possible, so 4 is not possible
  Serial.print(potValue);
  Serial.write('\t');
  Serial.println(selectionValue);
  delay(100);
}

————

Please correct your post above and add code tags around your code:

[code]

[color=blue]// your code is here[/color]

[/code]

.

It should look like this:

// your code is here

(Also press ctrl-T (PC) or cmd-T (Mac) in the IDE before copying to indent your code properly)

Dear J-M-L,

Please have a look at my code again, this is my first time using arduino forums, my apologies.

I did use the potentiometer and the range of values from -10 to 10 works perfectly, now the question do I need a serial print in this assignment?

As far as I am concerned, I still need buttons to push, in order to assign a value when doing simple calculations ;/

oso5v8m:
I did use the potentiometer and the range of values from -10 to 10 works perfectly, now the question do I need a serial print in this assignment?

no you don't - that was to give you an idea how the potentiometer could help you get a value between 0 and 3 --> 4 choices, just like what you need for 'a', 's', 't' and 'd'

As far as I am concerned, I still need buttons to push, in order to assign a value when doing simple calculations

well you need more than that. You need a way to sequence the 4 actions and capture input. that could be with a small state machine.

Your 2 buttons are on pin 9 and 10. do you have access to their examples and library? there is one called L6_KEY_Debounce that will show you how to handle a button

Thank you J-M-L,

I still need to figure out how to use CHAR (characters) to range them in a potetiometer.

But, first I need to understand the mechanism of how to toggle one button at least into assigning a value for value 1 or 2. If I understand that, I might be able to continue with my assignment.

Here is a debounce key example from the library: Key 1 and 2 are there to increase and decrease 1 number in my 4-digit display. However, I want the key 1 or 2 to choose a number and not increase or decrease it

#include "Display.h"

const int PIN_KEY1 = 9;
const int PIN_KEY2 = 8;

const int BOUNCE_DELAY = 50; // in ms

int count = 0;
int oldcount = 0;

// The button inputs are reverse (high = released, low = pressed)
int lastkey1state = HIGH;
int lastkey2state = HIGH;
int key1state = HIGH;
int key2state = HIGH;
int lasttime = 0;

void setup()
{
  pinMode(PIN_KEY1, INPUT_PULLUP);
  pinMode(PIN_KEY2, INPUT_PULLUP);
  Display.show(count);
}

int read_key()
{
  int key = 0;
  int key1 = digitalRead(PIN_KEY1);
  int key2 = digitalRead(PIN_KEY2);

  if (key1 != lastkey1state)
  {
    lasttime = millis();
  }
  if (key2 != lastkey2state)
  {
    lasttime = millis();
  }

  if (millis() - lasttime > BOUNCE_DELAY) {

    if (key1state != key1) {
      key1state = key1;
      if (lastkey1state == LOW)
        key = 1;
    }
    if (key2state != key2) {
      key2state = key2;
      if (lastkey2state == LOW)
        key = 2;
    }
  }
  lastkey1state = key1;
  lastkey2state = key2;
  return key;
}

void loop()
{
  int key = read_key();

  if (key == 1)
    count++;
  else if (key == 2)
    count--;

  if (oldcount != count) {
    Display.show(count);
    oldcount = count;
  }
}

oso5v8m:
I still need to figure out how to use CHAR (characters) to range them in a potetiometer.

well do you really need those? you can't display them anyway... so any number is good enough...

But if you want to know, did you study arrays ?

const byte potentiometerPin = A0; // same as pin 14 on UNO but more portable
const char operations[] = {'a', 's', 't', 'd'};

void setup() {
  Serial.begin(115200);
}

void loop() {
  int potValue = analogRead(potentiometerPin);
  int selectionValue = map(potValue, 0, 1024, 0, 4); // 1024 won't be possible, so 4 is not possible
  Serial.print(potValue);
  Serial.write('\t');
  Serial.print(selectionValue);
  Serial.write('\t');
  Serial.print(operations[selectionValue]);
  delay(100);
}

I want the key 1 or 2 to choose a number and not increase or decrease it

well you need one button act as a validation of a step in the sequence.

You should first try to describe in plain English what you want the code to do:

(stage1) the potentiometer is used to select a value between -10 and +10
a press on a button gets you to stage 2

(stage2) the potentiometer is used to...
a press on a button gets you to stage 3

(stage3) ....
a press on a button gets you to stage 4

(stage4) ....
a press on a button gets you to stage 1

void loop() {

  //stage1
  while ( button is not pressed) {
    potentiometer is used to select a value between - 10 and + 10
  }
  // here button has been pressed (mind bouncing)

  //stage 2
  while ( button is not pressed) {
    potentiometer is used to select ...
  }
  // here button has been pressed (mind bouncing)

  //stage 3
  while ( button is not pressed) {
    potentiometer is used to select ...
  }
  // here button has been pressed (mind bouncing)

  //stage 4
  ...


}

Thank you once again for your help JML,

I believe that I do need to put the 4 operations in the 4-digit display. And unfortunately, I have not studied arrays yet. But, do you think it is possible to range them in a map? Or only numeric values can be ranged in the display and not the serial monitor?

I will take a look and analyze your code on arrays, because I still need to apply my methods on the display instead of serial monitor.

If I may ask, why are you using while instead of if. Logically, I might use 'while' at the beginning to wait for the user to assign a value through the potentiometer, but after that (a button needs to be pressed and if not then we can use while...)

oso5v8m:
I believe that I do need to put the 4 operations in the 4-digit display.

from your specification:

The operator is one of the characters 'a' (add), 's' (subtract), 't' (times), 'd' (divide) for respectively '+', '-', '*' and '/'; the display does not support these symbols.

so I'm unsure what to display... may be you need to create a representation using the 7 segments... what did the teacher say ? have you done any of this before ?

If I may ask, why are you using while instead of if. Logically, I might use 'while' at the beginning to wait for the user to assign a value through the potentiometer, but after that (a button needs to be pressed and if not then we can use while...)

I'm using while to say 'as long as the button is not pressed, I'm staying in stage #x where 'this' is happening' --> for example in stage 1, until you press the button, the display should update constantly the value of the potentiometer mapped between -10 and 10.

The 4-digit display does not support the following symbols not characters: +,-,* and /.

As a result, we students should show the following characters: a, s, t and d in the 4 digit display.

Unfortunately, I am really new to arduino and programming languages and our teacher did not teach us any of that yet, but this assignment has to be submitted in 10 days.

I have noticed something in your codes and I hope I am not losing my mind here, why did you create a map and stages(while) function inside a loop(local function), is my code wrong in this case? Because I did add the potentiometer function outside both, setup and loop functions (as a global function)

int knobvalue1()
{
  int value1 = analogRead(potpin);
  int range1 = map(value1, 0, 1023, min_potvalue, max_potvalue);
  return range1;

I feel like I am confused, do I add this inside the loop function in order to link the stages to the map or outside ;/?

you are trying to rush to the final stage but you don't understand the basics... it won't work;

you need to split your task in easy steps that you can practice with

  • display a, s, t and d
  • identify when a button is pressed
  • turn on a LED

then sequence those, for example switch from a to s to t to d when you press a button

etc...

Thank you J-M-L,

I sometimes overcomplicate things, I will stick to your advice and keep you up to date with my development.

J-M-L:
you are trying to rush to the final stage but you don't understand the basics... it won't work;

you need to split your task in easy steps that you can practice with

  • display a, s, t and d
  • identify when a button is pressed
  • turn on a LED

then sequence those, for example switch from a to s to t to d when you press a button

etc...

Hello JML, i apologize for the delay in my response, I have been busy in the last few days trying to solve the assignment.

To begin with, I have been able to display a, s, t or d but not all of them at once as a group of operations or you can call them array.

second, i have identified when a button is pressed (HIGH is the nature of button when it is not pressed due to its reversible logic and LOW is when the button is pressed)

third, i am also able to turn on/off a led by pulling it up when pressing a button.

Please take a look at this simple piece of code

#include"Display.h"

const int button1 = 8;
int buttonstatus;
const int greenLED = 5;

void setup()
{
  pinMode(greenLED, OUTPUT);
  pinMode(button1, INPUT_PULLUP);
}

void loop()
{
  buttonstatus = digitalRead(button1);
  if (buttonstatus == LOW)
  {
    digitalWrite(greenLED, HIGH);
  }
  else
  {
    digitalWrite(greenLED, LOW);
  }


}

Now my problem is with the sequencing(connecting or linking let us say 4 LEDs into 4 stages or the characters of operation into 4 stages)

Is it possible to use if statement with else instead of switch and case method?

Thank you once again for your help, this assignment has been solved.

Let me know if you want me to share some of the tricks or codes for audience as reference

All the best!

sorry just saw the post now... glad you were able to solve it !