Automated Gardening - maxing out the MEGA?

Hey everyone. Im making an automated gardening box. I have a 20x4 LCD to display current temperature and humidity data and act as a UI for setting the timers for lights, fans and pumps. 5 buttons navigate through the menus and options. The pumps will be triggered based on the soil moisture.

The problem is when I add an analogRead() for the soil moisture sensor. The 5 buttons stop working. The serial monitor still prints the string from the right loop but it just won’t react to the buttons. When I comment out the analogRead, it works again. Whats going on here?

My code is attached. Sorry it advance for the weak code, it is probably the least robust and most chaotic code Ive ever written.

ArduGarden1_1.ino (43 KB)

String mainMenu[menuSize] = {
  "Time", "Date", "Temp", "Humidity", "Light1", "Light2", "Pump1", "Pump2", "Fan1", "Fan2", "Fan3", "Fan4"};
String timeMenu[four] = {
  "Set Time", "Hour:", "Minute:", "home"};
String timeHourMenu[four] = {
  "Set Hour","Hour:", "home"};
String timeMinuteMenu[four] = {
  "Set Minute", "Minute: ", "home"};
String dateMenu[five] = {
  "Set Date", "Month:", "Day:", "Year:", "home"};
String dateMonthMenu[four] = {
  "Set Month", "Month:", "home"};
String dateDayMenu[four] = {
  "Set Day", "Day:", "home"};
String dateYearMenu[four] = {
  "Set Year", "Year:", "home"};

String tempMenu[two] = {
  "Temperature:", "home",};
String humiMenu[two] = {
  "Humidity:", "home"};
String light1Menu[five] = {
  "Light1 Menu", "  ON:", " OFF:", "CONTINUOUS", "home"};
String light1OnMenu[three] = {
  "Set Light1 On", "ON:", "home"};
String light1OffMenu[three] = {
  "Set Light1 Off", "OFF:", "home"};
String light2Menu[five] = {
  "Light2 Menu", "  ON:", " OFF:", "CONTINUOUS", "home"};
String light2OnMenu[three] = {
  "Set Light2 On", "ON:", "home"};
String light2OffMenu[three] = {
  "Set Light2 Off", "OFF:", "home"};
String pump1Menu[three] = {
  "Pump1 Menu","Soil Moisture:","home"};
String pump2Menu[three] = {
  "Pump2 Menu","Soil Moisture:","home"};
String fan1Menu[five] = {
  "Fan1 Menu", "  ON:", " OFF:", "CONTINUOUS", "home"};
String fan2Menu[five] = {
  "Fan2 Menu", "  ON:", " OFF:", "CONTINUOUS", "home"};
String fan3Menu[five] = {
  "Fan3 Menu", "  ON:", " OFF:", "CONTINUOUS", "home"};
String fan4Menu[five] = {
  "Fan4 Menu", "  ON:", " OFF:", "CONTINUOUS", "home"};

String fan1OnMenu[three] = {
  "Set Fan1 On", "ON:", "home"};
String fan2OnMenu[three] = {
  "Set Fan2 On", "ON:", "home"};
String fan3OnMenu[three] = {
  "Set Fan3 On", "ON:", "home"};
String fan4OnMenu[three] = {
  "Set Fan4 On", "ON:", "home"};

String fan1OffMenu[three] = {
  "Set Fan1 Off", "OFF:", "home"};
String fan2OffMenu[three] = {
  "Set Fan2 Off", "OFF:", "home"};
String fan3OffMenu[three] = {
  "Set Fan3 Off", "OFF:", "home"};
String fan4OffMenu[three] = {
  "Set Fan4 Off", "OFF:", "home"};

Not a single one of these needs to be a String. Use strings char *), instead.

  pinMode(soil1Pin, INPUT);
  pinMode(soil2Pin, INPUT);

You can't set the mode of an analog pin, so quit trying. They are input only.

      mainMenu[0] = String(hour()) + ":" + String(minute()) + ":" + String(second());
      mainMenu[1] = String(month()) + "/" + String(day()) + "/" + String(year());
      mainMenu[2] = "Temp:     " + String(far(temp)) + " F";
      mainMenu[3] = "Humidity: " + String(h) + "%";

Why are you overwriting mainMenu?

You really need to learn how to use strings, and quit pissing resources away on Strings. You have a finite number of rows and a finite number of columns on the LCD. Create a 21 x 4 array of chars, and use that to define what to display on the LCD.

Thanks a lot, like I said it was pretty bad coding and yeah I dont have a good understanding of strings and chars. I am overwriting because I want it to stay constantly updated.

