Hi all,
I'm making a force-deflection device using an arduino UNO, a spring-return rotary encoder for deflection measurements, a load cell for force measurement, and a serial-enabled LCD to display results.
My digital rotary encoder currently is currently using interrupts, and was working quite nicely, HOWEVER, when I added the LCD code to it, it now struggles to "keep up". It seems like pulses are being skipped by the interrupts, and I have played around with the hardware enough to feel confident that it's a software issue.
Can y'all take a look at this code and see where things are interfering with one another? I want to make sure the encoder doesn't skip steps even when it's turned quickly.
//Include necessary libraries
#include "HX711.h" //must install bogde's HX711 library, available at https://github.com/bogde/HX711
#include "math.h" //included in arduino program download
#include "SoftwareSerial.h" //included in arduino program download
#define DOUT 5 //define data out pin
#define CLK 4 //define clock pin
#define txPin 6 //define transmitter pin for serial LCD
#define tare_Pin 9 //pin for manual taring
HX711 scale(DOUT, CLK); //initialize HX711 class called "scale" with pin specifications
SoftwareSerial LCD(0, txPin); //initialize SoftwareSerial class called "LCD" with pin specifications
//Variables
int pull_Position = 0; //the position of the pull cord
int A_SIG = 0; //square wave initial signals
int B_SIG = 0;
float mm_Reading; //variables for distance and scale reading
float scale_Reading;
float last_mm_Reading = 0;
float last_Scale_Reading = 0;
char load[7];
char distance[7];
//Constants
const byte num_Readings = 1; //average number of readings for weighing (leave as 1)
const byte dec_Pts = 1; //display this number of decimal points
const float scale_Calibration_Factor = 3440; //calibration factor, obtained with calibration script here: https://learn.sparkfun.com/tutorials/load-cell-amplifier-hx711-breakout-hookup-guide (saved as v5 calibration)
//******************************************** a higher calibration factor will result in lower readings at a given load and vice versa
const int distance_Calibration_Factor = 1293; //reading of pull_Position at calibration_Distance eg. 100mm
const int calibration_Distance = 100; //distance at which distance_Calibration_Factor pull position reading was taken (mm)
const int LCDdelay = 2; // conservative, 2ms works
//Run once at start of machine
void setup()
{
attachInterrupt(digitalPinToInterrupt(2), A_RISE, RISING); //attach interrupts to pins 2 and 3 for digital distance encoder
attachInterrupt(digitalPinToInterrupt(3), B_RISE, RISING);
LCD.begin(9600); //initialize LCD serial communication
pinMode(tare_Pin, INPUT); //initialize tare_Pin as an output
pinMode(tare_Pin, INPUT_PULLUP); //turn on pull up resistor to tie pin signal to high when button isn't pressed
pinMode(txPin, OUTPUT); //initialize LCD pin
scale.set_scale(scale_Calibration_Factor); //calibrate scale
scale.tare(); //reset the scale to 0
pull_Position = 0; //reset the distance encoder to 0
clearLCD(); //clear LCD
backlightOn();
lcdPosition(0, 3);
LCD.print("WELCOME TO");
lcdPosition(1, 2);
LCD.print("TESTING MODE");
delay(2000);
clearLCD();
/*(while(digitalRead(selection_Button_Pin) == HIGH)
{
//MENU SELECTION CODE GOES HERE -- NEED TO USE ROTARY ENCODER WITH INTERNAL BUTTON FOR SELECTION
}*/
//print initial dummy values
lcdPosition(0, 0);
LCD.print("LOAD: 0.0");
lcdPosition(1, 0);
LCD.print("DEFL: 0.0");
}
void loop()
{
//Get weight and distance readings
scale_Reading = fabs(scale.get_units(num_Readings));
mm_Reading = (float)pull_Position / distance_Calibration_Factor * calibration_Distance;
//Check if tare button is pressed
if (digitalRead(tare_Pin) == LOW)
{
scale.tare(); //reset measurements
pull_Position = 0;
}
//LCD printing
if (fabs(scale_Reading - last_Scale_Reading) >= 0.05)
{
lcdPosition(0, 7); //clear load reading
LCD.print(" ");
lcdPosition(0, 7); //print new load reading
LCD.print(dtostrf(scale_Reading, 7, 1, load));
}
if (fabs(mm_Reading - last_mm_Reading) >= 0.05)
{
lcdPosition(1, 7); //clear distance reading
LCD.print(" ");
lcdPosition(1, 7); //print new distance reading
LCD.print(dtostrf(mm_Reading, 7, 1, distance));
}
last_Scale_Reading = scale_Reading;
last_mm_Reading = mm_Reading;
}
//LCD Functions
void lcdPosition(int row, int col)
{
LCD.write(0xFE); //command flag for setting position
LCD.write((col + row * 64 + 128)); //set position
delay(LCDdelay);
}
void clearLCD()
{
LCD.write(0xFE); //command flag for setting position
LCD.write(0x01); //clear command
delay(LCDdelay);
}
void backlightOn() //turns on the backlight
{
LCD.write(0x7C); //command flag for backlight level
LCD.write(157); //set light level.
delay(LCDdelay);
}
void backlightOff() //turns off the backlight
{
LCD.write(0x7C); //command flag for backlight level
LCD.write(128); //light level for off.
delay(LCDdelay);
}
void serCommand() { //a general function to call the command flag for issuing all other commands
LCD.write(0xFE);
}
//Interrupt functions for distance encoder
void A_RISE()
{
detachInterrupt(digitalPinToInterrupt(2));
A_SIG = 1;
if (B_SIG == 1)
{
pull_Position++;//moving forward
}
else
{
pull_Position--;//moving reverse
}
attachInterrupt(digitalPinToInterrupt(2), A_FALL, FALLING);
}
void A_FALL()
{
detachInterrupt(digitalPinToInterrupt(2));
A_SIG = 0;
if (B_SIG == 0)
{
pull_Position++;//moving forward
}
else
{
pull_Position--;//moving reverse
}
attachInterrupt(digitalPinToInterrupt(2), A_RISE, RISING);
}
void B_RISE()
{
detachInterrupt(digitalPinToInterrupt(3));
B_SIG = 1;
if (A_SIG == 0)
{
pull_Position++;//moving forward
}
else
{
pull_Position--;//moving reverse
}
attachInterrupt(digitalPinToInterrupt(3), B_FALL, FALLING); \
}
void B_FALL()
{
detachInterrupt(digitalPinToInterrupt(3));
B_SIG = 0;
if (A_SIG == 1)
{
pull_Position++;//moving forward
}
else
{
pull_Position--;//moving reverse
}
attachInterrupt(digitalPinToInterrupt(3), B_RISE, RISING);
}
I don't really know what I'm doing with this stuff, so any help will be much appreciated! Thanks,
Leo