Go Down

Topic: A Gated Burst Generator For 40KHz Sonar (Read 3798 times) previous topic - next topic


Dec 21, 2015, 11:34 pm Last Edit: Dec 23, 2015, 01:25 pm by Arctic_Eddie
I have a project designing an RC barge( 4 feet long ) carrying a 50W 40KHz sonar transmitter and four sensors in a phased array scheme. I needed an externally tunable burst generator with a software controlled number of cycles within the burst. The first attempt worked but the circuit was complex and prone to wiring errors if a prototype was built. It also had only a cycle count range of 1 - 8 cycles. I needed something more software oriented with less circuitry but it suffered from gate position jitter since the oscillator was running independent of the Arduino. After recently discovering direct port/pin read and write commands, I settled on this version which works quite well and has a count range from 1 - 255. This could be extended by using a variable larger than uint8_t. Shown in the first attachment is a scope image showing four cycles and the enabling gate signal. There was a slight delay between the burst cycles and the gate due to programming delay in the sketch, about 180nsec. This is solved by inserting an RC delay circuit between two gates of a CD4049 inverter. This is shown in the second attachment, the Eagle schematic. The code for the sketch is shown below.

One thing that I wanted to use to monitor the state of the 40KHz waveform was the statement:

while( READ_OSC ) {} and while( !READ_OSC ) {}

However, this did not work because the argument apparently does not return a value to the 'while()' evaluator. I ended up using the version shown in the sketch. It probably has a similar execution time.

I used a Mega2560 for my project because it has many other things to do and needed large memory and I/O pins. The burst function should work fine in any 16MHz Arduino such as the Nano and Pro Mini.

I hope someone finds this code and schematic useful for their project.

Code: [Select]

// SonarBurstTest24, Direct pin read/write version, 12/21/2015
// Test of a gated burst of 'n' cycles using a CD4047 external oscillator at 40KHz
//  and an RC shifted CD4049 for gate/pulse alignment

