Port manipulation on Arduino Mega

Can anyone help me write code to make the PING Sensor read faster?

Currently the pin layout is:

const int pingPin = 22; const int groundpin2 = 26; const int powerpin2 = 24;

I'm talking about this:

http://www.arduino.cc/en/Reference/PortManipulation

if that helps.

The reading time of a ping sensor is limited by the return path time not by how fast it takes to access the pins. You can use port manipulation but it will no shave much off the time. .

#define FASTADC 1

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

const int pingPin = 22;
const int groundpin2 = 26; 
const int powerpin2 = 24;

const int groundpin = 55; //58 on +/-18
const int powerpin = 54; //59 on +/-18
const int xpin = 3;

long timea;
long timeb;
long truetime;
int duration;

void setup()
{
  Serial.begin(9600);
  
  #if FASTADC
  // set prescale to 16
  sbi(ADCSRA,ADPS2) ;
  cbi(ADCSRA,ADPS1) ;
  cbi(ADCSRA,ADPS0) ;
  #endif

  
  pinMode (groundpin, OUTPUT);
  pinMode (powerpin, OUTPUT);
  digitalWrite (groundpin, LOW);
  digitalWrite (powerpin, HIGH);
  pinMode (groundpin2, OUTPUT);
  pinMode (powerpin2, OUTPUT);
  digitalWrite (groundpin2, LOW);
  digitalWrite (powerpin2, HIGH);
}

void loop(){
   if (analogRead(xpin) > 511){
    timea = millis();
    readping();
    int amm = duration;\
    readping();
    int bmm = duration;
    readping();
    int rcmm = duration;
    readping();
    int dmm = duration;
    readping();
    int emm = duration;
    readping();
    int fmm = duration;
    readping();
    int gmm = duration;
    readping();
    int hmm = duration;
    readping();
    int kmm = duration;
    readping();
    int lmm = duration;
    readping();
    int rmmm = duration;
    readping();
    int nmm = duration;
    readping();
    int omm = duration;
    readping();
    int pmm = duration;
    readping();
    int qmm = duration;
    readping();
    int ormm = duration;
    readping();
    int smm = duration;
    readping();
    int tmm = duration;
    readping();
    int umm = duration;
    readping();
    int vmm = duration;
 /*   readping();
    int aamm = duration;
    readping();
    int bbmm = duration;
    readping();
    int ccmm = duration;
    readping();
    int ddmm = duration;
    readping();
    int eemm = duration;
    readping();
    int ffmm = duration;
    readping();
    int ggmm = duration;
    readping();
    int hhmm = duration;
    readping();
    int kkmm = duration;
    readping();
    int llmm = duration;
    readping();
    int romm = duration;
    readping();
    int nnmm = duration;
    readping();
    int oomm = duration;
    readping();
    int ppmm = duration;
    readping();
    int qqmm = duration;
    readping();
    int rrmm = duration;
    readping();
    int aaamm = duration;
    readping();
    int bbbmm = duration;
    readping();
    int cccmm = duration;
    readping();
    int dddmm = duration;
    readping();
    int eeemm = duration;
    readping();
    int fffmm = duration;
    readping();
    int gggmm = duration;
    readping();
    int hhhmm = duration;
    readping();
    int kkkmm = duration;
    readping();
    int lllmm = duration;
    readping();
    int mmmmm = duration;
    readping();
    int nnnmm = duration;
    readping();
    int ooomm = duration;
    readping();
    int pppmm = duration;
    readping();
    int qqqmm = duration;
    readping();
    int rrrmm = duration; */
    timeb=millis();
    truetime= timeb-timea;
    int dmina = min(min(min(min(vmm,umm), min(smm,tmm)),(min(emm,fmm), min(gmm,hmm))),min(min(min(kmm,lmm), min(rmmm,nmm)),(min(omm,pmm), min(qmm,ormm))));
//    int dminb = min(min(min(min(ccmm,ddmm), min(aamm,bbmm)),(min(eemm,ffmm), min(ggmm,hhmm))),min(min(min(kkmm,llmm), min(romm,nnmm)),(min(oomm,ppmm), min(qqmm,rrmm))));
 //   int dminc = min(min(min(min(cccmm,dddmm), min(aaamm,bbbmm)),(min(eeemm,fffmm), min(gggmm,hhhmm))),min(min(min(kkkmm,lllmm), min(mmmmm,nnnmm)),(min(ooomm,pppmm), min(qqqmm,rrrmm))));
 //   int dmino = min(dmina, min(dminb,dminc));
    Serial.print(amm);
    Serial.println("mm");
    Serial.print(bmm);
    Serial.println("mm");
    Serial.print(rcmm);
    Serial.println("mm");
    Serial.print(dmm);
    Serial.println("mm");
    Serial.print(emm);
    Serial.println("mm");
    Serial.print(fmm);
    Serial.println("mm");
    Serial.print(gmm);
    Serial.println("mm");
    Serial.print(hmm);
    Serial.println("mm");
    Serial.print(kmm);
    Serial.println("mm");
    Serial.print(lmm);
    Serial.println("mm");
    Serial.print(rmmm);
    Serial.println("mm");
    Serial.print(nmm);
    Serial.println("mm");
    Serial.print(omm);
    Serial.println("mm");
    Serial.print(pmm);
    Serial.println("mm");
    Serial.print(qmm);
    Serial.println("mm");
    Serial.print(ormm);
    Serial.println("mm");
 /*   Serial.print(aamm);
    Serial.println("mm");
    Serial.print(bbmm);
    Serial.println("mm");
    Serial.print(ccmm);
    Serial.println("mm");
    Serial.print(ddmm);
    Serial.println("mm");
    Serial.print(eemm);
    Serial.println("mm");
    Serial.print(ffmm);
    Serial.println("mm");
    Serial.print(ggmm);
    Serial.println("mm");
    Serial.print(hhmm);
    Serial.println("mm");
    Serial.print(kkmm);
    Serial.println("mm");
    Serial.print(llmm);
    Serial.println("mm");
    Serial.print(romm);
    Serial.println("mm");
    Serial.print(nnmm);
    Serial.println("mm");
    Serial.print(ppmm);
    Serial.println("mm");
    Serial.print(qqmm);
    Serial.println("mm");
    Serial.print(rrmm);
    Serial.println("mm");
    Serial.print(aaamm);
    Serial.println("mm");
    Serial.print(bbbmm);
    Serial.println("mm");
    Serial.print(cccmm);
    Serial.println("mm");
    Serial.print(dddmm);
    Serial.println("mm");
    Serial.print(eeemm);
    Serial.println("mm");
    Serial.print(fffmm);
    Serial.println("mm");
    Serial.print(gggmm);
    Serial.println("mm");
    Serial.print(hhhmm);
    Serial.println("mm");
    Serial.print(kkkmm);
    Serial.println("mm");
    Serial.print(lllmm);
    Serial.println("mm");
    Serial.print(mmmmm);
    Serial.println("mm");
    Serial.print(nnnmm);
    Serial.println("mm");
    Serial.print(ooomm);
    Serial.println("mm");
    Serial.print(pppmm);
    Serial.println("mm");
    Serial.print(qqqmm);
    Serial.println("mm");
    Serial.print(rrrmm);
    Serial.println("mm"); */
    Serial.println(dmina);
//    Serial.println(dminb);
//    Serial.println(dminc);
//    Serial.println(dmino);
    Serial.print("Time: ");
    Serial.print("\t");
    Serial.print(truetime); 
    Serial.println();
   }
}

