# 100khz square wave with 50% duty cycle

How to generate 100khz square wave with 50% duty cycle using arduino uno The following code was tried but did not give appropriate output

``````void setup() {
// initialize digital pin 13 as an output.
pinMode(13, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
delayMicroseconds(5); // wait for 5 micro seconds, 100khz frequency with  50%
// duty cycle
digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
delayMicroseconds(5);              // wait for 5 micro seconds
}
``````
• arduino.cc/en/Reference/DelayMicroseconds and arduino.cc/en/Reference/Micros explain that the micros has a resolution of 4µS: "has a resolution of four microseconds (i.e. the value returned is always a multiple of four)." Commented Jun 27, 2016 at 6:01
• Let us start with something easy: What are you assuming about loop() and digitalWrite()? 0 us? Commented Jul 27, 2016 at 12:22

The problem with your program is that it does not loop fast enough. Each call to `delayMicroseconds()` should take roughly the requested time to execute, but the CPU also needs time to execute the rest of your code, including the time needed to return from `loop()` and call it again. The period of the signal ends up being considerably longer than the desired 10 µs.

The simplest software-only approach would be to get rid of the delay using the technique described in the Blink Without Delay Arduino tutorial. With one twist: instead of

``````// save the last time you blinked the LED
previousMillis = currentMillis;
``````

you would use

``````// save the last time you should have blinked the LED
previousMillis += interval;
``````

This way the small timing errors do not add up: you get, on average the correct period. Oh, and obviously, you track time in microseconds, not milliseconds:

``````const uint16_t TOGGLE_TIME = 5;  // toggle pin every 5 us

void setup() {
pinMode(13, OUTPUT);
}

void loop() {
static uint16_t last_toggle;
static uint8_t pin_state = LOW;

if ((uint16_t) micros() - last_toggle >= TOGGLE_TIME) {
pin_state = !pin_state;       // invert pin state
digitalWrite(13, pin_state);
last_toggle += TOGGLE_TIME;
}
}
``````

This may somehow work if you have a fast enough Arduino, maybe a Due or a Zero. If you have an AVR-based board (like the Uno and actually most Arduinos), you will not get anything faster than ≈ 50 kHz with this. This is because `digitalWrite()` is sooo slooow, it cannot cope with your 100 kHz. You can improve things by using direct port access[] instead of `digitalWrite()`:

``````void loop() {
static uint16_t last_toggle;

if ((uint16_t) micros() - last_toggle >= TOGGLE_TIME) {
PINB = _BV(PB5);             // invert pin state
last_toggle += TOGGLE_TIME;
}
}
``````

Now you have roughly the requested frequency, but with some terrible jitter: testing on my Uno I could see each level being held for slightly less than 5 µs. Then, from time to time, one level is held for ≈ 9 µs. Things could still be made faster by wrapping the `if` inside an infinite loop, instead of relying on the Arduino core to repeatedly call `loop()`:

``````void loop() {
uint16_t last_toggle = 0;

for (;;) {  // infinite loop
if ((uint16_t) micros() - last_toggle >= TOGGLE_TIME) {
PINB = _BV(PB5);             // invert pin state
last_toggle += TOGGLE_TIME;
}
}
}
``````

And now the signal looks still worse: with the program running faster, levels are held most of the time for only 3.5 µs, and then one out of every ≈ 4 levels is held for about 9 µs. The average frequency is probably right, but the jitter is absolutely awful, which is likely due to the 4 µs resolution of `micros()` noted by user Talk2.

The conclusion from these tests is: your only hope to get a somewhat clean signal at this frequency is to generate it in hardware, not in software. Choose one of the timers and have it generate the signal you want. I would avoid timer 0, as it is needed by the Arduino timing functions (`delay()`, `millis()`...). Here is how it can be done with timer 2:

``````void setup() {
// The output will be on digital 3 = PD3 = OC2B.
pinMode(3, OUTPUT);

// Configure timer 2 for PWM @ 10 kHz on OC2B.
TCCR2A = _BV(COM2B1)  // non-inverting PWM on OC2B
| _BV(WGM20)   // mode 7: fast PWM, TOP = OCR2A
| _BV(WGM21);  // ditto
TCCR2B = _BV(WGM22)   // ditto
| _BV(CS21);   // clock @ F_CPU / 8
OCR2A  = 19;          // period = (19 + 1) * 8 CPU cycles
OCR2B  = 9;           // HIGH for (9 + 1) * 8 CPU cycles
}

void loop() {
// Nothing to do here, the signal is generated in hardware.
}
``````

And now you have a perfectly clean 10 kHz square wave, while your program is free to do other stuff at the same time. Notice that the output is now on pin 3: the pin choice is limited when using the hardware-based approach. Notice also that you loose the PWM capability on pin 11, since it depends on timer 2.

First, be sure to use the "{}" in the menu to show your code in a code block

``````void setup() {
// initialize digital pin 13 as an output.
pinMode(13, OUTPUT); }

// the loop function runs over and over again forever
void loop() {
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
delayMicroseconds(5); // wait for a second
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
delayMicroseconds(5); // wait for a second }
``````

I think you could benefit from reading the Secrets of PWM

using a microsecond delay will only give you an approximate pwm signal.

The Arduino's programming language makes PWM easy to use; simply call analogWrite(pin, dutyCycle), where dutyCycle is a value from 0 to 255, and pin is one of the PWM pins (3, 5, 6, 9, 10, or 11). The analogWrite function provides a simple interface to the hardware PWM, but doesn't provide any control over frequency. (Note that despite the function name, the output is a digital signal, often referred to as a square wave.)