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

参考