Embedded C Program to Generate Square Wave Signal
while(1) { PORT |= (1 << PIN); delay(); PORT &= ~(1 << PIN); delay(); } to generate a square wave.Examples
How to Think About It
Algorithm
Code
#include <avr/io.h> #include <util/delay.h> int main(void) { DDRB |= (1 << PB0); // Set pin PB0 as output while(1) { PORTB |= (1 << PB0); // Set PB0 HIGH _delay_ms(500); // Delay 500 ms PORTB &= ~(1 << PB0); // Set PB0 LOW _delay_ms(500); // Delay 500 ms } return 0; }
Dry Run
Let's trace the square wave generation on pin PB0 with 500ms delay.
Set pin PB0 as output
DDRB |= (1 << PB0); sets the data direction register to output for pin PB0.
Set pin HIGH
PORTB |= (1 << PB0); sets pin PB0 HIGH (logic 1).
Delay 500ms
_delay_ms(500); pauses program for 500 milliseconds.
Set pin LOW
PORTB &= ~(1 << PB0); clears pin PB0 to LOW (logic 0).
Delay 500ms
_delay_ms(500); pauses program for 500 milliseconds.
Repeat loop
The loop repeats steps 2-5 indefinitely to generate continuous square wave.
| Step | Pin PB0 State | Delay(ms) |
|---|---|---|
| 1 | Output mode set | 0 |
| 2 | HIGH (1) | 0 |
| 3 | HIGH (1) | 500 |
| 4 | LOW (0) | 0 |
| 5 | LOW (0) | 500 |
| 6 | Repeat | 0 |
Why This Works
Step 1: Pin Setup
We set the GPIO pin as output using DDRB |= (1 << PB0); so it can send signals.
Step 2: Toggle Pin HIGH
Setting the pin HIGH with PORTB |= (1 << PB0); starts the square wave's high phase.
Step 3: Delay for Timing
The _delay_ms() function creates a pause to keep the pin state stable for half the wave period.
Step 4: Toggle Pin LOW
Setting the pin LOW with PORTB &= ~(1 << PB0); completes the wave cycle's low phase.
Alternative Approaches
#include <avr/io.h>
#include <avr/interrupt.h>
ISR(TIMER0_COMPA_vect) {
PORTB ^= (1 << PB0); // Toggle pin PB0
}
int main(void) {
DDRB |= (1 << PB0); // Set PB0 as output
TCCR0A = (1 << WGM01); // CTC mode
OCR0A = 249; // Compare value for 1ms at 16MHz/64
TIMSK0 = (1 << OCIE0A); // Enable compare interrupt
TCCR0B = (1 << CS01) | (1 << CS00); // Prescaler 64
sei(); // Enable global interrupts
while(1) {}
return 0;
}#include <avr/io.h> int main(void) { DDRB |= (1 << PB1); // Set PB1 as output (OC1A) TCCR1A = (1 << COM1A0) | (1 << WGM10); // Toggle OC1A on compare match, 8-bit PWM TCCR1B = (1 << WGM12) | (1 << CS10); // CTC mode, no prescaler OCR1A = 128; // 50% duty cycle while(1) {} return 0; }
Complexity: O(1) time, O(1) space
Time Complexity
The program runs in an infinite loop toggling a pin with fixed delays, so time per cycle is constant, O(1).
Space Complexity
Only a few variables and registers are used, so space complexity is O(1).
Which Approach is Fastest?
Hardware timer or PWM methods are faster and more precise than software delay loops, which waste CPU cycles.
| Approach | Time | Space | Best For |
|---|---|---|---|
| Software Delay Loop | O(1) | O(1) | Simple, low precision |
| Timer Interrupt | O(1) | O(1) | Precise timing, efficient CPU use |
| PWM Hardware | O(1) | O(1) | Automatic waveform, minimal CPU |