Last active
December 25, 2019 14:45
-
-
Save Jamesits/8d164818946a65d0cafcd6203e3e5049 to your computer and use it in GitHub Desktop.
High-accuracy square wave generator (up to 55KHz) based on Arduino UNO, with runtime adjustable frequency, PWM width and offset. https://blog.swineson.me/high-frequency-square-wave-generator-based-on-arduino-uno/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// High-accuracy square wave generator | |
// based on Arduino UNO | |
// with runtime adjustable frequency, PWM width and offset | |
// Output wave at pin 13 | |
// by James Swineson <github@public.swineson.me>, 2017-05 | |
// https://gist.github.com/Jamesits/8d164818946a65d0cafcd6203e3e5049 | |
// See https://blog.swineson.me/high-frequency-square-wave-generator-based-on-arduino-uno/ | |
// for more information (article in Chinese) | |
// ESP8266 version: https://gist.github.com/Jamesits/92394675c0fe786467b26f90e95d3904 | |
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 = 1; | |
// width = 0.5; | |
// 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(); | |
} | |
prev_micros += cycle_time; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
支持一下