Ron T.
Published © GPL3+

Low Cost 10LC RPN calculator

You can build a 10LC RPN (reverse Polish notation) calculator for about $40 with the M5 Stack Cardputer, a micro SD card and some stickers.

IntermediateFull instructions provided1 hour55
Low Cost 10LC RPN calculator

Things used in this project

Hardware components

Cardputer
M5Stack Cardputer
×1
micro sd card
×1
sticker paper
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Code

10LC Arduino code

C/C++
To build and upload the code to the M5Stack Cardputer, first get the Arduino IDE at https://www.arduino.cc/en/software/

To setup Arduino to work with the M5Stack Cardputer, the first step is to follow the Arduino board management guidelines at:
https://docs.m5stack.com/en/arduino/arduino_board

The next step is to add the cardputer library. See https://docs.m5stack.com/en/arduino/m5cardputer/program

You can try uploading the display example before creating a new project that uses the source code below. Make sure you have the correct board and port settings in the Tools pulldown menu.
/** 10LC calculator
 copyright R. Tanikawa 2025
v. 0.90
 */

#include "M5Cardputer.h"
#include "math.h"
#include "SD.h"
#include "Complex.h"

int tones=0;
double mults=0;
int colr=0;
int fontz=0;
int keys;
int expp=0;
double num=0;
double num1=0;
int shifts=0;
int ans=0;
double stos[12]={0,0,0,0,0,0,0,0,0,0,0,0};
int pc=0;
int beeps=0;
int pgm[102];
int pgm1[102];
int mode=0;
int decm=0;
int gotos=0;
int scientif=0;
int scidigs=0;
int signs=1;
int idles=0;
int codes1=0;
double slope=0;
double intc=0;
int angles=0;
int gotosflag=0;
double lastx=0;
int stoper=0;
int secs=0;
int dispFlag=0;

//int zz=c_sqrt(3);
// 1=normal shift, 2=sto 3=rcl  5=exp 6=exp2 7=gto1 8=gto2 9=fix 10=sci 11=eng

double stacks[4]={0,0,0,0};
char strs[100];
//char keyz[42]="234567890-wertyuiop[asdfghjkl;@zxcvbnm,. ";
char keyz[46]="-234567890[wertyuiop;asdfgbjkl.@zxcvhnm,=/]' ";
int fixs=5;

void clearPgm() {
  int i;

  for (i=1; i<100; ++i)
    pgm[i]=2200;
  pgm[0]=0;
}

void clearDsp() {
M5Cardputer.Display.fillRect(0,0,240,135,BLACK);
}
double tohms(double a) {
  int i;
  double fp,temp;
  long a1;
  int minutes,seconds;
  int divs;
  Serial.println(a*3600);
//  temp=fmod(fp,fp);
  seconds=(int)(3600.0*modf(a,&temp)+0.5);
 // divs=(int)a;
  //seconds=(int)((a*3600.0)-(3600.0*divs)+0.5);
//  (int)(a*3600.0)(int)(a*3600) % 3600;
Serial.println(seconds);
//  a1=(int)a;
//  fp=a-a1;
//Serial.println("%f",fp);
//  seconds=fp*3600;
  minutes=(int)(seconds/60);
  seconds=(int)(seconds) % 60;

//  seconds=(int)(60*((60*fp)-(int)(60*fp)));

  return (int)a+(minutes/100.0)+(seconds/10000.0);
}


double tohours(double a) {
  int minutes,seconds;
  long a1;
  double fp;

  a1=10000*a;
  seconds=(int)a1 % 100;
  a1=a1/100;
  minutes=(int)a1 % 100;
/*  fp=a-a1;
  minutes=(int)(fp*100);
  
  fp=fp*100;
  seconds=(int)((fp-minutes)*100); */
  Serial.println(minutes);
  Serial.println(seconds);
  return (int)a+(minutes/60.0)+(seconds/3600.0);
}



double facts(float a) {
  double prod=1.0;
  int i;

  for (i=(int)a; i>1; --i)
    prod=prod*i;
  return prod;
}