void readping(){
  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);

  // The same pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  // convert the time into a distance
// mm = microsecondsToCentimeters(duration);
  
/*  mm = duration / float(2.9) / 2;
  Serial.print(mm);
  Serial.print("mm");
  Serial.println();
  */
  delayMicroseconds(10000); 
}

That's what I figured, but the problem that I'm having is that the read time should be less than a millisecond based on the distance I have the Ping sensor at, but I need a 10 millisecond delay to get the code to work properly. Without that delay I'll get a random 64 or some other ridiculously small number.

readping();
    int amm = duration;\
    readping();
    int bmm = duration;
    readping();
    int rcmm = duration;
    readping();
    int dmm = duration;
    readping();
    int emm = duration;
    readping();
    int fmm = duration;
    readping();
    int gmm = duration;
    readping();
    int hmm = duration;
    readping();
    int kmm = duration;
    readping();
    int lmm = duration;
    readping();
    int rmmm = duration;
    readping();
    int nmm = duration;
    readping();
    int omm = duration;
    readping();
    int pmm = duration;
    readping();
    int qmm = duration;
    readping();
    int ormm = duration;
    readping();
    int smm = duration;
    readping();
    int tmm = duration;
    readping();
    int umm = duration;
    readping();
    int vmm = duration;

Have you ever heard of arrays?

This:

min(min(min(min(vmm,umm), min(smm,tmm)),(min
(emm,fmm), min(gmm,hmm))),min(min(min(kmm,lmm), min(rmmm,nmm)),(min(omm,pmm), min(qmm,ormm))))

reminds me of LISP ;D

Without that delay I'll get a random 64 or some other ridiculously small number

I'm not that familiar with the Ping sensor, but imagine that there's a wall a little way past your object. You transmit a pulse and get an echo off your object. Good so far. You transmit another pulse immediately, but the first pulse is still in-flight. It hits the wall beyond your object and returns to the receiver, possibly before the pulse you just sent has reached your target object. Does this sound a likely scenario?

I'm pretty new to this, but I'm just sort of diving in.

How would I use an array?

Nope, the object in question is a very large metal wall at a relatively short distance.

Increasing the delay between read times helps, but I'm not sure why and I'd prefer not to have that long of a delay.

Nope, the object in question is a very large metal wall at a relatively short distance

You could still be getting multiple reflections. Can you turn the receiver gain down on a Ping? This would help reduce the effect of weaker returns.

How would I use an array?

#define ITERATIONS 100
int durations[ITERATIONS];

