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.
// 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
do
{
state = READ_OSC; // Get the state
}
while( !state ); // While osc low
do
{
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
do
{
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
do
{
state = READ_OSC; // Get the state
}
while( state ); // While osc high
}
// Wait for the last low half cycle to finish
do
{
state = READ_OSC; // Get the state
}
while( !state ); // While osc low
STOP_GATE; // Make gate signal low
STOP_OSC; // Stop the oscillator
}