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) {
// read everything from analog input (potentiometer)
// frequency: 0.1-102.4 Hz
// width: 0-100%
// offset: 0-100%
//freq = (double)(analogRead(1) + 1) / 10;
//width = (double)(analogRead(0) + 1) / 1024;
//offset = (double)analogRead(2) / 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