void rolldown(){
  double temp;
  temp=num;
  stacks[0]=stacks[1];
  stacks[1]=stacks[2];
  stacks[2]=stacks[3];
  stacks[3]=temp;
  dispNum(stacks[0]);
  num=stacks[0];
  ans=1;
}
void pushx(double val){
  stacks[3]=stacks[2];
  stacks[2]=stacks[1];
  stacks[1]=val;
  stacks[0]=val;
}
void stacklift(double val){
  stacks[3]=stacks[2];
  stacks[2]=stacks[1];
  stacks[1]=stacks[0];
  stacks[0]=val;
}
  
void popx(){
  stacks[1]=stacks[2];
  stacks[2]=stacks[3];
}

void clearReg(){
  int i;
  for (i=0; i<10; ++i)
    stos[i]=0;
  for (i=0; i<4; ++i)
    stacks[i]=0;
  num=0;
  dispNum(0);
  ans=1;
}
void setup() {
    int i;
    
    char strs1[]=".         ";
    char xx;


    Serial.begin(9600);
     i=M5Cardputer.Power.getBatteryLevel();
    Serial.println(i);
    i=M5Cardputer.Power.getBatteryVoltage();
    Serial.println(i);
    for (i=0; i<100; ++i)
      pgm[i]=2200;
    auto cfg = M5.config();
    M5Cardputer.begin(cfg, true);



    M5Cardputer.Display.setRotation(1);
    M5Cardputer.Display.setTextColor(GREEN);
    M5Cardputer.Display.setTextDatum(middle_left);
    M5Cardputer.Display.setTextFont(&fonts::FreeSerifBold18pt7b);
    M5Cardputer.Display.setTextSize(1);
    M5Cardputer.Display.drawString("10LC calculator",
                                   0,
                                   M5Cardputer.Display.height() / 2);
    M5Cardputer.Display.setTextFont(&fonts::FreeSerif9pt7b);
    M5Cardputer.Display.drawString("ver. 0.9",100,90);

  fileReads();
 pgm[0]=0;
 fileReads1();
 num=stacks[0];
    dispNum(num);
    ans=1;

 
}

void fileWrites() {
  int i;
  char strs1[]="                      ";
  SD.begin();
  File files=SD.open("/test9.txt",FILE_WRITE);

  if (files==NULL) {
    SD.end();
    return;
  }
  for (i=0; i<100; ++i) {
    sprintf(strs1,"%d",pgm[i]);
    files.println(strs1);
    delay(5); }

  files.close();
  SD.end();

}

void fileWrites1() {
  int i;
  char strs1[]="                      ";
  SD.begin();
  File files=SD.open("/test8.txt",FILE_WRITE);
  if (files==NULL) {
    SD.end();
    return;
  }
  for (i=0; i<10; ++i) {
    sprintf(strs1,"%e",stos[i]);
    files.println(strs1); }
  for (i=0; i<4; ++i) {
    sprintf(strs1,"%e",stacks[i]);
    files.println(strs1); }
  sprintf(strs1,"%d",fixs);
  files.println(strs1);

  sprintf(strs1,"%d",scientif);
  files.println(strs1);

  sprintf(strs1,"%d",scidigs);
  files.println(strs1);

  sprintf(strs1,"%d",fontz);
  files.println(strs1);

  sprintf(strs1,"%d",beeps);
  files.println(strs1);

  sprintf(strs1,"%d",colr);
  files.println(strs1);


  files.close();
  SD.end();
//fixs,scientif,scidigs,fontz,beeps,colr
}
void fileReads() {
  int xx;
  int i,j,k;
  char strs[]="                    ";

  j=0;
  k=0;
  SD.begin();
  File files=SD.open("/test9.txt",FILE_READ);
  if (files==NULL)
    return;
for (i=0; i<1000; ++i) {
  xx=files.read();
//  Serial.println(xx);
 
  if (xx==-1)
    break;
  if (xx!=13) {
  strs[j]=xx;
  j+=1;
  }else{
    xx=files.read();
//    Serial.println(xx);
    strs[j]=0;
    pgm[k]=atoi(strs);
//    Serial.println(strs);
    k+=1;
    if (k>99)
      break;
    j=0;
  }
  delay(1);
 } 
  files.close();
  SD.end();
}

