analogRead() slows down steppers

Hi!

I would like to implement 2 buttons as limiting
switches for an motor controlled axis. I check which
button is pressed by measuring the resistance of
each button (resitors before the buttons; the approach
works normally fine).

The thing is that the stepper motors seem to get
really slowed down when measuring the analog value
of the buttons all the time. If I comment the analogRead
out the steppers run fine otherwise they get really slow
and making a lot of noise and vibration.

So the question is:
Slows analogRead() the processor that hard? Are there
ways to compensate this behaviour?

In the class:

void AxisCtrl::home()
{
	motorOverride(1);
	if(limitSwitchState() == 1)
	{
		_axisHomed = true;
		_currStepPos = 0;
	}
}

void AxisCtrl::motorOverride(int dir)
{
	unsigned long currentMicros = micros();
	if(currentMicros - _previousCycle > _motorSpeed) {
		_previousCycle = currentMicros;
		if(_motorPinState == 0){
			_motorPinState = 1;
		} else {
			_motorPinState = 0;
		}
		digitalWrite(_dirPin, dir);
		digitalWrite(_motorPin,_motorPinState);
	}
}
int AxisCtrl::limitSwitchState()
{
	int btnNr;
	int btnVal = analogRead(_limitSwitchesPin);
	if(btnVal > 1000){
		btnNr = 0;
	} else if(btnVal>_axisHomeBtnVal-10 && btnVal<_axisHomeBtnVal+10){
		btnNr = 1;
	} else if(btnVal>_axisStopBtnVal-10 && btnVal<_axisStopBtnVal+10){
		btnNr = 2;
	}
	return btnNr;
}

In the loop():

if(homeAll){
    x.home();
    y.home();
    z.home();
}

Thanks in advance!
Regards!
Marius

You can do analogRead asynchronously, as I show here:

Scroll down to: "Read the Analog-to-Digital converter asynchronously"

That way the analog read is happening in the background.

Otherwise each analogRead takes 104 uS which will probably make a noticeable impact.

Thanks Nick!

I tried the ISR function but I cant get it work. :frowning:

This is my code (please note that I deleted for readability
all functions and variables that are not important here):

In the loop:

void loop() {
    Serial.println(x.limitSwitchState());
}

Class h.:

#ifndef AxisCtrl_h
#define AxisCtrl_h

#include "Arduino.h"

class AxisCtrl
{
  public:
	AxisCtrl(int motorPin, int dirPin, int limitSwitchesPin,int steps, float leadPitch);
	int limitSwitchState();
        void home();
private:
	volatile int adcReading;
	volatile boolean adcDone;
	boolean adcStarted;
};

#endif

And my cpp:

AxisCtrl::AxisCtrl(int motorPin, int dirPin, int limitSwitchesPin, int steps, float leadPitch)
{
	ADMUX = _BV (REFS0) | (limitSwitchesPin & 0x07);
}

int AxisCtrl::limitSwitchState()
{
	int btnNr;
	  // if last reading finished, process it
	if (adcDone)
	{
		adcStarted = false;
		if(adcReading>_axisHomeBtnVal-10 && adcReading<_axisHomeBtnVal+10){
			btnNr = 1;
		} else if(adcReading>_axisStopBtnVal-10 && adcReading<_axisStopBtnVal+10){
			btnNr = 2;
		}
		return btnNr;
		adcDone = false;
	}
	// if we aren't taking a reading, start a new one
	if (!adcStarted)
	{
		adcStarted = true;
		// start the conversion
		ADCSRA |= _BV (ADSC) | _BV (ADIE);
	}    
	// do other stuff here
}

ISR (ADC_vect)
{
  byte low, high;
  // we have to read ADCL first; doing so locks both ADCL
  // and ADCH until ADCH is read.  reading ADCL second would
  // cause the results of each conversion to be discarded,
  // as ADCL and ADCH would be locked when it completed.
  low = ADCL;
  high = ADCH;
  adcReading = (high << 8) | low;
  adcDone = true;  
}  // end of ADC_vect

I allways get a

C:\_Marius\EigeneProjekte\prj0009_CNCMaschine\prj0009_CNCMaschine\Binary_Arduino\libraries\AxisCtrl\AxisCtrl.cpp: In function 'void __vector_21()':
C:\_Marius\EigeneProjekte\prj0009_CNCMaschine\prj0009_CNCMaschine\Binary_Arduino\libraries\AxisCtrl\AxisCtrl.cpp:262: error: 'adcReading' was not declared in this scope
C:\_Marius\EigeneProjekte\prj0009_CNCMaschine\prj0009_CNCMaschine\Binary_Arduino\libraries\AxisCtrl\AxisCtrl.cpp:263: error: 'adcDone' was not declared in this scope

If I define the 2 variables inside the ISR function again it compiles but
I get nonsense readings.

Is it even possible to use the ISR inside a class?
Thanks!

ISRs cannot access class variables like that. Which instance of the class do they refer to?

Hm. Im not really sure what you mean by:

Which instance of the class do they refer to?

They get instanciated in the "AxisCtrl" class.

But to be honest I think I will just use 6 pins for each axis and
dont save 3 pins by using analog readings. DigitalRead() seams
to be a lot faster! :slight_smile:
But thanks again Nick, I will investigate this behaviour later. :slight_smile:

asuryan:
Hm. Im not really sure what you mean by:

Which instance of the class do they refer to?

They get instanciated in the "AxisCtrl" class.

There is a difference between a class and an instance. For example a dog is a class of animal, and Fido is an instance of the class dog.

In your code you have:

ISR (ADC_vect)
{
 ...
  adcReading = (high << 8) | low;
  adcDone = true;  
}  // end of ADC_vect

And your class has those variables:

class AxisCtrl
{
...
private:
	volatile int adcReading;
	volatile boolean adcDone;
	boolean adcStarted;
};

But the variables exist in an instance of the class. eg.

AxisCtrl control1;
AxisCtrl control2;
AxisCtrl control3;

So the ISR has no way of knowing which instance of the class you are referring to in the ISR.