void loop()
{
   for(byte i=0; i<ITERATIONS; i++)
   {
      read_ping();
      durations[i] = duration;
   }

   int minDuration = durations[0];
   for(byte i=1; i<ITERATIONS; i++)
   {
      if(durations[i] < minDuration)
        minDuration = durations[i];
   }

   // minDuration is now the quickest response time
}

Set the value of ITERATIONS to the number of readings you want to take.

Bonus marks are available for eliminating the second “for” loop (and probably the array)

I appreciate the help shortening the code, but that doesn't fix the problem I'm having with the delay time.

Even with that code when the object in front of the Ping is moved I still get a bad read time

I still get a bad read time

Tell us what a good reading looks like.
Tell us what a bad reading looks like.

Why don’t you try to help us help you?

We don’t know what your test environment looks like.
We don’t know what your results look like.

Have you tried testing in an open space?
Are your secondary returns giving consistent values?
Have you tried reducing the gain on the sensor?

Also, 10 milliseconds is very short, by human standards. Why is it necessary to shorten this time?

Even with a 10 millisecond delay, you could get close to 100 readings per second. How fast is the object moving?

Here's a thought: Is it the 10ms between readings that's the problem (possibly difficult to resolve), or the fact that the processor isn't doing anything during the "delay" (dead easy to resolve)?

I get a reading of 64 microseconds when it’s a problem, but around 544 normally. The object is moving back and forth and I want to know the minimum distance the object is from the ping. The object is on springs so it changes location rather quickly.

The problem is that the odd 64 reading completely throws off the minimum.
I don’t have anything else I would need to do during the delay, but the odd 64 or 89 reading would through off the rest of the code.

I would prefer to make the delay as small as possible as well.

i have same 1 and it's work naw thanx all :D

@gb667: Have you tried anything like foam or curtains to deaden multiple returns? Have you thought of filtering out obviously wrong results (i.e if the object can't possibly be closer than 80mm, then ignore such returns)?

I filtered out the wrong results here recently, but I still don’t understand why I need such a long delay.

It doesn’t seem to matter if the delay comes before or after when the duration is stored. Example:

  delay(10); 
      durations[i] = duration;
  delay(0);

or

  delay(0); 
      durations[i] = duration;
  delay(10);

However the amount of delay matters.
(All readings below are the Ping sensors readings when pointed at an unmoving object)
A total of 0 milliseconds delay will give no results.
A 1 millisecond delay will give a duration of 241 microseconds
A 2 millisecond delay will give a duration of 269-295 microseconds
A 3 millisecond delay will give a duration of 635 microseconds
A 4 millisecond delay will give a duration of 632-635 microseconds
A 5 millisecond delay will give a duration of 635 microseconds
A 6 millisecond delay will give a duration of 632-635 microseconds
A 7 millisecond delay will give a duration of 659 microseconds
A 8 millisecond delay will give a duration of 659 microseconds
And any delay greater than that will also give a duration of 659 microseconds.

These results are using the following code:

#define FASTADC 1

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

#define ITERATIONS 100

const int pingPin = 22;
const int groundpin2 = 26; 
const int powerpin2 = 24;

const int groundpin = 55; //58 on +/-18
const int powerpin = 54; //59 on +/-18
const int xpin = 3;

long timea;
long timeb;
long timec;
long truetime;
long btruetime;
int duration;
int durations[ITERATIONS];

void setup()
{
  Serial.begin(9600);
  
  #if FASTADC
  // set prescale to 16
  sbi(ADCSRA,ADPS2) ;
  cbi(ADCSRA,ADPS1) ;
  cbi(ADCSRA,ADPS0) ;
  #endif

  
  pinMode (groundpin, OUTPUT);
  pinMode (powerpin, OUTPUT);
  digitalWrite (groundpin, LOW);
  digitalWrite (powerpin, HIGH);
  pinMode (groundpin2, OUTPUT);
  pinMode (powerpin2, OUTPUT);
  digitalWrite (groundpin2, LOW);
  digitalWrite (powerpin2, HIGH);
}

void loop(){
 //  if (analogRead(xpin) > 511){
    timea = millis();
   for(byte i=0; i<ITERATIONS; i++)
   {
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);
  delay(20); 
      durations[i] = duration;
  delay(0); 
   }
   timeb = millis();
   int minDuration = durations[0];
   for(byte i=1; i<ITERATIONS; i++)
   {
     if(durations[i] > 232 && durations[i] < 669){
      if(durations[i] < minDuration)
        minDuration = durations[i];
   }
   }
   timec = millis();
   truetime = timeb- timea;
   btruetime = timec- timea;
    Serial.println(minDuration);
    Serial.print("Time: ");
    Serial.print("\t");
    Serial.println(truetime); 
    Serial.print("Time: ");
    Serial.print("\t");
    Serial.print(btruetime); 
    Serial.println();
   // minDuration is now the quickest response time
} 
//}

If anyone could explains why this occurs that would be great. I’d also like to get the delay as small as possible without inaccurate results.

5 milliseconds seems to produce the most accurate readings. 3 milliseconds produces inaccurate readings if moved