ADC disturbes PWM

Hi there!

I have a litte problem with my pro micro. I can not use the PWM and the ADC at once.

The task of the program is to scan the ambience with an GP2D12 mounted on a servo. The servo should turn from one endpoint to the other in 180 steps and the distance data of the GP2D12 is stored in an int-array with a length of 180.

But I encountered a crazy problem: If I start the ADC, the servo goes nuts. It moves to the first endpoint and stops working. Deleting the codeline with the ADC-conversion everything works fine.

Here is the code:

#include <Servo.h> 

void senseIR(void);
 
Servo m1, m2, s1;  // create servo objects
 
int m1speed = 0;
int m2speed = 0;
int s1position = 90;
int distance[180];
int i;
const int m1Speed = 3;
const int m1Direction = 4;
const int m2Speed = 5;
const int m2Direction = 6;;
const int s1Pin = 9;
const int IRSensPin = 8;
int increase = 1;
const int cycletime = 50;
int starttime, endtime;

void setup() 
{ 
  Serial.begin(9600); 
  pinMode(m1Speed, OUTPUT); 
  pinMode(m1Direction, OUTPUT);
  pinMode(m2Speed, OUTPUT);  
  pinMode(m2Direction, OUTPUT);
  s1.attach(s1Pin);  // attaches the servo on pin 9 to the servo object   
  // Initialize the array
  for (i=0; i<180; i++)
  {
      distance[i] = 0;
  }
} 

void senseIR(void)
{

   s1.write(s1position);


// ************** This is the line which causes the problems *************
   distance[s1position] = analogRead(IRSensPin);

    if(1 == increase)
    {  if (s1position < 180) 
       { s1position++;  } 
       else
       { increase = 0; } }
    else    // 0 == increase => decrease
    { if (s1position > 0) 
      { s1position--;    }
      else
      {  increase = 1;  }  }
}

void loop() 
{ 
   starttime = millis();
   senseIR();
    
    endtime = millis(); 
    delay(cycletime-(endtime - starttime));    // Wait to achieve approximately constant cycletime

}

Do you hava any idea why the ADC disturbes the PWM? I would be very thankful if you could help.

Thanks,
urwalfloh

const int IRSensPin = 8;
distance[s1position] = analogRead(IRSensPin);

So what Arduino do you have here?

Do you hava any idea why the ADC disturbes the PWM?

Basically it doesn’t, so the answer to your problems is in your hardware or software.

Anyway your problem concerns the servo library not the PWM.

How is your pro micro, servo and distance measuring sensor connected and powered?
Do you have a separate power source for your servo?
Have you avoided ground loops in your ground connections?

Thanks for the answers!

Grumpy_Mike:

const int IRSensPin = 8;
distance[s1position] = analogRead(IRSensPin);

So what Arduino do you have here?

I have this one:

During development the board was USB-powered, but in operating state use a 5V battery. (The problem happend both times)
In battery mode the battery is connected to the "raw"-side of the on-board power regulator. The servo is also connected to the raw-pin so the voltage-regulator does not have to drive the servo load.
The IR-sensor is conncted after the regulator.

Just by deleting the code-line

distance[s1position] = analogRead(IRSensPin);

everything works fine. So I assume a software problem, because the circuit and the load isn't changed.

There is a hardware problem.

What happens to the voltage on 5V USB power or 5V battery power when subjected to a load > 500mA? Are you absolutely sure VCC is maintained within 2.7V to 5.5V at all times?

I don't know what happens, when the USB load gets over 500mA and really don't want to know, because I don't want to kill my mainboard. :confused:

At first I also thought about a hardware problem, but why should the program work as expected if I comment the analogRead() out and do not change the circuit?
Without reading the analog value the servo turns, the Sharp sensor is still powered and connected to the ADC-pin.

Hence I thought about a software problem and maybe the ADC-conversion influences the timing of the servo control pin. But the PWM is generated by a hardware time so it should be independent...

What's the max load current of the servo and is it using the same power source as the Arduino?
Why not test the servo running off a separate supply and see what happens?

But the PWM is generated by a hardware time so it should be independent...

Again we are not talking about PWM here, it is the servo library.

Please show the circuit of how you have wired it up. There is nothing that should be going wrong with the software. Just to check does it still go wrong if you put this line in?

int scrap = analogRead(IRSensPin);

dlloyd:
What's the max load current of the servo and is it using the same power source as the Arduino?
Why not test the servo running off a separate supply and see what happens?

already tested, but the same result. this is obvious, because only the single line of code changes the behavior, not the circuit load.

Grumpy_Mike:
Again we are not talking about PWM here, it is the servo library.

why not PWM?
the servo needs a control signal with a pulse width of 20ms and a duty-cycle of 5% to 10%. in my opinion this can be done with a pulse width modulation (pwm).

(by the time i'm drawing the circuit. it should be finished soon)

in my opinion this can be done with a pulse width modulation (pwm).

While you are free to have an opinion you are not guaranteed to be right.

While the signal might look like PWM to an untrained eye, it is in fact PPM (pulse position modulation). This is because the signal is not about a continuous duty cycle. If you were to use PWM to control a servo then there would be a very limited resolution.

so, i drew the cicuit, it's not beautiful or that stuff, but it sould do:

Grumpy_Mike:
While you are free to have an opinion you are not guaranteed to be right.

ditto

In your code:

What happens if slposition > 180? (this condition is not being handled)

From servo.h:
void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds

int i; Why is this global?

delay(cycletime-(endtime - starttime)); // Wait to achieve approximately constant cycletime

Wouldn’t waiting an interval of time be more efficient and stable than blocking the code with delay? What range of values do you get with cycletime-(endtime - starttime)?

urwaldfloh:
ditto

Ok have it your own way. I am out of here. I hate people who are not willing to learn.

Hi, and thanks for your answers!

At first I tried
int scrap = analogRead(IRSensPin);
and it worked! :slight_smile:
Sadly copying the "scrap" variable into da array in a second step stopped the servo again.

dlloyd:
What happens if slposition > 180? (this condition is not being handled)

You are right, I didn't catch that. It should not happen, but it is a source for an error and i will correct it.

int i; Why is this global?

For no special reason...

delay(cycletime-(endtime - starttime)); // Wait to achieve approximately constant cycletime
The idea of this is to get a low-cost real-time system. The code is going to be part of a closed control loop and these are typically sensitive to the cycle time. During development of the project the code will get bigger and the cycle-time will increase. So I implement a delay to create space for later code.
In the end, if everything works fine this delay is going to be deleted.

By now (endtime - starttime) is about 1ms.

Please check your slposition logic.

{ if (s1position < 180)
{ s1position++; }
This will allow slposition to reach180, which is not a valid index (0…179) in
distance[s1position] = analogRead(IRSensPin);

Most probably i is overwritten then.

thanks for the advice! that was the problem. :grin:

 if(1 == increase)
    {
      if (s1position < 180)  <<< what happened if s1position = 179? ++, so s1position becomes 180 ! OUT of boundary of array ! 
       {
          s1position++;  
       } 
       else
       { 
          increase = 0;
       }
     }
    else    // 0 == increase => decrease
    { if (s1position > 0) 
      { s1position--;    }
      else
      {  increase = 1;  }  }
}