/*  Port details
    * Write pin PORTC |= B10000000 // Set bit 7 in port C to high, D30
    * Write pin PORTC &= B01111111 // Set bit 7 in port C to low,  D30
    * Read pin  PINC  &  B01000000 // Read bit 6 in port C,        D31
    * Write pin PORTC |= B00100000 // Set bit 5 in port C to high, D32
    * Write pin PORTC &= B11011111 // Set bit 5 in port C to low,  D32
    * D37 - D30 = PC0 - PC7

#define OSC_EN_PIN          30                    // Oscillator enable pin
#define OSC_MON_PIN         31                    // Oscillator monitor pin
#define GATE_OUT_PIN        32                    // Gate output pin
#define NUM_CYCLES          4                     // Temporary burst count
#define CYCLE_TIME          500                   // How often to repeat loop
#define START_OSC           (PORTC |= B10000000)  // Set bit 7 in port C to high, D30
#define STOP_OSC            (PORTC &= B01111111)  // Set bit 7 in port C to low, D30
#define READ_OSC            (PINC  &  B01000000)  // Read bit 6 in port C, D31
#define START_GATE          (PORTC |= B00100000)  // Set bit 5 in port C to high, D32
#define STOP_GATE           (PORTC &= B11011111)  // Set bit 5 in port C to low, D32

void setup()
    pinMode( OSC_MON_PIN, INPUT );      // Input from external 40KHz oscillator
    pinMode( OSC_EN_PIN, OUTPUT );      // Output for oscillator start/stop
    pinMode( GATE_OUT_PIN, OUTPUT );    // Output for gate high/low
    digitalWrite( OSC_EN_PIN, LOW );    // Oscillator is not running yet
    digitalWrite( GATE_OUT_PIN, LOW );  // Gate output is low

void loop()
    GatedBurst( NUM_CYCLES );           // Stay in function until count completes
    delay( CYCLE_TIME );                // Run auto repeat for testing

void GatedBurst( uint8_t burstcount )
    // Count external clock within gated window until burstcount reaches countdown
    uint8_t cyclecount, state;          // Local counter and pin status
    cyclecount = burstcount;            // Set counter
    START_OSC;                          // Start the oscillator

    // Waste the first negative and positive half cycle
    //  since we don't know exactly when it starts and the first
    //  half cycle is slightly longer than the rest
        state = READ_OSC;               // Get the state
    while( !state );                    // While osc low
        state = READ_OSC;               // Get the state
    while( state );                     // While osc high
    // Start the loop that opens the gate until cyclecount reaches zero
    while( cyclecount )                 // While counting down to zero
    {                                   // Oscillator is now low
            state = READ_OSC;           // Get the state
        while( !state );                // While osc low
        START_GATE;                     // Make gate signal high on rising edge
        cyclecount--;                   // Reduce the cycle counter
            state = READ_OSC;           // Get the state
        while( state );                 // While osc high

    // Wait for the last low half cycle to finish
        state = READ_OSC;               // Get the state
    while( !state );                    // While osc low
    STOP_GATE;                          // Make gate signal low
    STOP_OSC;                           // Stop the oscillator


Dec 22, 2015, 10:20 pm Last Edit: Dec 22, 2015, 10:20 pm by MarkT
You need to put parentheses around your macro expansions:
Code: [Select]

#define READ_OSC            (PINC  &  B01000000)

Then expressions like ! READ_OSC will do what you expect.[/code]
[ I DO NOT respond to personal messages, I WILL delete them unread, use the forum please ]


They work as is but I'll add them for consistency. I assumed that a #define statement was just a text substitution that the compiler uses during the first phase.


Yes, only textual so adding parentheses to a compound expansion is always a good idea - you don't
necessarily know the expression(s) it will be substituted into nor the relative precedence of the operators
in the macro-body and the macro-expansion site...
[ I DO NOT respond to personal messages, I WILL delete them unread, use the forum please ]


Understood and thanks for the info.

If it's something like:

#define OSC_EN_PIN    30

then it's likely OK.

However, if it's something like:

#define RATIO    (NUM / DEN)

then it's more likely to work as intended.


Dec 23, 2015, 05:16 pm Last Edit: Dec 23, 2015, 05:24 pm by raschemmel
Why don't you use delayMicroseconds in a FOR loop with a variable index "n" so it drops it drops out of loop when "n" = 0 ?
The ON time = 25 uS/2.
The OFF time = 25 - ON time.

 Put the FOR loop in an IF statement that checks Transmit boolean flag.


I had considered that but found two reasons for going to the direct port sampling and control. First, the oscillator has to be externally tunable in real time as the sonar transducer has a sharp resonance and not necessarily at 40KHz. Second, using high level commands causes too much of delay between the clocks and the gate. As you can see in the waveform, the clock starts before the gate and finishes later but the gate is exactly aligned. This works quite well when the transducer is driven by an H-bridge. The clock toggles the bridge back and forth but the gate signal applied to the bridge enable pins allows only the required signal to pass through to the transducer. My original circuit accomplished this task but needed six chips. This one only needs two and has a wider burst count range.


This may be a silly question but if you need a frequency generator, why don't you use a frequency generator, ie: MAX038 FREQUENCY GENERATOR


MAX038 is out of production, can't get one anymore.
Can you recommend a part that is currently available?
and to top it off:
High-Frequency Waveform Generator
Data Sheet
This product is No Longer Available.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.


Dec 24, 2015, 01:07 pm Last Edit: Dec 24, 2015, 01:26 pm by Arctic_Eddie
Finding a tunable oscillator is no problem as the CD4047 works nicely. The problem was generating the gate signal with software controlled number of cycles and phase aligned. These two signals are essential to make the H-bridge operate correctly. This scheme allows me to control the burst length directly and dynamically from the laptop program. Each command packet going to the boat contains a burst length number so it can be adjusted as needed. Every sonar pulse can be different, if needed.

For example, the command "c/f/12" means:
c = capture a scan
f = use all 4 of the receivers where each one has a unique bit flag. Four bits is hex 0xf.
12 = use 12 cycles in the burst
/ = delimiter

This string goes from the laptop to the shore station controller, Mega2560, by 2Mbps serial link then to the boat/barge in enumerated numeric form by nRF2401L+PA+LNA. Barge maneuvering is controlled by a totally separate nRF24 channel. The antenna polarization on one link is vertical while the other is horizontal and widely separated in frequency.


Dec 24, 2015, 04:21 pm Last Edit: Dec 24, 2015, 04:26 pm by raschemmel
What is the purpose of all this ? (what's the reason you need sonar ?)


This project is called the Body Barge and is intended to provide a service to local law enforcement in finding drowning victims and evidence in small lakes and creeks in the south Pinellas County area of Tampa Bay, FL. On a regular basis, a child is reported missing from a caretakers house, usually grandma. The child has figured out how to unlock the back door while grandma is snoozing in her recliner, fallen into the lake, and drowns. The child is reported missing after grandma wakes up which is usually too late.

The barge is a double pontoon boat, like a party barge, about four feet long and made from thin wall PVC tubing and propelled by twin water jets using bilge pumps. It is controlled by a joystick box and an independent nRF24 link. The sonar is a 50W 40KHz transducer module used in ultrasonic cleaning tanks. It has a 60° beam width. The four receivers are ceramic sensors designed for the same frequency and arranged in a square around the TX. A bandpass opamp circuit will prepare the signals for processing by four Nanos. Each Nano will be triggered at the same time by the leading edge of the TX gate signal. The echoes will be digitized at 51.2KHz using the PlainADC library. Each set of 512 10 bit integers will be sent to shore in 32 byte packets. Each Nano will have control of another nRF2401 radio sequentially until all data is returned to the shore station then to the laptop by a 2Mbps serial/usb adapter. My other post in this forum describes how that was solved.

The data from each of the sensors will be analyzed on a laptop using a program written in Lazarus, visual Pascal. The data will be treated as a phased array, X and Y with Z as depth, and produce a 4D image, 3D with colorized echo strength. The image will slide down the display as a waterfall with the overlapping part of the new image and all previous averaged for S:N ratio improvement. That part is not written yet.

In use, a barge owner will receive a call from a local law enforcement agency that a body or evidence needs to be found. The owner will take the barge and the laptop to the site, usually grandmas back yard. The barge is launched and a serpentine search path is started. The operator and search coordinator will watch the display until an item of interest is spotted. The barge will then hover over the spot and a blinking mast light turned on. The divers will check the lake bottom after the barge moves out of the way. If nothing is found then the barge will continue the search. Several barges will be constructed so that someone is available to any agency in south Pinellas.

This project has been underway for about eight months and would not have been possible without the Arduino technology and the IDE.


You really should put together a post in fhe Exhibition/ Gallery when you get it all dialed in.
It's a very comprehensive utilization of inexpensive off the shelf hobbyist technology to create a professional tool for Law Enforcement.
Well done .


Thank you for the compliment. When it's finished, I'll put together a complete package with drawings, schematic, and code and post it as you suggest.

Arduino components, the IDE, this forum, and sellers like Adafruit, Sparkfun, and many others, are the real key to projects like this. The limit is really just imagination.

Go Up