void fileReads1() {
  int xx;
  int i,j,k;
  char strs[]="                          ";
  int stackmode=0;

  j=0;
  k=0;
  SD.begin();
  File files=SD.open("/test8.txt",FILE_READ);
  if (files==NULL)
    return;
for (i=0; i<200; ++i) {
  xx=files.read();
//  Serial.println(xx);
 
  if (xx==-1)
    break;
  if (xx!=13) {
  strs[j]=xx;
  j+=1;
  }else{
    xx=files.read();
//    Serial.println(xx);
    strs[j]=0;
    if (stackmode==0)
      sscanf(strs,"%lf",&stos[k]);
    else if (stackmode==1)
      if (k<4)
        sscanf(strs,"%lf",&stacks[k]);
      else {
        switch (k) {
          case 4:
            sscanf(strs,"%d",&fixs);
            break;
          case 5:
            sscanf(strs,"%d",&scientif);
            break;
          case 6:
            sscanf(strs,"%d",&scidigs);
            break;
          case 7:
            sscanf(strs,"%d",&fontz);
            break;
          case 8:
            sscanf(strs,"%d",&beeps);
            break;
          case 9:
            sscanf(strs,"%d",&colr);
            if (colr==0)
              M5Cardputer.Display.setTextColor(GREEN);
            else if (colr==1)
              M5Cardputer.Display.setTextColor(RED);
            else if (colr==2)
              M5Cardputer.Display.setTextColor(WHITE);
            break;
          default:
            break;
        }
        
      }
    

//    stos[k]=atof(strs);
    Serial.println(strs);
    k+=1;
    if (k==10) {
      stackmode=1;
      k=0;
    }
    j=0;
  }
  delay(1);
 } 
 files.close();
  SD.end();
}
int proKeys() {
  int i;
  char strs1[]="                        ";

  for (i=0; i<44; ++i)
    if (M5Cardputer.Keyboard.isKeyPressed(keyz[i]))
      return i;
  return -1;
}

