Hackster is hosting Impact Spotlights: Robotics. Watch the stream live on Thursday!Hackster is hosting Impact Spotlights: Robotics. Stream on Thursday!
Ron T.
Published © GPL3+

Low Cost 32LC RPN calculator

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

IntermediateWork in progress1 hour48
Low Cost 32LC 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

32LC 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.
/** 32LC calculator
 copyright R. Tanikawa 2025
v. 0.92
 */

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

char menuz[125][20]={"a:IP","b:FP","c:RN","d:ABS","","a:DG","b:RD","c:GR","","",
"a:FX","b:SC","c:ALL","","","a:cX","b:cVARS","c:cPrg","d:cSum","",
"a:rec->pol","b:pol->rec","","","","a:->HR","b:->HMS","","","",
"a:->DEG","b:->RAD","","","","a:DEC","b:HX","c:OC","d:BN","",
"a:LBL","b:RTN","c:PSE","","","a:DSE","b:ISG","","","",
"a:SF","b:CF","c:FS?","","","a:x?y","b:x?0","","","",
"a:x!=y","b:x<y","c:x>y","d:x=y","","a:x!=0","b:x<0","c:x>0","d:x=0","",
"a:FN","b:SOLVE","c:Intgrt","","","a:sum","b:mnX,Y","c:s","d:LR","",
"a:sx","b:sy","","","","a:predX","b:predY","c:r","d:m","e:b",
"a:Cn,r","b:Pn,r","c:x!","d:RANDOM","e:SEED","a:RANDOM","b:SEED","","","",
"a:VAR","b:PGM","","","","a:mnX","b:mnY","c:mnXw","","",
"a:n","b:x","c:y","d:x^2","e:y^2","f:xy"};

char cmds[100][20]={"SQRT","e^x","ln","y^x","1/x","sum+","7","8","9","/",
"STO","RCL","RLDN","SIN","COS","TAN","4","5","6","x",
"SST","XEQ","x<>y","CHS","E","BSP","1","2","3","-",
"","C","shift","","","ENTER","0",".","R/S","+",
"X^2","10^X","LOG","%","%CHG","sum-","","","","",
"CMPX","PI","HYP","ASIN","ACOS","ATAN","","","","",
"BST","GTO","","","","","","","","",
"","OFF","","","","LASTx","INPUT","SHOW","PRGM","VIEW",
"SINH","COSH","TANH","ASINH","ACOSH","ATANH"};

//char alphas[35]="234567WERTYUSDFG890IOPJKLNM,.;[-";
int alphas[35]={0,1,2,3,4,5,10,11,12,13,14,15,21,22,23,24,6,7,8,16,17,18,26,27,28,36,37,38,39,29,19,9};
int sizes[24]={4,3,3,4,2,2,2,4,3,2,
3,2,4,4,3,4,2,5,5,2, 2,3,6};

double stats[6];

int cmdd=0;
int flags;
int intsolv=0;
int menunum=0;
int tones=0;
double mults=0;
double rnums=0.3857162904;
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[28]={0,0,0,0,0,0,0,0,0,0,0,0};
int pc=0;
int beeps=0;
int pgm[1500];
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 solvemode=0;
int fnum=0;
int solvar=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[asdfghjkl;@zxcvbnm,. ";
int fixs=5;

void clearPgm() {
  int i;

  for (i=0; i<1500; ++i)
    pgm[i]=38;
  for (i=0; i<26; ++i)
    pgm[100+50*i]=4000+i;
  pgm[0]=38;
}

void clearDsp() {
M5Cardputer.Display.fillRect(0,0,240,135,BLACK);
}

double tohms(double a) {
  int i;
  double fp,temp;
  long a1;
  int minutes;
  double seconds;
  int divs;
  Serial.println(a*3600);
//  temp=fmod(fp,fp);
  seconds=3600.0*modf(a,&temp);
 // 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=fmod(seconds,60);

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

  return temp+(minutes/100.0)+(seconds/10000.0);
}


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

  fp=a*100.0;
  seconds=modf(fp,&temp)/36.0;
//  a1=10000*a;
//  seconds=(int)a1 % 100;
//  a1=a1/100;
  minutes=fmod(temp,100.0);
/*  fp=a-a1;
  minutes=(int)(fp*100);
  
  fp=fp*100;
  seconds=(int)((fp-minutes)*100); */
  Serial.println(minutes);
  Serial.println(seconds);
  modf(a,&temp);
  return temp+(minutes/60.0)+(seconds);
}

