analogRead returns 0 when outside of loop

Hey all, thanks for taking the time to read about my noob-ish problems :grin:

So im trying to make a DIY hygrometer… i attached a rough schematic of my hygrometer set up. The “hygrometer resistor” is just two nails stuck into soil with some alligator clips attached.

Then I also have a air pump controlled by a transistor that’s fed 5v from the arduino. (Base connected to pin 13). (not in schematic)

Here’s my code:

int threshold = analogRead(A0);       //Set value which initiates watering

void setup() {
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
}

void loop() {
 int ref = analogRead(A0);             //Checks conductivity of soil
 
  if (ref < (threshold + 3)){         //Begin watering
    digitalWrite(13, HIGH);
    delay(1000);
    ref = analogRead(A0);            //Second reading needed because due to value difference when motor is running
    
    for (int i = 0; i < 20; i++){
     int soilVal = analogRead(A0);    //Check soil conductivity value
     delay(500);
       if (soilVal > (ref + 3)) {     //Check if soil has been watered
         digitalWrite(13, LOW);
         break;
       }
    }
  digitalWrite(13, LOW);              //Fail-safe if 13 hasnt been pulled low already
  }
}

My difficulty:
int threshold = analogRead(A0) will always return 0 if not placed into the loop function. Which is obviously a problem because then my set up would not water until the soil becomes (nearly) non-conductive.

The arduino reference states “It takes about 100 microseconds (0.0001 s) to read an analog input” so i was thinking maybe it’s taking longer than that for the signal to reach A0, but I’ve tried initializing threshold after the setup which included a half-second delay but no improvement. but when threshold is initialized in the loop function, right next to the initialization of ref I unsurprisingly get the same (non-zero) value for ref and threshold.

Any thoughts with what’s going on? Thanks again!

I know I may have done a poor job explaining but words are hard, especially at 5am. Let me know if anything needs clarification!

Hygrometer.JPG

Why not reading the value in the setup loop ?

Put:
int threshold = analogRead(A0);
inside the void setup() function.

Thanks for the suggestion Anatroll and Archibald,

When I initialize threshold in the setup function I do get the proper reading from it, but I still need to access that value in the loop function and so far as i know the only way to do so is to have threshold as a global variable.

Is there any way to call a value in loop() if it was initialized in setup()?

Also, if anyone could explain, I am still curious as to why im getting that 0 value when initializing out of a function? Not too much good stuff on the internet that i could find.

Put:
int threshold;
before void setup()
to declare a global variable.

Then put:
threshold=analogRead(A0);
inside setup() function.

Don’t ask me why! I’ve never understood why there is a setup() function for Arduinos.

archibald,

ahh, i see. thank you! works fine now.

Archibald: Put: int threshold; before void setup() to declare a global variable.

Then put: threshold=analogRead(A0); inside setup() function.

Don't ask me why! I've never understood why there is a setup() function for Arduinos.

The setup function is for one-shot initialization of various things that can be done with local variables, for example: setting initial states of I/O pins, starting communication buses, initializing library classes, etc. If all of these events were done entirely global, available memory could be chewed up pretty quickly.

For example, Serial.begin(9600); uses 9600 as a variable, which it passes and uses to initialize the USART (or is it a UART? I forget, right now) on the micro. Those 2 (or more, if you're looking at a 115200 baud!) bytes are no longer required after it's done and they're freed up when setup exits.

Thank you for the explanation but I'm not entirely convinced!

I still don't understand why if you put:

int threshold = analogRead(A0);

before or after the setup() function that it compiles but does not work.

If I put:

int threshold;
threshold=analogRead(A0);

before or after the setup() function I get compiler error message:

'threshold' does not name type

I'm still puzzled!

You can't call functions in the global space.

To achieve what you're trying to do, you'd do this:

int threshold=0; //Create "threshold" and give it a value to allocate memory

void setup(){
  threshold=analogRead(A0);
}

What we're doing here is creating and initializing a global variable named threshold. Before any other function is called, the compiler calls setup. Inside setup we give it a one-shot reading and store it in to threshold. After this, threshold will remain set to the value it's given inside setup, unless you modify it elsewhere in the code.

Edit:

I apologize, that wasn't a very complete answer. The reason why it will compile the first way is that, in terms of syntax, there's nothing inherently wrong with what you've done. The compiler doesn't know that it can't do anything with what you've given it.

The second one fails because the global space is reserved for declarations of various things, like variables, functions, classes, unions, etc. What it thinks you're trying to do with the second one is create a variable (or instance of a class, union, struct, etc) of type "threshold." That's why you get that error.

chazzy84: You can't call functions in the global space.

Yes you can, the problem is that global initializers (top level declarations) are setup before anything else in the code, including the hardware initialization that sets up registers controlling the ADC - so the hardware is in the wrong state.

Another common problem is people expecting to be able to run useful code in object constructors, which again tend to get put at top level. About the only thing you can safely do is allocate memory.

Read up on "c++ scope". here