Synchronizing HC SR04 Ultrasonic sensor with shift register

Hello , as the title says i’m trying to synchronize multiple ultrasonic sensors with a shift register .
The way i’m doing this is by continuously shifting the information in the register by one bit , and then pulsing the sensor for the required time so that it sends an ultrasonic burst.
i have all the sensors connected to 1 interrupt pin , and calculate the distance that way.
Now this should work in theory , but it doesn’t in practise , and i get weird outputs.
For example when the first sensor is connected , it gets sent to the third output.
I am very confused , and this might be because i lack knowledge of the sr04.
The code is below and it’s quite short and simple.

const byte SRL = 8 ; 
const byte RCLK = 7 ; 
const byte SRLCLK = 6 ;
const byte ECHO = 3; 
const byte OE =  4 ;

void setup() {

pinMode ( SRL    , OUTPUT) ;
pinMode ( RCLK   , OUTPUT) ;
pinMode ( SRLCLK , OUTPUT) ;
pinMode ( OE     , OUTPUT) ;
pinMode ( ECHO, INPUT ) ;

digitalWrite(SRL    , LOW );
digitalWrite(RCLK   , LOW );
digitalWrite(SRLCLK , LOW );
digitalWrite(OE     , HIGH);
Serial.begin(38400);
attachInterrupt (digitalPinToInterrupt(ECHO) , push,CHANGE); 

}
void clkIn(){

digitalWrite(RCLK   , HIGH);
digitalWrite(RCLK   , LOW);

}
void sendPulse(){
  digitalWrite(OE     ,LOW);
  delayMicroseconds(20);
  digitalWrite(OE     ,HIGH);
  }
int dist[8] ={0} ; 
int ctr = 0; 
long int LM ;
byte t = 1 ;
void push(){
  if(!(PIND & 0b00001000) )//direct reading of port  , digitalRead might introduce some mistake
  {
    for (int i=0; i<8; i++ ){
    if( t & (1 << i))
    dist[i] = ((float)(micros()-(LM))/58)  ;
    }
  }
  else  LM = micros() ; 
  }




void loop() {


shiftOut(SRL,SRLCLK, MSBFIRST, t);
clkIn();
t = t<<1 ;
sendPulse();
delay(30);
ctr++;
if(!t) {
  t = 1 ;
  for(int i = 0 ; i< 8 ; i++ ){
  Serial.print(dist[i]); 
   Serial.print(" "); 
  }
  Serial.println("");
  ctr = 0 ; 
}



}

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png? PLEASE do not use a Fritzy image.

What is the application? How many SR04 units?

If you fire ALL the transmitters at the same time, how do you know their respective receivers are ONLY receiving the echo from their respective transmitters. They all transmit at the same ultrasonic frequency.

How are you powering your project?

google arduino multiple sr04

Thanks.. Tom... :)

Here’s the circuit.
It has only 1 sensor connected for simplicity but if it works it should work for 8 of them .
They are not all being triggered at the same time , as i said the shift register only has one of its output pins set to high at a time .

The HC-SR04 has pullups on the trigger input according to this schematic: https://uglyduck.ath.cx/HC-SR04E/HC-SR04.svgz

Thus when your shift register output enable is disabled, all triggers will be in the high state. When you enable the shift register, the bit position with "1" will stay high and all the rest will pulse low then high. I'm not sure what the HC-SR04s will do in that case, but it's probably not what you intended.

Hi,
OPs circuit;
e40cc0d13fbdbf35ec193af083efe6c92fc37289.png
If you have all the echo pins connected together how do you know the respective sensor receiver is the one that received the return pulse, or that you don’t get multiple return echo signals?

Did you google what I suggested?

Tom… :slight_smile:

MrMark: The HC-SR04 has pullups on the trigger input according to this schematic: https://uglyduck.ath.cx/HC-SR04E/HC-SR04.svgz

Thus when your shift register output enable is disabled, all triggers will be in the high state. When you enable the shift register, the bit position with "1" will stay high and all the rest will pulse low then high. I'm not sure what the HC-SR04s will do in that case, but it's probably not what you intended.

I think you might be on to something here. I will try doing something with this information

