Change decimal to fraction

Hi,

I have decimal code below, when I type the X number on keypad it moves the stepper as decimal inch to the X number , I need to make this 1/64 of an inch fractional, it can still move same as decimal but i need to type fraction for example 12 23/64" or maybe 12-23/64. I can assign keypad key A=/ and B=-
also second question is it possible to go below 0 to -12 23/64
thank you
Ozan.

#include <AccelStepper.h> // AccelStepper Library
#include <Keypad.h>  // Keypad Library
#include <LiquidCrystal_I2C.h>
#include <Wire.h>

#define I2C_ADDR 0x3F  // Add your address here.
#define Rs_pin 0
#define Rw_pin 1
#define En_pin 2
#define BACKLIGHT_PIN 3
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7

LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);

// Global variables
byte index = 0;
char numbers[16]; // Plenty to store a representation of a float

// Keypad Setup
const byte ROWS = 4;   // Four Rows
const byte COLS = 4;   // Four Columns
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', '.'}
};
byte rowPins[ROWS] = {22, 24, 26, 28}; // Arduino pins connected to the row pins of the keypad
byte colPins[COLS] = {31, 33, 35, 37}; // Arduino pins connected to the column pins of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );  // Keypad Library definition

// AccelStepper Setup
AccelStepper stepper(1, A2, A3);  // 1 = Easy Driver interface
// Arduino A2 connected to STEP pin of Easy Driver
// Arduino A3 connected to DIR pin of Easy Driver

static char outstr[15];
void setup(void) {

  float len = 000.000;

  //  AccelStepper speed and acceleration setup
  stepper.setMaxSpeed(22000);
  stepper.setAcceleration(10000);
  {
    lcd.begin (20, 4); //  our LCD is a 20x4, change for your LCD if needed

    // LCD Backlight ON
    lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE);
    lcd.setBacklight(HIGH);
  }
}


void loop()
{
  char key = keypad.getKey();
  if (key != NO_KEY)
    lcd.print(key);
    {
      if (key == 'C')
      {
        index = 0;
        numbers[index] = '\0';
      }
      else if (key == '.')
      {
        numbers[index++] = '.';
        numbers[index] = '\0';
      }
      else if (key >= '0' && key <= '9')
      {
        numbers[index++] = key;
        numbers[index] = '\0';
      }
      else if (key == '#')
      {
        float len = atof(numbers);        

        dtostrf(len, 7, 3, outstr);

        lcd.clear();
        lcd.setCursor (13, 3);
        lcd.print(outstr);

        stepper.runToNewPosition(len * 1354.666666665203627);      //  steps for 1 inch 

        index = 0;
        numbers[index] = '\0';

      }
    }
  }/code]

also second question is it possible to go below 0 to -12 23/64

Not if you define - as the separator between the whole number and the fractional part.

It would be far simpler to have the user input the value in 64ths of an inch - 791 64ths is 1223/64.

It is possible to assign the meaning “separator between the whole number and the fraction” to one key and “negate the value” to another key, and then do what you want. But, entering the number of 64ths of an inch to move is far simpler.

you can use sscanf()

example:

char myData[] = "12+32/64";
struct Measure{
  int inches;
  int numerator;
  int denominator;
};

void setup()
{
  Serial.begin(9600);
  Measure data;
  sscanf(myData, "%d+%d/%d" , &data.inches, &data.numerator, &data.denominator);
  Serial.println(data.inches);
  float value = float(data.inches) + float(data.numerator) / float(data.denominator);
  Serial.println(value);
}

void loop()
{
}

No reason to type the "/64" if the user understands the rules.

"12+32" could be understood as 12+32/64.

dtostrf converts a float to text. That’s not what you asked about :wink: You also don’t really need that function unless you insist on printing with a certain precision (always 3 digits).

@BulldogLowel showed you how you can convert an entered text with your specification; so the only thing you have to do is rewrite the code that collects the numbers to handle the ‘/’, the ‘+’ (or maybe a space) and the ‘-’ (for negative numbers)

The below loop() implementation handles that using a switch statement and using the serial port instead of lcd.

void loop()
{
  Measure data;
  float len;

  char key = keypad.getKey();

  switch (key)
  {
    case NO_KEY:
      break;
    case 'C':
      index = 0;
      numbers[index] = '\0';
      break;
    case '#':
      Serial.println();
      sscanf(numbers, "%d %d/%d" , &data.inches, &data.numerator, &data.denominator);
      if (data.inches >= 0)
        len = float(data.inches) + float(data.numerator) / float(data.denominator);
      else
        len = float(data.inches) - float(data.numerator) / float(data.denominator);

      Serial.print(data.inches); Serial.print(" ");
      Serial.print(data.numerator); Serial.print("/"); Serial.println(data.denominator);
      Serial.println(len);

      index = 0;
      numbers[index] = '\0';
      break;
    case '-':
      if (index == 0)
      {
        numbers[index++] = key;
        numbers[index] = '\0';
        Serial.print(key);
      }
      break;
    default:
      numbers[index++] = key;
      numbers[index] = '\0';
      Serial.print(key);
      break;
  }
}

Note that compared to @BulldogLowell’s code, I have used a space to separate whole inches from fractions. The code supports negative numbers.

I’ve changed the keypad layout a little

char keys[ROWS][COLS] =
{
  {'1', '2', '3', '-'},
  {'4', '5', '6', ' '},
  {'7', '8', '9', '/'},
  {'*', '0', '#', 'C'}
};

Honours go to @BulldogLowell; karma added :wink:

sterretje:
Honours go to @BulldogLowell; karma added :wink:

sscanf is a great tool that I almost always forget about!

**quid pro quo