 # Arduino产生方波信号

Arduino可以使用PWM产生方波信号，在我的Arduino UNO R3上，支持PWM的输出口是pin 3,5,6,9,10,11这几个引脚，支持大约980Hz的PWM输出。这方面不再赘述。

• 固定频率，占空比，偏移量的方波
• 通过模拟口连接可调电位器，产生可变频率、占空比、偏移量的方波
```// High-accuracy square wave generator
// based on Arduino UNO
// with runtime adjustable frequency, PWM width and offset
// Output wave at pin 13

double freq; // Hz
double offset; // percent (0.0 to 1.0)
double width; // percent (0.0 to 1.0)

// unit: microsecond
unsigned long cycle_time;
unsigned long raising_edge;
unsigned long falling_edge;
unsigned long prev_micros;

// compare 2 unsigned value
// true if X > Y while for all possible (X, Y), X - Y < Z
#define TIME_CMP(X, Y, Z) (((X) - (Y)) < (Z))

inline void setHigh() {
// 2 CPU cycles to balance execution time with setLow()
// this is based on measurement on Arduino UNO R3, your mileage may vary
PORTB = B00100000;
PORTB = B00100000;
}

inline void setLow() {
PORTB = B00000000;
}

void setup() {
DDRB = B00100000;

prev_micros = micros();

while(1) {

// frequency: 0.1-102.4 Hz
// width: 0-100%
// offset: 0-100%
//freq = (double)(analogRead(1) + 1) / 10;
//width = (double)(analogRead(0) + 1) / 1024;

// OR manual settings
// max possible frequency is around 55000Hz with <1KHz deviation
// based on measurements on Arduino UNO R3
// you may get to ~77500Hz with significantly larger deviation
// note: please uncomment the next 3 expressions, then
// move the following 6 expressions ahead of while loop
// if you are going to use manual settings, because it is no worth
// to recalculate them.
freq = 50;
width = 0.3;
offset = 0.0;

cycle_time = 1000000 / freq;
raising_edge = (unsigned long)(offset * cycle_time) % cycle_time;
falling_edge = (unsigned long)((offset + width) * cycle_time) % cycle_time;

if (width + offset < 1) {
// raising edge should appear earlier
while (TIME_CMP(micros(), prev_micros + raising_edge, cycle_time)); setHigh();
while (TIME_CMP(micros(), prev_micros + falling_edge, cycle_time)); setLow();
} else {
// falling edge should appear earlier
while (TIME_CMP(micros(), prev_micros + falling_edge, cycle_time)); setLow();
while (TIME_CMP(micros(), prev_micros + raising_edge, cycle_time)); setHigh();
}pin
prev_micros += cycle_time;
}
}
```

• PORTB表示的是控制pin8-pin13的寄存器，最高的两位6&7不使用。
• 可以改变B00100000来在其他pin脚上产生方波信号
• 同样的PROTD寄存器控制digital pin0-pin7