TomGeorge: If you have all the echo pins connected together how do you know the respective sensor receiver is the one that received the return pulse, or that you don't get multiple return echo signals?

i can't check if i have multiple return signals, but with the delay function i shouldn't be receiving more than 1 return signal. Because there are atleast 30 miliseconds between 2 triggers , that should be enough for a return signal , although i'm not sure , maybe i need to make the delay bigger .

DAoliHVAR: I think you might be on to something here. I will try doing something with this information i can't check if i have multiple return signals, but with the delay function i shouldn't be receiving more than 1 return signal. Because there are atleast 30 miliseconds between 2 triggers , that should be enough for a return signal , although i'm not sure , maybe i need to make the delay bigger .

How do you know which receiver received the echo(es)? There could/will be multiple reflections Tom.. :)

from what i understood from the datasheet , the sensors return an echo only after they have been triggered .So this is my logic (assuming i have 8 sensors)

Trigger sensor one
delay(30) < this could be longer
during the delay only the triggered sensor will pull the echo pin high and then low
use this to calculate distance , and put it in an array .

but this is assuming that the soundwave is sent , reflected once , and then dissapears.
I wouldn’t know hot to deal with multiple bounces off the walls in my room , and i don’t think the sensors deal with them either.
Probably after some time the sound is completely absorbed by the surrounding area.
I wish i had an osciloscope to see what is truly going on .
Right now i only have 1 ultrasonic sensor , and i try to have it trigger multiple times .

Now if what was said previously is true , i could be triggering all of the sensors by mistake .

Hi, Use another 595 in tandem, to multiplex the ECHO.

Tom.. :)

TomGeorge: Use another 595 in tandem, to multiplex the ECHO.

How're you going to keep track of the exact time it takes for the echo pulse to finish? There's no interrupt, so you'd have to be polling the pin all the time.

DAoliHVAR: I think you might be on to something here. I will try doing something with this information i can't check if i have multiple return signals, but with the delay function i shouldn't be receiving more than 1 return signal. Because there are atleast 30 miliseconds between 2 triggers , that should be enough for a return signal , although i'm not sure , maybe i need to make the delay bigger .

That schematic you linked to is interesting, as it shows that both the trig and echo have pull-up resistors.

Trigger: has to be actively pulled low by the Arduino to create a low signal, then to create the pulse you would be able to set the pin to INPUT for that time instead of OUTPUT, HIGH just as well, as the pull-up resistor will do the job to pull it high. It's normal though to drive it high. The device triggers upon the trigger signal going low. Therefore, you best keep your 595 outputs LOW for the unused sensors, only change the one you want to trigger. So you shift in that bit as 1 and the rest 0, enable it, wait 10µs, shift in all 0s, and enable it. Upon the enable the sensor is triggered.

