I haven't done much programming with Arduino, compared to my previous projects this one is kind of a major one.

I have one of these DIY Filament extruder , I am trying to add Filament puller and filament diameter sensor to create a closed loop system which would give a controlled diameter tolerance. Inspired by 3Devo filament extruder

I am using a Digital caliper to measure the diameter. I have written code to read the diameter and send it over to Serial if value is different that the previous one, and use this a s Input to PID, compare it with Setpoint and produce output, that will be used to control the speed of DC motor.

I can read the caliper data(Sometimes there're glitches). I decided to add a 16x2 LCD so that I can view the measured diameter and in later stage add a rotary encode, so that I could change Kp, Ki, Kd and Setpoint values.

But when added code to display the measured diameter on LCD, both Serial and LCD data are incorrect and changes rapidly. With out LCD code, Serial terminal displays same reading as shown in Caliper display.

with LCD code commented out Without LCD code

with LCD code Without LCD code

Here's the code,

//Digital caliper code to read the value off of a cheap set of digital calipers
//By Making Stuff Youtube channel https://www.youtube.com/c/makingstuff
//This code is open source and in the public domain.

#include <PID_v1.h>

// include the library code:
#include <LiquidCrystal.h>
//#include <LiquidCrystal_I2C.h>

#define PIN_OUTPUT 5    // To motor driver

//Define Variables we'll be connecting to
double Setpoint, Input, Output;
uint8_t SampleTime = 20;

// PID MIN & MAX output values
#define MIN   50
#define MAX   255

//Specify the links and initial tuning parameters
double Kp = 2, Ki = 5, Kd = 1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, REVERSE);

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 6, en = 7, d4 = 8, d5 = 9, d6 = 10, d7 = 11;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

const byte clockPin = 2;  //attach to clock pin on calipers
const byte dataPin = 3; //attach to data pin on calipers

//Milliseconds to wait until starting a new value
//This can be a different value depending on which flavor caliper you are using.
const int cycleTime = 32;

unsigned volatile int clockFlag = 0;

long now = 0;
long lastInterrupt = 0;
long value = 0;

float finalValue = 0;
float previousValue = 0;

int newValue = 0;
int sign = 1;
int currentBit = 1;

uint8_t previousOutput = 0;

void setup() {

  pinMode(clockPin, INPUT);
  pinMode(dataPin, INPUT);

  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);

  //We have to take the value on the RISING edge instead of FALLING
  //because it is possible that the first bit will be missed and this
  //causes the value to be off by .01mm.
  attachInterrupt(digitalPinToInterrupt(clockPin), clockISR, RISING);

  //initialize the variables we're linked to
  Setpoint = 1.75;    // Required diameter of filament
  //turn the PID on
  myPID.SetOutputLimits(MIN, MAX);

void loop() {

  if (newValue)
    if (finalValue != previousValue) {
      previousValue = finalValue;
      Serial.println(finalValue, 2);
    newValue = 0;

  //The ISR Can't handle the arduino command millis()
  //because it uses interrupts to count. The ISR will
  //set the clockFlag and the clockFlag will trigger
  //a call the decode routine outside of an ISR.
  if (clockFlag == 1)
    clockFlag = 0;

  Input = finalValue;
  analogWrite(PIN_OUTPUT, Output);

  //lcd.setCursor(0, 1);

void decode() {
  unsigned char dataIn;
  dataIn = digitalRead(dataPin);

  now = millis();

  if ((now - lastInterrupt) > cycleTime)
    finalValue = (value * sign) / 100.00;
    currentBit = 0;
    value = 0;
    sign = 1;
    newValue = 1;
  else if (currentBit < 16 )

    if (dataIn == 0)
      if (currentBit < 16) {
        value |= 1 << currentBit;
      else if (currentBit == 20) {
        sign = -1;




  lastInterrupt = now;


void clockISR() {
  clockFlag = 1;

Even uncommenting

lcd.setCursor(0, 1);

causes error in reading ?

Why is that?

My doubt is that, delay in LCD functions cause this.

So I thought about using I2C based LCD, but now I think it would be much slower that current one(i2c at 100 KHz).

Here's some useful links if needed :

Reading Digital Calipers This is the code I used. I used BC548 to convert 1.5V from Caliper to 5V. I didn't need to modify anything else to read data.

My Caliper data is same as shown in this site(I checked using DSO)

I also have few doubts,

  1. I have seen some people using Stepper motor instead of DC motor. 3Devo also uses stepper motor, any idea why is that??

  2. I don't know anything about selecting suitable micro-controller for a given project. I had Arduino UNO, so I used it. Is Arduino UNO enough for this? I mean regarding processing speed and everything. According to my current planning, even if I use rotary encoder, pins are enough. I know a little bit AVR register level programming. once I finish the project using Arduino, I could try to write by accessing Registers instead of using libraries. I think that would optimize the code, eve if it's not, it would be great learning practise

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.