int parseNum(int keys) {
  switch (keys) {
    case 7:
      return 7;
    case 8:
      return 8;
    case 9:
      return 9;
    case 17:
      return 4;
    case 18:
      return 5;
    case 19:
      return 6;
    case 27:
      return 1;
    case 28:
      return 2;
    case 29:

      return 3;
    case 37:
      return 0;
    default:
      return -1;
  }
  return -1;
}
int parseKey(int keys) {
  double temp;
  int i;
  char strs[]="               ";

  switch (keys) {
    case 7:
      return 7;
    case 8:
      return 8;
    case 9:
      return 9;
    case 17:
      return 4;
    case 18:
      return 5;
    case 19:
      return 6;
    case 27:
      return 1;
    case 28:
       return 2;
    case 29:
      return 3;
    case 37:
      return 0;
//DECIMAL POINT
    case 38:
      decm=2;
      mults=0.1;
      
      return 48;
//ADD
    case 30:
      lastx=num;
      num=num+stacks[1];
      popx();
      stacks[0]=num;
      
      dispNum(num);
      ans=1;
      return 40;
 //ENTER
    case 26:
 //     lastx=num;
      pushx(num);
      num1=num;
 //     num=0;
      dispNum(num);
      decm=0;
      ans=2;
      shifts=0;
      return 36;
    case 1:
      if (num<0)
        errors(0);
      else {
      lastx=num;
      num=sqrt(num);
      stacks[0]=num;
      dispNum(num);
      ans=1;
      }
      return 11;
    case 2:
      lastx=num;
      num=exp(num);
      stacks[0]=num;
      dispNum(num);
      ans=1;
      return 12;
    case 3:
      lastx=num;
      num=pow(10,num);
      stacks[0]=num;
      dispNum(num);
      ans=1;
      return 13;
    case 4:
      if ((stacks[1]==0) && (num<=0))
        errors(0);
      else if ((stacks[1]<0) && ((num-int(num))!=0))
        errors(0);
      else {
      lastx=num;
      num=pow(stacks[1],num);
      popx();
      stacks[0]=num;
      dispNum(num);
      ans=1;
      }
      return 14;
    case 5:
      if (num==0)
        errors(0);
      else {
      lastx=num;
      num=1/num;
      stacks[0]=num;
      dispNum(num);
      ans=1;
      }
      return 15;
    case 6:
      num=-num;
      stacks[0]=num;
      dispNum(num);
      ans=1;
      return 16;
    case 0:
      
      if (num==0)
        errors(0);
      else {
      lastx=num;
      num=stacks[1]/num;
      popx();
      stacks[0]=num;
      dispNum(num);
      ans=1;
      }
      return 109;
//percent - STACKLIFT?
    case 11:
      lastx=num;
      num=num*0.01*stacks[1];
      dispNum(num);
      ans=1;
      return 21;
//GOTO
    case 12:
      shifts=7;
      M5Cardputer.Display.setTextFont(&fonts::FreeSerif9pt7b);
      M5Cardputer.Display.drawString("gto",90,120);
      M5Cardputer.Display.setTextFont(&fonts::FreeSerif18pt7b);
      return 22;
    case 13:
      switch (angles) {
        case 0:
          num=sin(num*3.14159265359/180.0);
          break;
        case 1:
          num=sin(num);
          break;
        case 2:
          num=sin(num*3.14159265359/200.0);
          break;
      }
      
      stacks[0]=num;
      dispNum(num);
      ans=1;
      return 23;
    case 14:
      lastx=num;
      switch (angles) {
        case 0:
          num=cos(num*3.14159265359/180.0);
          break;
        case 1:
          num=cos(num);
          break;
        case 2:
          num=cos(num*3.14159265359/200.0);
          break;
      }
      
      stacks[0]=num;
      dispNum(num);
      ans=1;
      return 24;
    case 15:
      lastx=num;
      switch (angles) {
        case 0:
          num=tan(num*3.14159265359/180.0);
          break;
        case 1:
          num=tan(num);
          break;
        case 2:
          num=tan(num*3.14159265359/200.0);
          break;
      }
      
      stacks[0]=num;
      dispNum(num);
      ans=1;
      return 25;
    case 10:
      lastx=num;
      num=stacks[1]*num;
      popx();
      stacks[0]=num;
      dispNum(num);
      ans=1;
      return 20;
    case 20:
      lastx=num;
      num=stacks[1]-num;
      popx();
      stacks[0]=num;
      dispNum(num);
      ans=1;
      return 30;
// RUN
    case 21:
      if (mode!=1) {
        mode=2;
//        stacks[0]=num;
        ans=1;
      }
      return 31;
// SST
    case 22:
      if (pc==0)
        pc=1;
      showProgram(pgm[pc]);
      delay(1000);
      doProgLine(pgm[pc]);
      
      
      return 132;
// rolldown
    case 23:
      rolldown();
      return 133;
// x<>y
    case 24:
      temp=num;
      stacks[0]=stacks[1];
      stacks[1]=temp;
      num=stacks[0];
      dispNum(num);
      ans=2;
      return 134;
//clx
    case 25:
      num=0;
      stacks[0]=0;
      dispNum(num);
      ans=2;
      return 135;
    case 36:
      num=lastx;
      stacks[0]=num;
      dispNum(num);
      ans=2;
      return 36;
//Exponent
    case 16:
      shifts=5;
      Serial.println("expon");
      return 26;
// PROG
    case 33:
      mode=1;
        //M5Cardputer.Display.clear();
        clearDsp();
        sprintf(strs,"%d-%d",pc,pgm[pc]);
  M5Cardputer.Display.drawString(strs,15,90);
      return 43;
//STO
    case 34:
      shifts=2;
      stoper=0;
      return 44;
//RCL
    case 35:
      shifts=3;
      return 45;   
//SHIFT
    case 32:
      shifts=1;
      M5Cardputer.Display.setTextFont(&fonts::FreeSerif9pt7b);
      M5Cardputer.Display.drawString("f",10,120);
      M5Cardputer.Display.setTextFont(&fonts::FreeSerif18pt7b);
      return 42;
// sum +
    case 39:
      lastx=num;
      stos[0]+=1;
      stos[1]+=num;
      stos[2]+=num*num;
      stos[3]+=stacks[1];
      stos[4]+=stacks[1]*stacks[1];
      stos[5]+=num*stacks[1];
      dispNum(stos[0]);
      num=stos[0];
      stacks[0]=num;
      ans=2;
      return 149;
    case 40:
      fontz=(fontz+1) % 2;
      dispNum(num);
      return 150;
    case 41:
      stacks[0]=num;
      fileWrites();
      fileWrites1();
      M5Cardputer.Power.powerOff();
      return 151;
    case 42:
      colr=(colr+1) % 3;
      if (colr==0)
        M5Cardputer.Display.setTextColor(GREEN);
      else if (colr==1)
        M5Cardputer.Display.setTextColor(RED);
      else if (colr==2)
        M5Cardputer.Display.setTextColor(WHITE);
      dispNum(num);
      return 152;
    case 43:
      beeps=(beeps+1) % 2;
      return 153;
    default:
      return -1;
  }
  return -1;
}