void solves() { //secant solver method
  double x0=-8;
  double x1=0;
  
  double e=0.000000001;
  int N=20;
  int step=0;
  double x=0;
  double f0;
  double f1;
  double x2;
  double f2;
  int count=0;

  x0=stacks[0];
  x1=stacks[1];
  intsolv=1;
  if (x0==x1) {
    x1+=15.0;
    x0-=30.0;
  }
  solvemode=1;
//  mode=2;
  while (count<50) {
    count++;
    x=x0;
    pc=100+fnum*50;
    stos[solvar]=x;
//    mode=2;
    runProgram();
    
    f0=num;

    x=x1;
    pc=100+fnum*50;
    stos[solvar]=x;
//    mode=2;
    runProgram();
    f1=num;

    if (f0==f1) {
      intsolv=0;
      //M5Cardputer.Display.clear();
      clearDsp();

      M5Cardputer.Display.setTextFont(&fonts::FreeSerif18pt7b);
      M5Cardputer.Display.drawString("Error:  g1=g2",15,90);
//      Serial.println("Math error");
      mode=0;
      return;
    }
    x2=(x0*f1-x1*f0)/(f1-f0);
    x0=x1;
    x1=x2;
    stos[solvar]=x2;
    pc=100+fnum*50;
//    mode=2;
    runProgram();
    f2=num;
      
 //Serial.println(f0);
      

      
    step = step + 1;
      
    if (step > N) {
      intsolv=0;
      //M5Cardputer.Display.clear();
      clearDsp();
      M5Cardputer.Display.setTextFont(&fonts::FreeSerif18pt7b);
      M5Cardputer.Display.drawString("not convergent",15,90);
//      Serial.println("no convergence");
      solvemode=0;
      mode=0;

      return;
    }
    if (fabs(f2)<=e)
      break;
  }
//    Serial.println(x2);
    intsolv=0;
    if (count==50) {
      //M5Cardputer.Display.clear();
      clearDsp();
      M5Cardputer.Display.setTextFont(&fonts::FreeSerif18pt7b);
      M5Cardputer.Display.drawString("solution not found",15,90);
    } else {
    num=x2;
    stacks[0]=num;
    ans=1;

    dispNum(num);
    }
    mode=0;
    
    solvemode=0;
    
    return;
}


void integrate(){
  long int n,i;
  double a,b,h,x,sum=0,integ;
  double fa,fb;
  char msg[20];
 
 intsolv=1;
 if (scientif)
  n=int(pow(10,(scidigs+3)/2));
 else
  n=int(pow(10,(fixs+3)/2));

  if ((n % 2)!=0)
    n+=1;
//n=100;
a=stacks[1];
b=stacks[0];

  h=abs(b-a)/n;
  for(i=1;i<n;i++){

    if ((i%10000)==0) {
      sprintf(msg,"integrating %d",i/10000);
      //M5Cardputer.Display.clear();
      clearDsp();
      M5Cardputer.Display.drawString(msg,15,40);
    }

    M5Cardputer.update();
    if(M5Cardputer.Keyboard.isChange()) {
      
      mode=0;
      ans=1;
      stacks[0]=num;
      break;
      
    }
    x=a+i*h;
    if(i%2==0){
      pc=100+fnum*50;
      stos[solvar]=x;
 //     mode=2;
      runProgram();
      sum=sum+2*num;
    }
    else{
      pc=100+fnum*50;
      stos[solvar]=x;
//      mode=2;
      runProgram();
      sum=sum+4*num;
    }
  }
  pc=100+fnum*50;
  stos[solvar]=a;
//  mode=2;
  runProgram();
  fa=num;

  pc=100+fnum*50;
  stos[solvar]=b;
//  mode=2;
  runProgram();
  intsolv=0;
  fb=num;
  integ=(h/3)*(fa+fb+sum);
   /*Print the answer */
   Serial.println(integ);
   num=integ;
   dispNum(num);
//  text(toString(integral),5,5);
}


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<27; ++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;

//    double xxx;

    Serial.begin(9600);