Echo: you connect them all together. Now as all have a pull-up resistor in place, that implies to me that the manufacturer uses open collector outputs (which makes sense: it's cheaper and works just fine). One of the sensors closing its output will make no difference, as the other sensors pull down the line just fine. The solution here will be to put a diode in all the echo lines, pointing towards the sensor, then use the internal pull-up resistor on the echo pin to pull up the signal on the Arduino side. Now every individual sensor can pull low the input pin.

All in all, with that in mind, the 595 multiplexing on trig pins should work, as long as you don't set the outputs to high impedance, ever. That would be the same as sending a high trig signal to the sensor.

wvmarle:
That schematic you linked to is interesting, as it shows that both the trig and echo have pull-up resistors.

Trigger: has to be actively pulled low by the Arduino to create a low signal, then to create the pulse you would be able to set the pin to INPUT for that time instead of OUTPUT, HIGH just as well, as the pull-up resistor will do the job to pull it high. It’s normal though to drive it high.
The device triggers upon the trigger signal going low.
Therefore, you best keep your 595 outputs LOW for the unused sensors, only change the one you want to trigger. So you shift in that bit as 1 and the rest 0, enable it, wait 10µs, shift in all 0s, and enable it. Upon the enable the sensor is triggered.

Echo: you connect them all together. Now as all have a pull-up resistor in place, that implies to me that the manufacturer uses open collector outputs (which makes sense: it’s cheaper and works just fine). One of the sensors closing its output will make no difference, as the other sensors pull down the line just fine. The solution here will be to put a diode in all the echo lines, pointing towards the sensor, then use the internal pull-up resistor on the echo pin to pull up the signal on the Arduino side. Now every individual sensor can pull low the input pin.

All in all, with that in mind, the 595 multiplexing on trig pins should work, as long as you don’t set the outputs to high impedance, ever. That would be the same as sending a high trig signal to the sensor.

from the 595 datasheet it says that the outputs are high impedence whenever the output enable is pulled high , which is what I use to send the 10 us pulse . Meaning that they would all get triggered at once.
That is an obvious problem. And your solution (which doesn’t use the output Enable at all ) should work.
As for the second part i have a hard time understanding it.
From searching open cellector output , It is an npn transistor that is connected to ground.
Now , because the transistor has a pull up resistor on it (5v) , it will conduct and thus be connected to ground
which makes sense because the output pin should be held low . What i don’t understand is , how does a high output generate. If we bring 0v to the transistor it will close and the transistor won’t be connected to ground anymore . I’m really having a hard time understanding the second part. Why do we put diodes , won’t the line be pulled low anyway ? Can i use a normal LED since i don’t have regular diodes ?

//edit : i tried it with a diode and it seems to work , but i still can’t understand the concept of why it works . Also since i have only one Sensor , I try to connect more than one of the shift register outputs to it . I don’t see why this shouldn’t work , since it would only give me the same distances , but the program doesn’t know that it’s the same sensor. This works when I put 2 triggers on the same sensor , but once I put 3 triggers , it stops working and all my distance ouputs are 0. I don’t know if this is because i’m polling the sensor too often(i don’t think this is the case since I have atleast 60 ms pause before each poll) , or because of a bug in my code .
here is my current version of the code

 const byte SRL = 8 ; 
const byte RCLK = 7 ; 
const byte SRLCLK = 6 ;
const byte ECHO = 3; 
const byte OE =  4 ;


void setup() {

pinMode ( SRL    , OUTPUT) ;
pinMode ( RCLK   , OUTPUT) ;
pinMode ( SRLCLK , OUTPUT) ;
pinMode ( ECHO, INPUT_PULLUP ) ;

digitalWrite(SRL    , LOW );
digitalWrite(RCLK   , LOW );
digitalWrite(SRLCLK , LOW );
Serial.begin(38400);
shiftOut(SRL,SRLCLK, MSBFIRST, 0);
attachInterrupt (digitalPinToInterrupt(ECHO) , push,CHANGE); 

}
void clkIn(){

digitalWrite(RCLK   , HIGH);
digitalWrite(RCLK   , LOW);

}

int dist[8] ={0} ; 
int ctr = 0; 
long int LM ;
byte t = 1 ;
void push(){
  if(!(PIND & 0b00001000) )//direct reading of port  , digitalRead might introduce some mistake
  {

    dist[ctr] = ((float)(micros()-(LM))/58)  ;
    
    
  }
  else  LM = micros() ; 
  }




void loop() {


shiftOut(SRL,SRLCLK, MSBFIRST, t);
clkIn();
delayMicroseconds(15);
shiftOut(SRL,SRLCLK, MSBFIRST, 0);
clkIn();
t = t<<1 ;
delay(100);
ctr++;
if(!t) {
  
  t = 1 ;
  for(int i = 0 ; i< 8 ; i++ ){
   Serial.print(dist[i]); 
   Serial.print(" "); 
   dist[i] = 0 ;
  }
  Serial.println("");
  ctr = 0 ; 
 
}



}

Oh, for the diode part I just realise I actually have it wrong there. The diode works great for outputs that are active low (most open collector outputs work that way), this one is unusual: active high. So my thoughts got mixed up.

Connecting multiple triggers at the same time to the same outputs of the 595 won’t work as the outputs are driven, so you effectively short out the 595 outputs! Internal resistance makes that you still see a voltage, but if one goes high and another goes low, there’s a short between them. So don’t do this, not even for testing. Use a second HC-SR04.

I had to draw it out to come with a solution for this, but it should work this way:
schematic.png
“Arduino” goes to a pin set to INPUT_PULLUP.

Now if any of the HC-SR04 outputs a high signal (an active echo), the NPN transistor at the output (any small signal transistor will do fine) conducts, pulling down the Arduino signal. When all outputs are idle, the internal pull-up pulls up the Arduino pin to a high level.

You can connect many sensors this way - but do change your code to look for a LOW pulse rather than a HIGH one on the echo with pulseIn(). Also do add a 30000 µs timeout on the pulseIn (that’s 5 meter distance - 10 meters round trip). No need to wait for 1 second for an echo that never comes!

I googled the microcontroller the sensor uses and apparently it has open drain outputs. This from what I understand shouldn't change anything , just means that it uses a mosfet instead of a bjt. As far as your solution goes , I understand it as this . Since the open drain outputs are active high , most of the outputs will be low most of the time , thus pulling the arduino pin low . So even when one of the outputs tries to pull the arduino high , it will still be low because of all the other outputs . your solution effectively reverses this , turning the outputs into active low open drain outputs . am i correct in this ? Also when the trigger pin hasn't been pullsed yet , is the echo pin low , or is it floating , or something else i don't understand ?

also could i connect multiple outputs of the 595 to the sensor , by putting a diode facing the sensor on the 595 line , and a pulldown resistor on the sensor trigger pin ?

DAoliHVAR: your solution effectively reverses this , turning the outputs into active low open drain outputs . am i correct in this ?

Exactly. That way you can connect them together. If just any of the echo outputs is high, the Arduino pin is pulled low.

Also when the trigger pin hasn't been pullsed yet , is the echo pin low , or is it floating , or something else i don't understand ?

It should be driven low (as the open drain is activated), so it produces the echo signal by switching off the output, which is then pulled high by the 10k resistor.

also could i connect multiple outputs of the 595 to the sensor , by putting a diode facing the sensor on the 595 line , and a pulldown resistor on the sensor trigger pin ?

That should work indeed. I see you're getting a hang of it - great!

Hi,
Can you post a diagram showing how you have physically configured your sensors, that is, what direction are they pointed with respect to each other.

Is there an overlap in the area they cover?
schematic.png
This seems a lot of work when a tandem 595 would use less components.

Thanks… Tom… :slight_smile:

hey tom , yes the area that they would cover does overlap. And i'm doing this with 1 shift register 1.Because it's for a school project with such description. 2.Because at the moment i only have 1 shift register , and i'd have to wait 2 months for others to come from china . Best regards .

DAoliHVAR: 2.Because at the moment i only have 1 shift register , and i'd have to wait 2 months for others to come from china .

I'm sure you can find some local to you - cost a little more per register but after shipping cost not so much, considering how cheap the shift registers themselves are. Anyway, it can't cost much. By the way, when buying components never buy as much as you need. Get double the number (or more - especially for dirt cheap things like resistors, caps, and indeed shift registers). Barely more cost, and you are bound to use them again sooner or later. Also a good precaution for when you blow one up.

TomGeorge: This seems a lot of work when a tandem 595 would use less components.

One transistor per output only. Not that much more work.

How can you accurately time the echo as it comes in on a shift register, other than a loop that checks the status time and again?

wvmarle: I'm sure you can find some local to you - cost a little more per register but after shipping cost not so much, considering how cheap the shift registers themselves are. Anyway, it can't cost much.

you'd be surprised . I live in a country (would rather not say where) where these types of electronics aren't readily available . There is only one store that actually has these types of through hole components on supply , and they are very expensive . Mostly because they buy high quality parts ( since i am a beginner i don't mind low quality parts at all) , and because they are the only store , they can inflate the prices . Thus for the price that I would get 10 shift registers from china , i would only get one here. I sometimes buy from them when I must, but I try to avoid it . And since for this problem your solution seems to work , and i have transistors on hand , and it is how the problem was specified , I will use it . Thank you for all your help , and I will ask more questions if(when) I have them cheers :D

wvmarle: How can you accurately time the echo as it comes in on a shift register, other than a loop that checks the status time and again?

Sorry use a 4051 multiplex IC. on echo. Tom.. :)