You have a finite number of rows and a finite number of columns on the LCD. Create a 21 x 4 array of chars, and use that to define what to display on the LCD.

The menu scrolls through 12 options the top 4(time, date, temp, humidity) stay updated. Im not sure how to recreate that functionality with a 20x4 array of chars.

So by "pissing" away resources on Strings, I indeed have overwhelmed the memory or something like that?

Could I get some pointers on how to switch it all chars. A million things went wrong when I tried.

For starters

String timeMenu[four] = { "Set Time", "Hour:", "Minute:", "home"};

can be

char * timeMenu[] = { "Set Time", "Hour:", "Minute:", "home"};

Same with all the other ones.

BTW,

timeMenu[four]

have you seriously got a variable called “four” that has the constant value 4? Please tell me it ain’t so :slight_smile:


Rob

how do I fix the constant update? mainMenu[0] = String(hour()) + ":" + String(minute()) + ":" + String(second());

It won't be pretty, but look up strcat()

There's no doubt Strings make for neater-looking code, as this example will need 5 strcat()s to do I think.

Another (neater) option is sprintf(), that will take all those strings and put them into a single array.

Off the top of my head (I haven't used it for a long time)

char buff[100];
sprintf (buff, "%s:%s:%s", hour(), minute(), second());
Serial.print (buff);

Assuming those funcs return a char*, slightly different if they return something else like an int.


Rob

hmm, I tried it out but nothing shows up in serial monitor.

Assuming those funcs return a char*

Is that the case?


Rob

oh, I missed that part. yes it is returning an int. what would be the change? thanks a lot btw

try

sprintf (buff, “%d:%d:%d”, hour(), minute(), second());


Rob

working nicely, thanks for your help. Ill adapt the rest of the code and see if that fixes the problem. I feel kinda stupid for asking this but is there a well documented arduino API? The reference page is a little weak when it gets down to these specific cases.

well documented arduino API? The reference page is a little weak

That's it I'm afraid.

However sprintf() is strictly a C function and for good reason the Arduino reference does not try to document C/C++ per sa, just some of the basic operators and of course the Arduino-specific library functions. Trying to also document C/C++ would be a fool's errand as there are many other places that is done.

For example if you Google "sprintf" I'm sure you will find 1 or 2 results :slight_smile:

I would get a book or find an online reference you like and start reading, that does get pretty dry pretty quick I admit and not all the stuff you find will work on the Arduino (file operations for example), but you will learn a lot. The other thing to do is read a lot of other people's code, you could start with the Arduino libraries.


Rob

Okay, I have completely eliminated strings and cut a lot of the menus out. I wasn’t sure how to clear the buffer so I just made 15 of them. Im sure that was wrong but it worked. Problem is, I still have the same problem. Calling an analogRead still disables the 5 buttons. Now, I am stumped…

Here is the revised and slightly improved code.

ArduGardenMini.ino (30.4 KB)

You mean this one?

int s = analogRead(A8);

I see no obvious reason for that to break the program. Start putting prints in places to see exactly where it stops.


Rob

 int s = analogRead(A8);

that's the one. Or when I try readSoil().

Start putting prints in places to see exactly where it stops.

I have and it continuously prints the mainMenu to serial monitor (like it should). The program doesn't even stop, the LCD will display all the right data in real time so the analogRead does actually happen and updates to the screen but the navigation buttons stop working. It makes absolutely no sense. Could something be wrong with the readAllButtons() or the debounce() methods?

Could something be wrong with the readAllButtons() or the debounce() methods?

I’ll have a look, but you can easily test debouce() but removing it.

EDIT: Not so easy as you have 5 debounce() funcs, why not just have one with a parm for the pin to read?


Rob

sprintf (buff, "%d:%d:%d", hour(), minute(), second());

Typically, the format string would be "%2d:%02d:%02d", so that 8 minutes and 3 seconds after 5 o'clock would print as 5:08:03.

The format statement here would print 5:8:3

Not so easy as you have 5 debounce() funcs, why not just have one with a parm for the pin to read?

it was on the list of things to tidy up. I removed all the debounces and still no luck. Maybe the high humidity has affected the arduino. Although, analogRead works just fine in other sketches I have run to test it.

The Atmega168 datasheet also cautions against switching digital pins in close temporal proximity to making A/D readings (analogRead) on other analog pins. This can cause electrical noise and introduce jitter in the analog system. It may be desirable, after manipulating analog pins (in digital mode), to add a short delay before using analogRead() to read other analog pins.

Would reading digital pins cause a similar noise? I have tried delays but nothing helps.