1 MHz pulse generating

Hello everyone. I need your help for generating 8 pulses 1 MHz square wave with arduino nano . I found a code in internet for it but this code for 40 kHz and i want to use it for 1 MHz. How can i change this code for 1 MHz? I changed delayMicroseconds but i cant set it for 1 MHz. Thanks. Code is below:

bool triggered = false;
bool Trig_in_state = false;

void setup() {

DDRD |= B00111000; // Sets D3, D4, D5 outputs
DDRB |= B00000100; // Sets D10 as output

PCICR |= (1 << PCIE0); //enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); //Set pin D8 (trigger pin) set to fire interrupt on state change.
PCMSK0 |= (1 << PCINT1); //Set pin D9 (echo in) set to fire an interrupt on state change.

}

void loop() {
if(triggered)//Burst code starts...
{
delayMicroseconds(150);
/*We have seen a delay of 250uS when we've made tests
between the 10us trig pulse and the 8 cycles burt. For some reasons, if I put 250us delay,
I get 350 on the oscilloscope. That's why I've made a 150us delay.
*/
PORTD &= B11011111; //D5 LOW //Activate the MAX323 PNP transistor for supply

PORTD |= B00001000; //D3 HIGH
PORTD &= B11101111; //D4 LOW
delayMicroseconds(12);//12us so around 40KHz. Freq = 1/2*12us
PORTD &= B11110111; //D3 LOW
PORTD |= B00010000; //D4 HIGH
delayMicroseconds(12);
//We do this 8 times...
PORTD |= B00001000; //D3 HIGH
PORTD &= B11101111; //D4 LOW
delayMicroseconds(12);
PORTD &= B11110111; //D3 LOW
PORTD |= B00010000; //D4 HIGH
delayMicroseconds(12);

PORTD |= B00001000; //D3 HIGH
PORTD &= B11101111; //D4 LOW
delayMicroseconds(12);
PORTD &= B11110111; //D3 LOW
PORTD |= B00010000; //D4 HIGH
delayMicroseconds(12);

PORTD |= B00001000; //D3 HIGH
PORTD &= B11101111; //D4 LOW
delayMicroseconds(12);
PORTD &= B11110111; //D3 LOW
PORTD |= B00010000; //D4 HIGH
delayMicroseconds(12);

PORTD |= B00001000; //D3 HIGH
PORTD &= B11101111; //D4 LOW
delayMicroseconds(12);
PORTD &= B11110111; //D3 LOW
PORTD |= B00010000; //D4 HIGH
delayMicroseconds(12);

PORTD |= B00001000; //D3 HIGH
PORTD &= B11101111; //D4 LOW
delayMicroseconds(12);
PORTD &= B11110111; //D3 LOW
PORTD |= B00010000; //D4 HIGH
delayMicroseconds(12);

PORTD |= B00001000; //D3 HIGH
PORTD &= B11101111; //D4 LOW
delayMicroseconds(12);
PORTD &= B11110111; //D3 LOW
PORTD |= B00010000; //D4 HIGH
delayMicroseconds(12);

PORTD |= B00001000; //D3 HIGH
PORTD &= B11101111; //D4 LOW
delayMicroseconds(12);

PORTD &= B11000111; //D3, D4, D5 LOW //We have finished the burst. We set everything to low

PORTB |= B00000100;
/Rember, after the 8 cycles, the echo out pin, D10, is set
to high till we receive the bounced echo signal.
/
triggered = false; //Reset the triggered value
}
}

ISR(PCINT0_vect){
//If digital D8 is high -> trigger was activated
if(PINB & B00000001){
Trig_in_state = true; //Set the Trig_in_state to true since we've detected the trigger pulse
}
//If trigger pin is low, the 10us pulse is over and we start the code
else if(Trig_in_state)
{
triggered = true; //Set trigered state to true
Trig_in_state = false; //Reset the D8 pin state
}

/*After the 8cycle burst each time there will be an interruption, that could be made by D8 or D9
since those are the only 2 pins set as interrupt active
So, since D8(trigger) is already low till next measurement, only D9 (echo in) could fire the interruption
So, when we detect that, we set the echo out pin to low (D10) and end the echo pulse
IMPORTANT: A better way to do this, is to also measure the echo in frequency to make sure
it is around 40KHz, but I haven't done that. Works like this as well.
*/
PORTB &= 11111011; //D10, echo pin out to LOW
}

First of all, welcome to the forum. It would be immensely helpful if you read the "How to use this Forum" near the top of every forum category. That way, you would know how to post your code in a far easier to read format, etc.

Second, you realize that the period of a 1MHz square wave is 1µS. So, using the delayMicroseconds function is, pretty much, not going to work.

Third, the clock speed of a Nano is 16Mhz, so that gives you only 16 instruction cycles to get things done within a space of 1µS.

