0
\$\begingroup\$

I'm trying to connect 4 ultrasonic sensors HC-SR04 to Arduino UNO using a NXP's PCF8574P chip. If 4 sensors are connected to Arduino pins, everything's fine.

The problem appears when I try co bind them throught PCF8574P. The speed of response falls dramatically: almost 4 seconds to send signals and read response from the all 4 sensors.

What really takes time is pulseIn(). This is the place where I see the most of time being spent...

Here's the code:

#include <Wire.h>
#include "PCF8574.h"

PCF8574 pcf_us; //Ultrasonic sensors

//The matrix of pin assignments for the ultrasonic sensors (trig (OUTPUT), echo (INPUT))
int usPinMatrix[4][2] = {
  {0, 4}, //0 (pin for trig), 4 (pin for echo)
  {1, 5}, //1 (pin for trig), 5 (pin for echo)
  {2, 6}, //2 (pin for trig), 6 (pin for echo)
  {3, 7}  //3 (pin for trig), 7 (pin for echo)
};

void setup() {
  Serial.begin (9600);
  Serial.println("Initializing device...");

  Wire.begin();

  //PCF8574P I2C address
  /*
    A0 A1 A2 address
    -  -  -  0x20
    +  -  -  0x21
    -  +  -  0x22
    +  +  -  0x23
    -  -  +  0x24
    +  -  +  0x25
    -  +  +  0x26
    +  +  +  0x27
  */
  pcf_us.begin(0x21);

  for (int i = 0; i <= 3; i++){
      pcf_us.pinMode(usPinMatrix[i][0], OUTPUT);
      pcf_us.pinMode(usPinMatrix[i][1], INPUT);
  };

};

void loop() {

  int us_pin, trigPin, echoPin, duration, distance;

  for (int i = 0; i <= 3; i++){

    Serial.print(usPinMatrix[i][0]);
    Serial.print(") ");
    Serial.print("Send sound...   ");

    pcf_us.digitalWrite(usPinMatrix[i][0], HIGH);

    pcf_us.digitalWrite(usPinMatrix[i][0], LOW);

    Serial.print("Switch off...   Reading from ");
    Serial.print(usPinMatrix[i][1]);
    Serial.print("...   ");

    duration = pulseIn(usPinMatrix[i][1], HIGH);
    distance = duration / 2 / 29.1;

    Serial.print("Duration: ");
    Serial.print(duration);
    Serial.print(" s   ");
    Serial.print(distance);
    Serial.println(" cm");

    if (usPinMatrix[i][0] == 3) Serial.println("");

  };

};

This is what I get when I run the code:

0) Send sound...   Switch off...   Reading from 4...   [Waiting] Duration: 0 s   0 cm
1) Send sound...   Switch off...   Reading from 5...   [Waiting] Duration: 0 s   0 cm
2) Send sound...   Switch off...   Reading from 6...   [Waiting] Duration: 0 s   0 cm
3) Send sound...   Switch off...   Reading from 7...   [Waiting] Duration: 0 s   0 cm

What am I doing wrong?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I found a working code (tested by myself) for this exact task. Here it is: http://cpre.kmutnb.ac.th/esl/learning/index.php?article=multi_hc-sr04_reading

Here's the code:

///////////////////////////////////////////////////////////////////////////////
// Author: RSP @ Embedded System Lab (ESL), KMUTNB, Bangkok/Thailand
// Date: 2015-05-25
// Board: Arduino with ATmega168/328P (5V/16MHz)
// Arduino IDE: version 1.0.6
// Description:
//   This Arduino Sketch demonstrates how to use an Arduino Uno
//   and a PCF8574A chip to interface with multiple ultrasonic distance 
//   sensor modules (up to 4 modules). 
///////////////////////////////////////////////////////////////////////////////

#include <Wire.h> // use the Wire library

// connect address pins: A0=0 (GND), A1=0 (GND), A2=0 (GND)
#define ADDR_BITS (0B000) // A0=0,A1=0,A2=0  
#define I2C_SLAVE_ADDR ((0B0111000) | ADDR_BITS) // 7-bit address

#define MAX_DISTANCE_IN_MM       (4000)   // max. valid value for distance
#define DURATION_TO_DISTANCE(x)  ((17*(x))/100) // usec -> mm.

const int ECHO_PIN = 2; // D2 pin (External Interrupt 0)
const int TRIG_PIN = 4; // D4 pin
const int LED_PIN = 13; // D13 pin

volatile uint32_t tH, tL, pulse_width = 0;
uint16_t dist_mm;       // distance in mm.
char sbuf[32];          // used for sprintf()

void setup() {
   pinMode( LED_PIN, OUTPUT );
   Wire.begin();
   TWBR = 12; // for 400kHz
   writeOutput(0xF0);
   attachInterrupt( 0, eint_isr, CHANGE ); // D2 pin (EINT0)
   Serial.begin( 115200 );
   delay(1000);
}

void writeOutput( byte value ) { // write one byte
  Wire.beginTransmission( I2C_SLAVE_ADDR );
  Wire.write( value ); 
  Wire.endTransmission();
}

byte readInput( void ) { // read one byte
  byte data = 0xff;
  Wire.requestFrom( I2C_SLAVE_ADDR, 1 ); 
  delayMicroseconds(4);
  if ( Wire.available() ) {
     data = Wire.read();
  }
  return data;
}

uint16_t read_ultrasonic_sensor( int pin ) {
  digitalWrite( LED_PIN, HIGH); 
  writeOutput( 0xF0 | (1 << pin) );
  writeOutput( 0xF0 );
  pulse_width = 0;
  while ( pulse_width == 0 ) {}  // wait until pulse_width > 0
  digitalWrite( LED_PIN, LOW ); 
  return DURATION_TO_DISTANCE( pulse_width ); 
}

void loop() {
  for (int i=0; i < 2; i++ ) {
    dist_mm = read_ultrasonic_sensor( i );
    if ( dist_mm > MAX_DISTANCE_IN_MM ) {
      Serial.println( "Out of range." );
    } else {
      sprintf( sbuf, "Sensor %d, %d.%1d cm", i, (dist_mm/10), (dist_mm%10) );
      Serial.println( sbuf );
    }
    delay(5);
  }
  delay( 250 );
}

volatile uint32_t timestamp;

void eint_isr() { // ISR for Ext. Interrupt
  timestamp = micros();  // read the timestamp (in microseconds)
  if ( digitalRead( ECHO_PIN ) == LOW ) { 
    tH = timestamp;
  } else { // HIGH
    tL = timestamp;
    pulse_width = (tL-tH);
  }
}

///////////////////////////////////////////////////////////////////////////////
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.