// non working tangent algorithm
double tan3(double a) {
  return 0;
}

int parseShift(int keys) {
  double temp,temp1;
  double i;

  Serial.println("shift");
  switch (keys) {
    case 1:
      lastx=num;
      num=num*num;
      stacks[0]=num;
      dispNum(num);
      ans=1;
      shifts=0;
      return 111;
    case 2:
      if (num<=0)
        errors(0);
      else {
      lastx=num;
      num=log(num);
      stacks[0]=num;
      dispNum(num);
      ans=1;
      }
      shifts=0;
      return 112;
    case 3:
      if (num<=0) 
        errors(0);
      else {
      lastx=num;
      num=log10(num);
      stacks[0]=num;
      dispNum(num);
      ans=1;
      }
      shifts=0;
      return 113;
    case 4:
      lastx=num;
      num=tohms(num);
      stacks[0]=num;
      dispNum(num);
      ans=1;
      shifts=0;
      return 114;
    case 5:
      lastx=num;
      num=tohours(num);
      stacks[0]=num;
      dispNum(num);
      ans=1;
      shifts=0;
      return 115;
    case 6:
      stacks[0]=num;
//      stacklift(num);
      num=3.14159265359;
      stacklift(num);
//      stacks[0]=num;
      dispNum(num);
      ans=1;
      shifts=0;
      return 116;
    case 7:
      Serial.println("FIX");
      shifts=9;
      scientif=0;
      
      return 117;
    case 8:
      shifts=10;
      scientif=1;
      return 118;
// p->r
    case 11:
      lastx=num;
      switch(angles) {
        case 0:
          stacks[1]=stacks[1]*3.14159265359/180.0;
          break;
        case 2:
          stacks[1]=stacks[1]*3.14159265359/200.0;
          break;
      }
      temp=num*sin(stacks[1]);
      temp1=num*cos(stacks[1]);
      stacks[1]=temp;
      stacks[0]=temp1;
      num=temp1;
      dispNum(num);
      ans=1;
      shifts=0;
      return 121;

// R->P, quad 2,3,4 case
    case 12:
      lastx=num;
    Serial.println("r-p");
      temp=sqrt(num*num+stacks[1]*stacks[1]);
      if (num==0) {
        if (stacks[1]>0)
          stacks[1]=3.14159265359/2.0;
        else
          stacks[1]=-3.14159265359/2.0;
      }
      else {
//Quadrant 1       
        if ((stacks[1]>=0) && (num>0))
          stacks[1]=atan(stacks[1]/num);
// Quadrant 3
        else if ((stacks[1]<=0) && (num<0))
          stacks[1]=atan(stacks[1]/num)-3.14159265359;
// Quadrant 4
        else if ((stacks[1]<=0) && (num>0))
          stacks[1]=atan(stacks[1]/num);
        else
// Quadrant 2
          stacks[1]=atan(stacks[1]/num)+3.14159265359;
      }
      num=temp;
      switch (angles) {
        case 0:
          stacks[1]=stacks[1]*180/3.14159265359;
          break;
        case 2:
          stacks[1]=stacks[1]*200/3.14159265359;
          break;
      }
      dispNum(num);
      ans=1;
      shifts=0;
      return 121;
    case 13:
      if (abs(num)>1)
        errors(0);
      else {
      lastx=num;
      num=asin(num);
      switch (angles) {
        case 0:
          num=num*180/3.14159265359;
          break;
        case 2:
          num=num*200/3.14159265359;
          break;
      }
      stacks[0]=num;
      dispNum(num);
      ans=1;
      }
      shifts=0;
      return 123;
    case 14:
      if (abs(num)>1)
        errors(0);
      else {
      lastx=num;
      num=acos(num);
      switch (angles) {
        case 0:
          num=num*180/3.14159265359;
          break;
        case 2:
          num=num*200/3.14159265359;
          break;
      }
      stacks[0]=num;
      dispNum(num);
      ans=1;
      }
      shifts=0;
      return 124;
    case 15:
      lastx=num;
      num=atan(num);
      switch (angles) {
        case 0:
          num=num*180/3.14159265359;
          break;
        case 2:
          num=num*200/3.14159265359;
          break;
      }
      stacks[0]=num;
      dispNum(num);
      ans=1;
      shifts=0;
      return 125;
    case 16:
      if ((num<0) || (modf(num,&i)!=0))
        errors(0);
      else {
      lastx=num;
      num=facts(num);
      stacks[0]=num;
      dispNum(num);
      ans=1;
      }
      shifts=0;
      return 126;
    case 17:
      angles=0;
      shifts=0;
      dispNum(num);
      return 127;
    case 18:
      angles=1;
      shifts=0;
      dispNum(num);
      return 128;
    case 19:
      angles=2;
      shifts=0;
      dispNum(num);
      return 129;
// to radians
    case 20:
      lastx=num;
      num=num*3.14159265359/180.0;
      stacks[0]=num;
      ans=1;
      shifts=0;
      dispNum(num);
      return 130;
// Pause
    case 21:
      shifts=0;
      dispNum(num);
      return 131;
    case 22:
      shifts=0;
      dispNum(num);
      return 132;
    case 23:
      clearPgm();
      pc=0;
      dispNum(num);
      shifts=0;
      return 133;
    case 24:
      clearReg();
      dispNum(num);
      shifts=0;
      return 134;
//clear prefix
    case 25:
      dispNum(num);
      shifts=0;
      return 135;
    case 27:
      if ((stos[0]<=1) || (slope==0) || ((stos[0]*stos[2]-(stos[1]*stos[1]))==0) || ((stos[0]*stos[4]-(stos[3]*stos[3]))==0) )
        errors(1);
      else {
      lastx=num;
// y=mx+b, x=(y-b)/m
      num=(num-intc)/slope;
      stacks[1]=(stos[0]*stos[5]-(stos[1]*stos[3]))/sqrt((stos[0]*stos[2]-(stos[1]*stos[1]))*(stos[0]*stos[4]-(stos[3]*stos[3])));
      dispNum(num);
      ans=1;
      }
      shifts=0;
      return 137;
    case 28:
      if ((stos[0]<=1) || ((stos[0]*stos[2]-(stos[1]*stos[1]))==0) || ((stos[0]*stos[4]-(stos[3]*stos[3]))==0))
        errors(1);
      else {
...

This file has been truncated, please download it to see its full contents.

Credits

Ron T.
3 projects • 0 followers

Comments