/*    if (isinf(xxx))
      Serial.println("infinite"); */

     i=M5Cardputer.Power.getBatteryLevel();
    Serial.println(i);
    i=M5Cardputer.Power.getBatteryVoltage();
    Serial.println(i);
    for (i=0; i<100; ++i)
      pgm[i]=38;
    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("32LC calculator",
                                   0,
                                   M5Cardputer.Display.height() / 2);
    M5Cardputer.Display.setTextFont(&fonts::FreeSerif9pt7b);
    M5Cardputer.Display.drawString("ver. 0.92",100,90);

  fileReads();
 pgm[0]=38;
 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<1500; ++i) {
    sprintf(strs1,"%d",pgm[i]);
    files.println(strs1);
    delay(1); }

  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<26; ++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<8000; ++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>1499)
      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<2600; ++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==26) {
      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 parseAlpha(int keys) {
  int i;

  for (i=0; i<32; ++i)
    if (keys==alphas[i])
      return i;
  return -1;
} 
int parseNum(int keys) {
  switch (keys) {
    case 6:
      return 7;
    case 7:
      return 8;
    case 8:
      return 9;
    case 16:
      return 4;
    case 17:
      return 5;
    case 18:
      return 6;
    case 26:
      return 1;
    case 27:
      return 2;
    case 28:

      return 3;
    case 36:
      return 0;
    default:
      return -1;
  }
  return -1;
}
// for PROG mode, this is not used
int parseKey(int keys) {
  double temp,temp1;
  int i;
  char strs[]="               ";

  switch (keys) {
    case 6:
      return 7;
    case 7:
      return 8;
    case 8:
      return 9;
    case 16:
      return 4;
    case 17:
      return 5;
    case 18:
      return 6;
    case 26:
      return 1;
    case 27:
       return 2;
    case 28:
      return 3;
    case 36:
      return 0;
//DECIMAL POINT
    case 37:
      decm=2;
      mults=0.1;
      
      return 48;
//ADD
    case 39:
      lastx=num;
      num=num+stacks[1];
      popx();
      stacks[0]=num;
      
      dispNum(num);
      ans=1;
      
      return 40;
 //ENTER
    case 35:
 //     lastx=num;
      pushx(num);
      num1=num;
 //     num=0;
      dispNum(num);
      decm=0;
      ans=2;
      shifts=0;
      return 36;
    case 0:
      if (num<0)
        errors(0);
      else {
      lastx=num;
      num=sqrt(num);
      stacks[0]=num;
      dispNum(num);
      ans=1;
      }
      return 11;
    case 1:
      lastx=num;
      num=exp(num);
      stacks[0]=num;
      dispNum(num);
      ans=1;
      return 12;
    case 2:
      if (num<=0)
        errors(0);
      else {
      lastx=num;
      num=log(num);
      stacks[0]=num;
      dispNum(num);
      ans=1;
      }
      
      return 112;

    case 3:
      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 4:
      if (num==0)
        errors(0);
      else {
      lastx=num;
      num=1/num;
      stacks[0]=num;
      dispNum(num);
      ans=1;
      }
      return 15;
    case 23:
      lastx=num;
      num=-num;
      stacks[0]=num;
      dispNum(num);
      ans=1;
      return 16;
    case 9:
      
      if (num==0)
        errors(0);
      else {
      lastx=num;
      num=stacks[1]/num;
      popx();
      stacks[0]=num;
      dispNum(num);
      ans=1;
      }
      return 109;

    case 13:
      lastx=num;
      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 19:
      lastx=num;
      num=stacks[1]*num;
      popx();
      stacks[0]=num;
      dispNum(num);
      ans=1;
      return 20;
    case 29:
      lastx=num;
      num=stacks[1]-num;
      popx();
      stacks[0]=num;
      dispNum(num);
      ans=1;
      return 30;
// RUN
    case 38:
      if (mode!=1) {
        mode=2;
//        stacks[0]=num;
        ans=1;
      }
      return 31;
// SST
    case 20:
      if (pc==0)
        pc=1;
      showProgram(pgm[pc]);
      delay(1000);
      Serial.println(pgm[pc]);
      doProgLine(pgm[pc]);
      
      
      return 132;
// rolldown
    case 12:
      rolldown();
      return 133;
    case 21: //XEQ
      dispCmd(21);
      shifts=12;
      return 121;
// x<>y
    case 22:
      temp=num;
      stacks[0]=stacks[1];
      stacks[1]=temp;
      num=stacks[0];
      dispNum(num);
      ans=1;
      return 134;
//bksp
    case 25:
      if (decm) {
        if (mults>=0.1)
          return -1;
        temp=modf(num/(mults*100),&temp1);
        num=temp1*(mults*100);
        mults=mults*10;
        dispNum(num);
 //       ans=2;
      }
      else {
        temp=modf(num/10,&temp1);
        num=temp1;
        dispNum(num);
//        ans=2;
      }
      
      return 135;
    case 97:
      num=lastx;
      stacks[0]=num;
      dispNum(num);
      ans=2;
      return 36;
//Exponent
    case 24:
      shifts=5;
      doexponent();
/*      shifts=5;
      Serial.println("expon"); */
      return 26;
// PROG
/*    case 33:
      mode=1;
        M5Cardputer.Display.clear();
        sprintf(strs,"%d-%d",pc,pgm[pc]);
  M5Cardputer.Display.drawString(strs,15,90);
      return 43; */
//STO
    case 10:
    Serial.println("sto");
      dispCmd(10);
      shifts=2;
      stoper=0;
      dosto();
      return 44;
//RCL
    case 11:
      dispCmd(11);
      shifts=3;
      dorcl();
      return 45;
    case 31:
      num=0;
      stacks[0]=0;
      ans=1;
      dispNum(num);
      return 31;   
//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 5:
      lastx=num;
      stats[0]+=1;
      stats[1]+=num;
      stats[3]+=num*num;
      stats[2]+=stacks[1];
      stats[4]+=stacks[1]*stacks[1];
      stats[5]+=num*stacks[1];
      dispNum(stats[0]);
      num=stats[0];
      stacks[0]=num;
      ans=2;
      return 149;
    case 33:
      fontz=(fontz+1) % 2;
      dispNum(num);
      return 150;


    case 34:
      beeps=(beeps+1) % 2;
      return 153;
    default:
      return -1;
  }
  return -1;
}



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

  Serial.println("shift");
  switch (keys) {
    case 0: 
      shifts=0;
      if (mode==1) {
        cmdd=40;
        return 40;
      }   
      lastx=num;
      num=num*num;
      stacks[0]=num;
      dispNum(num);
      ans=1;
      
      cmdd=40;
      return 111;
    case 1:
      shifts=0;
      if (mode==1) {
        cmdd=41;
...

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

Credits

Ron T.
3 projects • 0 followers

Comments