I've been working on a project lately and it involves the lCD. It uses two while statements and in the main while statement, we incorporated a part in which the LCD displays values from one of our sensor pins. The valve and sensor work, but I can't get the LCD to display the values.
#include <LiquidCrystal.h>
LiquidCrystal lcd(2,3,4,5,11,12);
unsigned long previoustime = 0;
int goodmoisture = 850;
int notgoodmoisture = 900;
long halfday = 7200000;
const int valve = 8;
const int Sensorin = A0;
void setup () {
Serial.begin(9600);
pinMode(Sensorin, INPUT);
pinMode(valve, OUTPUT);
lcd.begin(16,2);
lcd.clear();
}
void loop() {
int Sensorreads = analogRead(Sensorin);
Serial.print(" The moistness is: ");
Serial.println(Sensorreads);
unsigned long Time = millis();
while(Sensorreads <= goodmoisture){
Serial.println(Sensorreads);
lcd.setCursor(0,0);
lcd.print("Moisture: ");
lcd.print(analogRead(Sensorin));
if (Time - previoustime > halfday) {
previoustime = Time;
// Timer For Valve
digitalWrite(valve, HIGH);
delay(50000);
digitalWrite(valve, LOW);
delay(30000);
// Valve Opening for 3 seconds
}
}
// Moisture Conditions
while (Sensorreads >= notgoodmoisture) {
Serial.println(Sensorreads);
digitalWrite(valve, HIGH);
delay(20000);
digitalWrite(valve, LOW);
}
}
I thought that the "Serial.println(Sensorreads);" would update the Sensorreads because I have it before and in the while statement because the Sensorreads is just analogRead(A0) which is my sensor pin.
I don't think the way you have set this program up is very good. The loop function on the arduino runs continuously so that negates the need to use the while loops.
Typically the way things are done is to call smaller functions from the loop. For example
int sensorReadingNow;
int sensorReadingPrev;
unsigned long LCDUpdateTime;
void setup(){
//set up your inputs and outputs etc.
}
void loop(){
readSensors();
updateLCD();
operateValve();
}
void readSensors(){
sensorReadingPrev = sensorReadingNow; //save your previous reading
sensorReadingNow = ; //read your sensor
}
void updateLCD(){
//you may only want to update your LCD if the sensor reading has changed
if(sensorReadingPrev != sensorReadingNow)
{
CODE TO UPDATE LCD
}
//or you may want to update the LCD every x seconds
if(millis() - LCDUpdateTime >= x000)
{
LCDUpdateTime = millis();
CODE TO UPDATE LCD
}
}
void operateValve(){
CODE TO OPEN AND CLOSE VALVE
}
If you write it this way, it is very easy to see by looking at your loop function what your code is doing, and what each part of the code does due to appropriately named functions. I couldn't figure out what your logic for your valve timing is so I left that for you to write.
It also makes your code a whole lot easier to maintain and add to in case you decide to tinker with your setup and add in other inputs and/or outputs.
I am not some magic wizard that somehow knows what code is uploaded to every Arduino in the world so even if for some reason I did mind if you copied my code, there isn't a thing I could do to stop you :). But the reason I typed it up was for you to help you out so of course you are free to do what you wish with it.
You are getting there. In my example code I gave you two options for how you wanted to choose to update the LCD. Either update it when the sensor reading changes, or update it after a certain period of time (it seems you chose 2 seconds). Since you went with the periodic change option, do you think you still need to keep track of the previous reading?
In the update LCD section, where is the cursor when you update the LCD? I haven't worked with LCDs since running through the tutorials quite a while ago. Also you are reading the sensor value to output it to the screen. Didn't you read the sensor elsewhere and have that value saved? Maybe it would be useful to use that.
Those delays in the bottom two functions will still cause issues with responsiveness. During the delay the arduino is doing nothing. So you get the same problem of the LCD not updating. And you can't read the sensor during this time. And if you connect other stuff in the future it can't interact with it either during this delay time.
Did you read those articles on the timing? Especially the first link in my last post regarding using millis() for timing. The concept used in the updateLCD() function is similar to what you should be using in your operateValve() function. The moistureConnection() is just a little bit trickier because we have to keep track of the state of the valve, so let's fix the operateValve() one first.
In the updateLCD() function, you do something after a certain period of time right? In the updateLCD() function that period is 2 seconds. In the operateValve that period is half a day. Do you see the similarity? Can you implement the same idea as updating the LCD to operating the valve periodically? I would suggest renaming the variable previoustime to something more descriptive. Previous time of what?
Can you also give us a description of your desired logic for the system? Is it to turn the valve on for 5 seconds every time the moisture reading is too low, and also to turn it on for 5 seconds regardless of the moisture twice a day?
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11,5, 4, 3, 2);
unsigned long previoustimeopening = 0;
int notgoodmoisture = 900;
unsigned long startMillis;
unsigned long currentMillis;
unsigned long halfday = 7200000;
const int valve = 8;
const int Sensorin = A0;
int sensorReadingNow;
int sensorReadingPrev;
unsigned long LCDUpdateTime;
int Time = millis;
void setup () {
Serial.begin(9600);
pinMode(Sensorin, INPUT);
pinMode(valve, OUTPUT);
lcd.begin(16,2);
lcd.clear();
startMillis = Time;
}
void loop(){
readSensors();
updateLCD();
operateValve();
Serial.print("The Moisture is: ");
Serial.println(sensorReadingNow);
}
void readSensors(){
sensorReadingPrev = sensorReadingNow;
sensorReadingNow = analogRead(A0);
}
void updateLCD(){
if(millis() - LCDUpdateTime >= 2000)
{
LCDUpdateTime = millis();
lcd.setCursor(0, 0);
lcd.print("Moisture: ");
lcd.print(sensorReadingNow);
}
}
void operateValve(){
if (Time - previoustimeopening > halfday) {
previoustimeopening = Time;
// Timer For Valve
digitalWrite(valve, HIGH);
digitalWrite(valve, LOW);
startMillis = currentMillis;
}
}
This is what my code is looking like right now, and I'm still pretty confused because all though I did everything you said, my LCD still isn't updating at all. I'm also pretty sure what I did for the valve operation is wrong. I'm not sure if I set up the millis correctly in relation to my timer. Also, I want to have my valve open every half day and for my sensor to collect values and display those values of moisture onto my LCD.
Please respond to this as soon as possible, and thank you so so much!!
Is your LCD not updating, or is it updating with the same value meaning that you can't see a change? I'm assuming you have this in soil? Try taking it out and putting it back in and see if you get a different value on the screen.
I am under the impression that you are randomly copying and pasting code without putting too much thought into the logic of how it works. I am also under the impression that you haven't read the article on using millis() for timing and also the one on doing several things at once.
The LCD just isn't showing anything and the sensorReadingPrev = sensorReadingNow; is important because if not for some reason the serial monitor states that the moisture is 0. For the digitalWrite(valve, HIGH);
digitalWrite(valve, LOW); I think I forgot the I'm not sure because I don't even know how to set up the timer, but I just wanted to have the valve open and then close. Also, I wanted to set millis to time (because this is a project) so people know what millis stands for.
Edit: I moved the millis delay up one:
GamerGang:
Also, I wanted to set millis to time (because this is a project) so people know what millis stands for.
So other people will be reading and using this code? Are you teaching a course or something?
I don't think this line
int Time = millis;
does what you think it does. The Time variable does not get automatically set to the millis() value. You have to tell it to update every time you want it to. And since you never update Time anywhere it would stay at the same value it was initially set to. Which frankly I don't know what that is because millis is a function and should be called like
millis();
You don't need to reinvent the wheel. Trying to do what you did for the sake of "clarity" just caused a bug.
So now in your code you have turned the valve on after half a day. But you then immediately turn it off again. What you want to do is to when you turn the valve on keep track of the state of the valve. You can do this by declaring a global variable for example valveOn. Since it can only be on or off, a bool would do fine for this.
So now that you know the time at which you turned the valve on, you now need to turn it off after your set period (I believe this is 5 seconds). Within your operateValve() function, but NOT inside the current if statement, you need another if statement. This if statement should check if the valve is on AND if the 5 seconds has elapsed. If that is true, then inside the if statement you want to turn the valve off and set the valveOn variable to an appropriate value.
void operateValve(){
if (Time - previoustimeopening > halfday) {
previoustimeopening = Time; //don't use Time
// Timer For Valve
digitalWrite(valve, HIGH);
startMillis = currentMillis; //bad variable naming. start of what?
digitalWrite(valve, LOW);//get rid of this, the valve will be turned off below
}
//if statement to check if you want to turn the valve off should go here
}
I'm not sure what is happening with your LCD. You mentioned that you weren't sure about your potentiometer. Could that be causing an issue?