Checking input at specific time

Hi everybody!

I’m trying to use an old Lego RCX rotation sensor with an Arduino. I made a lot of research so I know that I have to give the sensor 5V for a given time, let’s say 3 ms, (I tried with other values, that’s not the problem), then switch the pin from output to input and read the value. There is a capacity inside the sensor which discharges regularly and that can give four different values depending on the angle measured.

Here’s a link to a webpage where I found my info about the sensor: http://www.philohome.com/sensors/legorot.htm

And here’s a link to another webpage about using such sensors with Arduino: Using RCX Lego sensors with Arduino | Ro-Bot-X's Weblog

And here’s some code I found on the previous webpage:

int ReadLegoSensor(){
  pinMode(legoSensorPin, OUTPUT); //set pin as output
  digitalWrite(legoSensorPin, HIGH); //set output high
  delay(10); // wait a bit
  pinMode(legoSensorPin, INPUT); //set pin as input
  int value=analogRead(legoSensor); //read the input
  return value; //return the raw value
}

It works, but of course the value depends on the time elapsed between switching from output to input and reading the value. If you check the voltage too late, the capacity will be completely discharged and the tension will be zero.

Now what’s weird is that I found out after many checks that the time the Arduino takes to read a measure after switching from output to input varies a lot from time to time. That’s why for now I always print the elapsed time along with the read value.

pinMode(pin, INPUT); //set pin as input 
switchingTime=micros();
value=analogRead(legoSensor); //read the input 
elapsedTime=micros()-switchingTime;

What’s even weirder, is that if I create a while loop to take 100 measures for instance, the first measure will take about twice as much time than the 99 others. That’s weird because the way I take my measure does not change.

Another example? If I type

  pinMode(pin, OUTPUT);      //set pin as output
  digitalWrite(pin, HIGH);   //set output high
  delay(chargingTime);       // wait a bit
  switchingTime=micros();
  value=analogRead(legoSensor); //read the input 
  firstElapsedTime=micros()-switchingTime; 
  pinMode(pin, OUTPUT);      //set pin as output
  digitalWrite(pin, HIGH);   //set output high
  delay(chargingTime);       // wait a bit
  switchingTime=micros();
  value=analogRead(legoSensor); //read the input 
  secondElapsedTime=micros()-switchingTime;

the firstElapsedTime will be about twice as long than secondElapsedTime

I tried to register lots of values in order to modelize the variation of the voltage so that I could include the elapsed time in my criterium to differentiate between the four possible angles. Attached is a graph of what I got.

I established three limite functions (D12, D23 and D34) in order to be able to use a condition like

if value<D34(elapsedTime) {angle=4}

.

Unfortunately, it turns out that this solution will not work.

I think the solution would be to make sure the time between switching from output to input and reading the value remains constant.

I tried to use something like

  pinMode(pin, INPUT); //set pin as input 
  switchingTime=micros();
  while (micros()- switchingTime <200)
  {
  }
  value=analogRead(legoSensor); //read the input 
  elapsedTime=micros()-switchingTime;

in order to set the time to 200 µs. It worked but the elapsed time still varied way too much.
Do you have any suggestions? Any way to set the time between the switching and the reading to a constant value?

Thank you very much!

  switchingTime=micros();

while (micros()- switchingTime <200)
  {
  }

You’ve successfully re-invented the delayMicroseconds() function. Except yours doesn’t work for small values of microseconds. Not that that’s an issue for 200; it will be close to right.

The micros() timer is only accurate to 4us on the 16MHz Arduinos. Is the variability you are seeing about this magnitude? You don’t ever give us any real readings, just comparisons of twice or half.

What is “way too much”? Do you have any numbers that you would like to see?

analogRead() is a fairly time-consuming function. It has to do a lot of checks, to check the pin is an input, to check it doesn’t have a PWM timer connected to it and then the analog conversion also takes time. One thing that might be causing the variability is the ADC needs to switch to the correct channel and then wait to stabilise. If it’s already on that channel (pin) then it can read faster.

Thanks for your help!

This

 switchingTime=micros();
  while (micros()- switchingTime <200)
  {
  }

is not a reinvention of the delayMicroseconds function as it will delay the program only if switchingTime<200 us and the delay will be variable.

You’re right, I should have given you some samples of the values I have. The time between switching from output to input and reading the value usually varies between 112 and 136 µs, occasionally being as long as 208 µs. You can also check the picture I attached to my first post which contains an excel plot of my values. I attach it again.

You are totally right again about analogRead being faster if the same channel is used, unfortunately that’s what I was already doing :wink:

what I would like would be to be able to perform analogRead at a precisely fixed time, 200 µs for instance. That’s what I tried to do with my loop.

Some more ideas?

The “right” way to do it would be to use a hardware timer. You can run the analog system in “free running mode” where it samples regularly depending on a timer. (I’ve never successfully got this working because I always want to measure several inputs, not just one.) Free-running mode is also going to work badly with switching input and output modes.