Callback method analog input

Hi all,

I'm quite new to the Arduino, and been experimenting with some ws2812 led strips for the past weeks.
Works great and I'm really impressed with the Arduino.

Only two things I can't really get working:

I've connected a potentiometer, and read the values serial monitor successful. However what I actually want to do is put a 5V current into one or multiple analog ports and trigger some sort of 'callback' method.

I could use analogRead in the loop method, but from my understanding from the docs, it's quite an intensive task for the Arduino. Also, if I'm currently running some code with a loop and delay, it could take very long to trigger the callback, but I want it to happen immediately.

I'm finding all sorts of ISR callbacks for digital pins, but not the analog pins?

Here some example code (I'm using the NeoPixel library at this moment):

void setup() {
	
	strip1.begin();
}

int readAnalog1;
int readAnalog2;

void loop() {
	animateLed();

	readAnalog1 = AnalogRead(A0);
	readAnalog2 = AnalogRead(A1);

	if(readAnalog1 > 0) {
		callbackAnalog1();
	}

	if(readAnalog2 > 0) {
		callbackAnalog2();
	}
}

void animateLed() {
	
	for(int i = 0; i < 100; i++) {
		strip1.setPixelColor(i, 255, 0, 0);
		strip1.show();

		delay(200);
	}

	delay(2000);
}

void callbackAnalog1() {
	// set first three leds to blue

	for(int i = 0; i < 3; i++) {
		strip1.setPixelColor(i, 0, 0, 255);
	}

	strip1.show();
}

void callbackAnalog2() {
	// set first three leds to green
	
	for(int i = 0; i < 3; i++) {
		strip1.setPixelColor(i, 0, 255, 0);
	}

	strip1.show();
}

What's the best approach here?

Please let me now if my explanation isn't clear.

Thanks,

Tim

I could use analogRead in the loop method, but from my understanding from the docs, it's quite an intensive task for the Arduino.

I don't know where you read that. It does take roughly 104 microseconds to read, but that may not matter.

There is no reason to make the variables that hold the values read from the analog pins global, since you only use the values in loop().

Faim:
I've connected a potentiometer, and read the values serial monitor successful. However what I actually want to do is put a 5V current into one or multiple analog ports and trigger some sort of 'callback' method.

I could use analogRead in the loop method, but from my understanding from the docs, it's quite an intensive task for the Arduino. Also, if I'm currently running some code with a loop and delay, it could take very long to trigger the callback, but I want it to happen immediately.

I'm not clear about what you have in mind when you say "callback" - maybe you can write a few lines of pseudo code to illustrate your idea?

If the time it takes for analogRead() is a problem you could interact with the ADC registers and avoid any "delay" but that does not make the actual "behind the scenes" ADC process any faster.

If you want a responsive program don't use delay() and make sure no function takes more than a few microsecs (or millisecs at most) to complete. That way loop() can repeat hundreds or thousands of times per second. Have a look at the demo Several Things at a Time

...R

Yea, I don’t think ‘Callback’ is the right term. That’s typically a function that you register with a service (like attachInterrupt()) that will be called when some specific event occurs. That’s inherently a digital concept -- either the event occurs (and your function is called), or it does not.

gfvalvo:
Yea, I don’t think ‘Callback’ is the right term. That’s typically a function that you register with a service (like attachInterrupt()) that will be called when some specific event occurs. That’s inherently a digital concept -- either the event occurs (and your function is called), or it does not.

Yes, however that is exactly what I'm trying to accomplish. I use multiple led strips, and I need to use delay to create light effects. If there is input from an analog pin, I don't want to wait for the light effect sequence to end, but the 'callback' has to start immediately.

Also is it possible to put 5V directly into an analog pin? Right now I need to connect it to the ground pin to been able to read any value of it.

From your example code, don't put the analogRead() in loop but put it in animateLed() that way it can instantly respond to changes instead of waiting until the procedure has finished and returns to the main loop.

Also is it possible to put 5V directly into an analog pin? Right now I need to connect it to the ground pin to been able to read any value of it.

You could put 5V directly into the analogue pin but your would just get a 1023 reading all the time. The idea of analogue read is to read a variable voltage value between VCC (5V) and GND (0V) and to get the variable voltage you could use a potentiometer where the wiper output is the input to the analogue pin.

Riva:
From your example code, don't put the analogRead() in loop but put it in animateLed() that way it can instantly respond to changes instead of waiting until the procedure has finished and returns to the main loop.
You could put 5V directly into the analogue pin but your would just get a 1023 reading all the time. The idea of analogue read is to read a variable voltage value between VCC (5V) and GND (0V) and to get the variable voltage you could use a potentiometer where the wiper output is the input to the analogue pin.

Yes, that would be fine. If I put a switch between it, it would read 1023 when on, and a value below when off.

In my example code is just one loop, with one delay. However if I have multiple loops, with multiple delays, it seems like a bit of an overkill to call the AnalogRead everytime.

Isn't there some other way to achieve this? Instead of doing something like this:

void myDelay(int delay) {

    int aRead1, aRead2, i;

    i = 0;

    while(i + 20 > delay) {
        int aRead1 = analogRead(A0);
        int aRead2 = analogRead(A1);

        if(aRead1 > 1000) {
             doThis();
        }

        if(aRead2 > 1000) {
            doThat();
        }

        delay(20 * i);
        i += 20;
    }

    // check remaining delay
    if(i < delay) {
         delay(delay - i);
    }
    
}

5V-Analog.png

Faim:
In my example code is just one loop, with one delay. However if I have multiple loops, with multiple delays, it seems like a bit of an overkill to call the AnalogRead everytime.

Did you look at how the code is organized in the link I gave you in Reply #2. Planning and Implementing a Program is a more extensive example. See how all the parts are called from loop() so they all get a look-in, and none of them takes very long on its own.

...R

Faim:
Isn't there some other way to achieve this? Instead of doing something like this:

If all you want to do is read an on/off switch then use the analogue pins digital mode instead. It works just the same as reading a normal digital pin but will allow reading the pin 100's of times per second faster than analogue read.
And a better option for connecting a switch is to use the pins internal pullup resistor and connect the other side of the switch to ground. This will prevent a floating pin that can cause false triggering.

Robin2:
Did you look at how the code is organized in the link I gave you in Reply #2. Planning and Implementing a Program is a more extensive example. See how all the parts are called from loop() so they all get a look-in, and none of them takes very long on its own.

...R

Allright, what I understand from this, is that it would be better to use millis() in the progress, instead of delay. Compare it with the last value, and precede to the next step if a certain amount of time has passed. This way the loops get executed continuously, instead of being holdup by calling delay.

This makes sense, I've got some rewriting from my current code to do.

Also reading some more, it would be better to use a digital pin, instead of an analog one, since it will be only on or off. I don't need the exact voltage.

Just to clarify and to be sure, if I'm applying this, without any load resistors:

I would get an value and there's no way I'm damaging my board?

The way to connect the switch is...

and turn on the internal pullup resistor for the pin you use.

pinMode(switchPin, INPUT_PULLUP);

Riva:
The way to connect the switch is...

and turn on the internal pullup resistor for the pin you use.

pinMode(switchPin, INPUT_PULLUP);

The switch was just an example. I've got an external device that outputs 5V at multiple wires if switches get pushes.

If it's not possible to put 5V directly into the Arduino, I think I'm going to put some relais in between.

Faim:
The switch was just an example. I've got an external device that outputs 5V at multiple wires if switches get pushes.

Ah, I missed that little nugget in the previous posts. Yes you can wire the switch the other way round so it pulls the Arduino pin to 5V when the button is pressed but now you will need an external resistor to hold the pin to ground when the switch is not pressed or you may get false readings.

In this case don't use internal pullup resistor and just define the switch thus

pinMode(switchPin, INPUT);

Riva:
Ah, I missed that little nugget in the previous posts. Yes you can wire the switch the other way round so it pulls the Arduino pin to 5V when the button is pressed but now you will need an external resistor to hold the pin to ground when the switch is not pressed or you may get false readings.

In this case don't use internal pullup resistor and just define the switch thus

pinMode(switchPin, INPUT);

Great!
Thanks for your help Riva, appreciate it!