I am trying to piece together something to control how much water to fill a container with using a rotary encoder, water solenoid, and flow meter. The problem I am having right now is the LCD gets garbled messages if I turn the rotary encoder with the flow meter code on. If I comment out the flow meter code everything else works correctly and the display doesn't get messed up.
Here is my code:
/*
Arduino Connections:
*** LCD ***
- 1 (Gnd) to GND
- 2 (Vcc) to +5V
- 3 (VO) to Potentiometer Center (Wiper)
- 4 (RS) to digital pin 7
- 5 (R/W) to ground
- 6 (Enable) pin to digital pin 8
- 11 (D4) to digital pin 9
- 12 (D5) to digital pin 10
- 13 (D6) to digital pin 11
- 14 (D7) to digital pin 12
- 10K Potentiometer one end to +5V one to GND
*** Rotary Encoder ***
- 1 (B) to Digital Pin 2 (YEL)
- 2 (Common) to GND (BLK)
- 3 (A) to Digital Pin 4 (GRN)
- 5 (SwitchA) to Ground
- 6 (SwitchB) to A0
*** Flow Meter ***
- Yellow (Signal) to Digital Pin 3 (Interrupt)
- Black to GND
- Red to +5V
*/
// 20x4 LCD Setup
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
// Encoder Pins and default value setup
#define encoder0PinA 2
#define encoder0PinB 4
#define encoderInterrupt 0
volatile float encoder0Pos = 0;
// Button Varibles
const int buttonPin = A1; // the number of the pushbutton pin
const int BUTTON1 = 1; // Rotary Encoder - 67 ohms = Set Value
const int BUTTON2 = 2; // Red 1 - 384 ohms = Reset Desired and Set values
const int BUTTON3 = 3; // Red 2 - 4.8K = Add 2.5 gallons to Desired
const int BUTTON4 = 4; // Red 3 - 5.5k (Larger variance would be better) = Reset Total Amount/
const int BUTTON1LOW = 1012; // Tolerance is +/- 4 of what I was reading
const int BUTTON1HIGH = 1020;
const int BUTTON2LOW = 982;
const int BUTTON2HIGH = 990;
const int BUTTON3LOW = 686;
const int BUTTON3HIGH = 694;
const int BUTTON4LOW = 655;
const int BUTTON4HIGH = 663;
// Variables will change:
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin
// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0; // the last time the output pin was toggled
long debounceDelay = 50; // the debounce time; increase if the output flickers
// Water values
volatile float desiredFillAmount = 0; // Default value for how much to fill the kettles
// Water flow meter
byte sensorInterrupt = 1; // 0 = pin 2; 1 = pin 3
byte sensorPin = 3;
volatile byte pulseCount;
unsigned long oldTime;
// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
// liter/minute of flow.
float calibrationFactor = 4.5;
float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitresA;
unsigned long totalMilliLitresB;
float flowRateGallons;
float flowGallons;
float totalGallons;
float literToGallons = 3.78541; // Liters in a gallon
void setup() {
// LCD Setup / Default Displays
lcd.begin(20, 4);
lcd.setCursor(0,0);
lcd.print("Desired: 0.00 Gal");
lcd.setCursor(0,1);
lcd.print(" Set: 0.00 Gal");
lcd.setCursor(0,2);
lcd.print(" Total: 0.00 Gal");
lcd.setCursor(0,3);
lcd.print(" Rate: 0.00 G/min");
// Encoder setup
pinMode(encoder0PinA, INPUT);
digitalWrite(encoder0PinA, HIGH); // turn on pullup resistor
pinMode(encoder0PinB, INPUT);
digitalWrite(encoder0PinB, HIGH); // turn on pullup resistor
attachInterrupt(encoderInterrupt, doEncoderA, CHANGE); // encoder pin on interrupt 0 - pin 2
// Button Setup
pinMode(buttonPin, INPUT);
// Flow Meter setup
pinMode(sensorPin, INPUT);
digitalWrite(sensorPin, HIGH);
pulseCount = 0;
flowRate = 0.0;
oldTime = 0;
flowRateGallons = 0.0;
flowGallons = 0;
totalGallons = 0;
// The Hall-effect sensor is connected to pin 3 which uses interrupt 1.
// Configured to trigger on a FALLING state change (transition from HIGH
// state to LOW state)
attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}
void loop() {
// Start Button Code
int reading = analogRead(buttonPin);
int tmpButtonState = LOW; // the current reading from the input pin
if(reading>BUTTON4LOW && reading<BUTTON4HIGH){
tmpButtonState = BUTTON4; //Read switch 4
}else if(reading>BUTTON3LOW && reading<BUTTON3HIGH){
tmpButtonState = BUTTON3; //Read switch 3
}else if(reading>BUTTON2LOW && reading<BUTTON2HIGH){
tmpButtonState = BUTTON2; //Read switch 2
}else if(reading>BUTTON1LOW && reading<BUTTON1HIGH){
tmpButtonState = BUTTON1; //Read switch 1
}else{
tmpButtonState = LOW; //No button is pressed;
}
if (tmpButtonState != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
buttonState = tmpButtonState;
}
lastButtonState = tmpButtonState;
switch(buttonState){
case BUTTON1: // Rotary Encoder (Set)
desiredFillAmount = encoder0Pos; // Set the desired amount to what the encoder is at
lcd.setCursor(13,1);
lcd.print(" ");
lcd.setCursor(9,1);
lcd.print(desiredFillAmount);
break;
case BUTTON2: // Red 1 - Reset Desired & Set amount
desiredFillAmount = 0; // Set the desired back at 0
encoder0Pos = 0; // Reset encoder count
lcd.setCursor(9,0);
lcd.print(encoder0Pos);
lcd.setCursor(9,1);
lcd.print(desiredFillAmount);
break;
case BUTTON3: // Add 2.5 Gallons to the desired amount to help count faster
// This doesn't work correctly and needs a delay or something so it only adds 2.5 per press..might just remove for now
encoder0Pos += 2.5;
lcd.setCursor(9,0);
lcd.print(encoder0Pos);
break;
case BUTTON4: // Reset current amount to 0
totalGallons = 0;
lcd.setCursor(9,2);
lcd.print(totalGallons);
break;
}
// End Button Code
// Start Flow Meter Code
if((millis() - oldTime) > 1000) // Only process counters once per second
{
// Disable the interrupt while calculating flow rate and sending the value to
// the host
detachInterrupt(sensorInterrupt);
// Because this loop may not complete in exactly 1 second intervals we calculate
// the number of milliseconds that have passed since the last execution and use
// that to scale the output. We also apply the calibrationFactor to scale the output
// based on the number of pulses per second per units of measure (litres/minute in
// this case) coming from the sensor.
flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
flowRateGallons = (flowRate / literToGallons);
// Note the time this processing pass was executed. Note that because we've
// disabled interrupts the millis() function won't actually be incrementing right
// at this point, but it will still return the value it was set to just before
// interrupts went away.
oldTime = millis();
// Reset the pulse counter so we can start incrementing again
pulseCount = 0;
// Enable the interrupt again now that we've finished sending output
attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
// Divide the flow rate in litres/minute by 60 to determine how many litres have
// passed through the sensor in this 1 second interval, then multiply by 1000 to
// convert to millilitres.
flowMilliLitres = (flowRate / 60) * 1000;
// Add the millilitres passed in this second to the cumulative total
flowGallons = (flowRateGallons / 60) * literToGallons;
totalGallons += flowGallons;
//Output in gallons
lcd.setCursor(9, 2);
lcd.print(totalGallons / literToGallons); // Total amount
lcd.setCursor(7, 3);
lcd.print(flowRateGallons); // Current flow rate
lcd.print(" ");
}
// End Flow Meter Code
}
// Start encoder read function
void doEncoderA(){
// look for a low-to-high on channel A
if (digitalRead(encoder0PinA) == HIGH) {
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinB) == LOW) {
encoder0Pos = encoder0Pos + .004; // CW
}
else {
encoder0Pos = encoder0Pos - .004; // CCW
}
}
else // must be a high-to-low edge on channel A
{
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinB) == HIGH) {
encoder0Pos = encoder0Pos + .004; // CW
}
else {
encoder0Pos = encoder0Pos - .004; // CCW
}
}
if(encoder0Pos < 0) {
encoder0Pos = 0;
}
lcd.setCursor(13,0);
lcd.print(" ");
lcd.setCursor(9,0);
lcd.print(encoder0Pos);
}
// End encoder read function
// Start Flow Meter Function
void pulseCounter()
{
// Increment the pulse counter
pulseCount++;
}
// End Flow Meter function