I would say, if this is even possible, your best bet would be to use PWM, with some sort of timer gating [if this is even possible--I'd have to dig into the documentation]. And, very likely, you are going to need to dig into the guts of the AVR PWM mechanism and fiddle with the actual registers. So, you've bit off a rather challenging project. Something like:

  • Start PWM
  • Using a timer not used by the PWM module, write a value to the Timer register that will cause a Timer interrupt after an 8µS count.
  • In the Timer interrupt, stop the PWM [or set it to 0%].

But, along with all of that, because of the limited number of instruction cycles, and the fact that each instruction cycle burns 62.5nS, you will have to sum in the time it takes to execute these instructions, and adjust timing to compensate. Also, an interrupt might be too time intensive, so that might be a deal breaker--if that turns out to be the case, try polling the Timer Overflow flag, and react when it changes. Again, a challenging puzzle--if attempted on the Nano.

You might consider using something like a Duo, instead. It has a clock speed of 84MHz -- which provides a lot more head room for something like this.

I found a code in internet for it but this code for 40 kHz and i want to use it for 1 MHz.

Very bad idea, because it does lots of things you don't need. It will never work for your task.

You can do this with a timer clocked at 1 MHz and controlling an output pin, or with direct port manipulation and carefully calculated delays. For example, to pulse a port pin at 1 MHz for one cycle (not tested, might need 6 NOP instructions):

#define NOP __asm__ __volatile__ ("nop\n\t")

PORTD |= 1<<PD3; //set PD3 high and delay 7 machine cycles
 NOP; // delay 62.5ns on a 16MHz AtMega
 NOP; // delay 62.5ns on a 16MHz AtMega
 NOP; // delay 62.5ns on a 16MHz AtMega
 NOP; // delay 62.5ns on a 16MHz AtMega
 NOP; // delay 62.5ns on a 16MHz AtMega
 NOP; // delay 62.5ns on a 16MHz AtMega
 NOP; // delay 62.5ns on a 16MHz AtMega 
PORTD &= ~(1<<PD3); //set PD3 low
 NOP; // delay 62.5ns on a 16MHz AtMega
 NOP; // delay 62.5ns on a 16MHz AtMega
 NOP; // delay 62.5ns on a 16MHz AtMega
 NOP; // delay 62.5ns on a 16MHz AtMega
 NOP; // delay 62.5ns on a 16MHz AtMega
 NOP; // delay 62.5ns on a 16MHz AtMega
 NOP; // delay 62.5ns on a 16MHz AtMega

jremington:
You can do this with a timer clocked at 1 MHz and controlling an output pin, or with direct port manipulation and carefully calculated delays. For example, to pulse a port pin at 1 MHz for one cycle:

#define NOP __asm__ __volatile__ ("nop\n\t")

PORTD |= 1<<PD3; //set PD3 high and delay 7 machine cycles
NOP; // delay 62.5ns on a 16MHz AtMega
NOP; // delay 62.5ns on a 16MHz AtMega
NOP; // delay 62.5ns on a 16MHz AtMega
NOP; // delay 62.5ns on a 16MHz AtMega
NOP; // delay 62.5ns on a 16MHz AtMega
NOP; // delay 62.5ns on a 16MHz AtMega
NOP; // delay 62.5ns on a 16MHz AtMega
PORTD &= ~(1<<PD3); //set PD3 low
NOP; // delay 62.5ns on a 16MHz AtMega
NOP; // delay 62.5ns on a 16MHz AtMega
NOP; // delay 62.5ns on a 16MHz AtMega
NOP; // delay 62.5ns on a 16MHz AtMega
NOP; // delay 62.5ns on a 16MHz AtMega
NOP; // delay 62.5ns on a 16MHz AtMega
NOP; // delay 62.5ns on a 16MHz AtMega

Nice! And, in case it isn't clear to the OP, "PD3" is, on the Nano, Pin 3. And, in fact, this work all the way up to Pin 7:

PD3 = Pin 3
PD4 = Pin 4
PD5 = Pin 5
PD6 = Pin 6
PD7 = Pin 7

Beyond that, you will need to go to PORTB...

Also, this doesn't satisfy the 8 pulses, criteria. In fact, as written, it only produces one 500nS pulse.

Do you really need 8 separate signals? Why not one and split it?

Using timer1.

TCCR1A = _BV(COM1A0) | _BV(COM1B0); // toggle OC1A/B on Compare Match
TCCR1B = _BV(WGM12) | _BV(CS10); // CTC, no prescaler
OCR1A = 7; // 1 MHz

Sets 1MHz pulse train on pins 9 and 10.

DKWatson:
Using timer1.

TCCR1A = _BV(COM1A0) | _BV(COM1B0); // toggle OC1A/B on Compare Match
TCCR1B = _BV(WGM12) | _BV(CS10); // CTC, no prescaler
OCR1A = 7; // 1 MHz

Sets 1MHz pulse train on pins 9 and 10.

And does that produce eight 1 MHz pulses -- no more, no less? ...as requested by the OP?

See #4.

DKWatson:
See #4.

Do you mean #5?:

DKWatson:
Do you really need 8 separate signals? Why not one and split it?


Weird, huh? The numbers change. I think it has to do with whether you're logged in or not [otherwise not sure what causes this -- but I've seen it before] :wink: