Last active
November 21, 2020 19:44
-
-
Save Tech-TX/572aab942d44638566e07036fe77a4c6 to your computer and use it in GitHub Desktop.
generic test of the various PWM functions for the ESP8266 Arduino
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
// A simple test to exercise PWM, Tone and Servo functions, all controlled from the terminal. | |
// All PWM sources and WiFi are initially disabled, individually enabled from the terminal. | |
// If you have an RC filter on one of the PWM pins, you can read it at the A0 analog input. | |
// A 200-3K res & 10uf cap R-C work @ 500-40KHz PWM. Make sure your board supports 3.3V Ain! | |
// | |
// This code is released to the public domain with no guarantees whatsoever | |
// "If it breaks in half, you get to keep both halves." ~ George Carlin | |
#include <core_esp8266_waveform.h> // so we can independently disable PWM sources | |
#include <ESP8266WiFi.h> //the main WiFi routines | |
#include <ArduinoOTA.h> //the main OTA routines | |
#include <WiFiUdp.h> //low-level protocol used for OTA | |
#include <ESP8266mDNS.h> //needed for OTA from IDE | |
#include <Servo.h> | |
#include <polledTimeout.h> | |
const char* ssid = "your SSID"; | |
const char* password = "your password/PSK"; | |
IPAddress staticIP(192, 168, 0, abc); // parameters below are for your static IP address, if used | |
IPAddress gateway(192, 168, 0, 1); | |
IPAddress subnet(255, 255, 255, 0); | |
IPAddress dns1(xxx, xxx, xxx, xxx); | |
IPAddress dns2(yyy, yyy, yyy, yyy); | |
const int CH1pin = 2; // D4, GPIO2 for PWM channel 1 (running if enabled & duty cycle > 0 or < 1023) | |
const int CH2pin = 5; // D1, GPIO5 for PWM channel 2 (inverse of channel 1 if enabled) | |
const int CH3pin = 0; // D3, GPIO0 for PWM channel 3 (only used in the RGB test) | |
const int TONEpin = 12; // D6, GPIO12 for a tone output | |
const int SERVO1pin = 13; // D7, GPIO13 for the first servo | |
const int SERVO2pin = 15; // D8, GPIO15 for the second servo | |
const int TP1 = 16; // D0, GPIO16 test point, toggles with each PWM inc/dec loop | |
const int TP2 = 14; // D5, GPIO14 test point, toggles with each PWM change | |
const int TP3 = 4; // D2, GPIO4 test point, toggles around timer1Interrupt ISR | |
uint32_t freqPWM = 977; // initial PWM frequency, max 977Hz if you want all 1023 steps | |
uint32_t dutyCycle = 1; // starting duty cycle of the PWM output(s) | |
uint32_t minDutyCycle = 0; // minimum duty cycle, 0-1023 (at 0 pin is low / PWM disconnected) | |
uint32_t maxDutyCycle = 1023; // maximum duty cycle 0-1023 (at 1023 pin is high / PWM disconnected) | |
uint32_t pauseDutyCycle = 10E3; // pause between duty cycle changes | |
int incPWM = 1; // increment/decrement the PWM sweep loop | |
uint32_t loopDelay = 0; // delay between INC/DEC loops | |
bool firstChannel = true; // one channel PWM output | |
bool secondChannel = true; // one or two channel PWM output | |
bool thirdChannel = true; // one, two or three channel PWM output | |
bool valueOutput = false; // print the PWM duty cycle values to the terminal | |
bool voltageOutput = false; // print the ADC value to the terminal | |
bool hold = true; // if true stops the INC/DEC cycling | |
bool rgbTest = false; // if true output dutyCycle on all 3 channels, changing values simultaneously | |
bool keepCH1 = false; // if true, freeze CH1 PWM during RGB test, +/-/d still effect it | |
bool eightChTest = false; // if true, output 20KHz PWM on 8 GPIOs (disconnect servos!) | |
uint32_t dutyCH1 = 0; // CH1 duty cycle for fixed RGB test | |
uint32_t toneFreq = 0; // default no tone output | |
uint32_t expiry = 0; // expiry for tone & servo commands | |
bool sirenTone = 0; // toggle for the siren tone output | |
bool sirenFreq = 0; // high/low frequency | |
int32_t servo1Angle = 90; // SERVO1 set to neutral but not enabled | |
int32_t servo2Angle = 90; // SERVO2 set to neutral but not enabled | |
int servoIncr = 5; // inc/dec for the servo sweep funtion | |
int servoStep = servoIncr; | |
bool waveServos = false; // if true, start sweeping the servos back and forth | |
uint16_t servoHigh = 0; // default alt method of driving servo1 off | |
uint16_t servoLow = 18; // milliseconds after the servo pulse | |
uint32_t ledPWM = 1025; // LED_BUILTIN PWM [0-1023] @ 1KHz | |
bool wifiDisabled = true; // WiFi initially disabled | |
bool otaEnabled = true; // OTA enabled/disabled | |
String command; // stores the requested command from the serial terminal | |
esp8266::polledTimeout::periodicFastUs pwmTimeout(pauseDutyCycle); // initially 10ms between PWM duty cycle changes | |
esp8266::polledTimeout::periodicMs servoTimeout(60); // fixed 60ms between servo sweep changes so it can settle | |
esp8266::polledTimeout::periodicMs sirenTimeout(650); // fixed 650ms between siren tone changes | |
Servo servo1; | |
Servo servo2; | |
void setup() { | |
Serial.begin(74880); // start serial for terminal | |
Serial.println(); | |
Serial.println(ESP.getFullVersion()); | |
Serial.println(F("\nPWM / Tone / Servo test program (press ? and <enter> for help)\n")); | |
pinMode(TP1, OUTPUT); // test point for outer loop | |
pinMode(TP2, OUTPUT); // test point for duty cycle changes | |
pinMode(TP3, OUTPUT); // test point for ISR | |
GPOC = (1 << 4); // TP3 / D2 used for checking timer1Interrupt() latency | |
pinMode(SERVO1pin, OUTPUT); // avoids high-impedance noise pickup | |
pinMode(SERVO2pin, OUTPUT); // avoids high-impedance noise pickup | |
analogWriteRange(1023); // due to new default AVR compatibility, https://github.com/esp8266/Arduino/pull/7456 | |
if (!wifiDisabled) { | |
initWiFi(); | |
if (otaEnabled) | |
initOTA(); | |
} else { | |
Serial.println(F("WiFi disabled, enter Y to enable it")); | |
disableWiFi(); | |
} | |
} | |
void loop() { | |
if (pwmTimeout && !hold) | |
sweepPWM(); | |
if (servoTimeout && waveServos) | |
sweepServos(); | |
if (sirenTimeout && sirenTone) | |
toggleSiren(); | |
commandCheck(); | |
if (WiFi.localIP() && (WiFi.status() == WL_CONNECTED) && otaEnabled) | |
ArduinoOTA.handle(); //see if we need to reflash | |
yield(); | |
} | |
void sweepPWM() { | |
digitalWrite(TP2, !digitalRead(TP2)); // toggle around duty cycle changes disabled for quick test | |
if (dutyCycle <= minDutyCycle) { // increase duty cycle, decrease for second channel | |
incPWM = 1; | |
digitalWrite(TP1, HIGH); // toggle the loop activity LED | |
if (valueOutput) | |
Serial.println(F("loop switch-over")); | |
delay(loopDelay); // completed one half sweep loop | |
} | |
if (dutyCycle >= maxDutyCycle) { | |
incPWM = -1; | |
digitalWrite(TP1, LOW); // toggle the loop activity LED | |
if (valueOutput) | |
Serial.println(F("loop switch-over")); | |
delay(loopDelay); // completed one half sweep loop | |
} | |
if (!rgbTest) { // sweep one or two channels in opposition from min to max and back | |
if (firstChannel) | |
analogWrite(CH1pin, dutyCycle); | |
if (secondChannel) | |
analogWrite(CH2pin, 1023 - dutyCycle); | |
if (valueOutput) { | |
Serial.print(F("CH1 = ")); | |
if (firstChannel) { | |
Serial.print(dutyCycle); | |
} else { | |
Serial.print(F("disabled")); | |
} | |
Serial.print(F(" CH2 = ")); | |
if (secondChannel) { | |
Serial.print(1023 - dutyCycle); | |
} else { | |
Serial.print(F("disabled")); | |
} | |
Serial.println(); | |
if (voltageOutput) { // this prints the PREVIOUS value, would need a delay to get current value | |
float volts = 3.3 * analogRead(A0) / 1024; | |
Serial.print(F("voltage = ")); | |
Serial.println(volts); | |
} | |
} | |
} else { // RGB test, sweep all 3 channels up and down together | |
if (valueOutput && (firstChannel || secondChannel || thirdChannel)) { | |
Serial.print(F("RGB channels at ")); | |
Serial.println(dutyCycle); | |
} | |
if (firstChannel && !keepCH1) | |
analogWrite(CH1pin, dutyCycle); // inverted for common-anode LEDs (1023 = bright with MOSFET drivers) | |
if (secondChannel) | |
analogWrite(CH2pin, dutyCycle); | |
if (thirdChannel) | |
analogWrite(CH3pin, dutyCycle); | |
} | |
dutyCycle += incPWM; | |
} | |
void sweepServos() { | |
servo1Angle += servoStep; | |
if (servo1Angle >= 180) { | |
servoStep = -(servoIncr); | |
servo1Angle = 180; | |
} | |
if (servo1Angle <= 0) { | |
servoStep = servoIncr; | |
servo1Angle = 0; | |
} | |
servo1.write(servo1Angle); | |
servo2Angle = 180 - servo1Angle; | |
servo2.write(servo2Angle); | |
} | |
void toggleSiren() { | |
sirenFreq = !sirenFreq; | |
tone(TONEpin, sirenFreq ? 440 : 585); | |
} | |
void commandCheck() { | |
if (Serial.available()) { // serial command processor | |
command = Serial.readStringUntil('\n'); | |
command.trim(); // strip the newline | |
if (command.equalsIgnoreCase("help") || command.equals("?")) // terminal commands list | |
{ | |
Serial.println(F("\nAvailable commands: (all commands terminated by <enter>)")); | |
Serial.println(F("2000f sets PWM frequency to 2000Hz, doesn't update until the duty cycle changes")); | |
Serial.println(F("r toggles RGB test mode, sweeping all 3 PWM outputs }else{ alternate CH1 & CH2")); | |
Serial.println(F("k toggles freezing CH1 PWM in RGB test, +/-/d still effect CH1")); | |
Serial.println(F("h toggles holding current duty cycle or continues the PWM/RGB sweep")); | |
Serial.println(F("+ increments the duty cycle while in HOLD, ignoring min/max")); | |
Serial.println(F("- decrements the duty cycle while in HOLD, ignoring min/max")); | |
Serial.println(F("300d set the duty cycle of CH1 to 300 while in HOLD")); | |
Serial.println(F("u toggles the first PWM channel on/off")); | |
Serial.println(F("c toggles the second PWM channel on/off")); | |
Serial.println(F("g toggles the third PWM channel on/off")); | |
Serial.println(F("10000p sets the pause between duty cycle changes to 10ms")); | |
Serial.println(F("30m sets PWM minimum duty cycle to 30/1023")); | |
Serial.println(F("900x sets PWM maximum duty cycle to 900/1023")); | |
Serial.println(F("1020j sets the LED_BUILTIN to 1020 (dim) with analogWrite, 'j' disables LED_BUILTIN")); | |
Serial.println(F("1020L sets the LED_BUILTIN to 1020 (dim) with startWaveform(high,low,0)")); | |
Serial.println(F("& toggles 8 channel 20KHz analogWrite() PWM test")); | |
Serial.println(F("o toggles printing the PWM values")); | |
Serial.println(F("v toggles printing the ADC input reading (in volts)")); | |
Serial.println(F("500t plays a 500Hz tone, 0t or t stops the tone, range 1Hz-20KHz")); | |
Serial.println(F("500e plays the tone for 500ms, 0e or e sets no expiry/infinite duration")); | |
Serial.println(F("q toggles the siren tone on/off")); | |
Serial.println(F("90s sets the 1st servo to 90 degrees, > 180 or 's' detaches the servo")); | |
Serial.println(F("90a sets the 2nd servo to 90 degrees, > 180 or 'a' detaches the servo")); | |
Serial.println(F("w toggles sweeping the servos from 0 to 180 and back")); | |
Serial.println(F("1500b sets the 1st servo to 90 degrees, 'b' detaches the servo")); | |
Serial.println(F("20n sets a 20ms pause after the servo1 pulse, default 18")); | |
Serial.println(F("y toggles WiFi & OTA on/off")); | |
Serial.println(F("z does an ESP.restart()")); | |
Serial.println(F("i displays the current settings\n")); | |
} else { | |
switch ( command.charAt(command.length() - 1) ) { // get the last byte (the requested command) | |
case 'u': case 'U': // U toggles the first PWM channel on/off | |
firstChannel = !firstChannel; | |
Serial.print(F("running PWM channels ")); | |
if (firstChannel) | |
Serial.print(F("1 ")); | |
if (secondChannel) | |
Serial.print(F("2 ")); | |
if (thirdChannel) | |
Serial.print(F("3")); | |
if (!firstChannel) { | |
analogWrite(CH1pin, 0); | |
stopWaveform(CH1pin); | |
} | |
if (!firstChannel && !secondChannel && !thirdChannel) | |
Serial.print(F("<none>")); | |
Serial.println(); | |
break; | |
case 'c': case 'C': // C toggles the second PWM channel on/off | |
secondChannel = !secondChannel; | |
Serial.print(F("running PWM channels ")); | |
if (firstChannel) | |
Serial.print(F("1 ")); | |
if (secondChannel) | |
Serial.print(F("2 ")); | |
if (thirdChannel) | |
Serial.print(F("3")); | |
if (!secondChannel) { | |
analogWrite(CH2pin, 0); | |
stopWaveform(CH2pin); | |
} | |
if (!firstChannel && !secondChannel && !thirdChannel) | |
Serial.print(F("<none>")); | |
Serial.println(); | |
break; | |
case 'g': case 'G': // G toggles the third PWM channel on/off | |
thirdChannel = !thirdChannel; | |
Serial.print(F("running PWM channels ")); | |
if (firstChannel) | |
Serial.print(F("1 ")); | |
if (secondChannel) | |
Serial.print(F("2 ")); | |
if (thirdChannel) | |
Serial.print(F("3")); | |
if (!thirdChannel) { | |
analogWrite(CH3pin, 0); | |
stopWaveform(CH3pin); | |
} | |
if (!firstChannel && !secondChannel && !thirdChannel) | |
Serial.print(F("<none>")); | |
Serial.println(); | |
break; | |
case 'h': case 'H': // H freezes at current duty cycle, or free-runs the sweep loops | |
hold = !hold; | |
if (hold) { | |
Serial.print(F("holding PWM at current CH1 duty cycle = ")); | |
Serial.println(dutyCycle); | |
if (voltageOutput) { // this prints the current value after a delay | |
delay(150); | |
float volts = 3.3 * analogRead(A0) / 1024; | |
Serial.print(F("voltage = ")); | |
Serial.println(volts); | |
} | |
} else { | |
analogWriteFreq(freqPWM); // start the PWM (must change duty cycle for PWM freq to update) | |
Serial.print(F("incrementing / decrementing PWM duty cycle at PWM freq = ")); | |
Serial.print(freqPWM); | |
Serial.println(F("Hz")); | |
} | |
break; | |
case '+': // + increment the duty cycle in HOLD, min / max ignored | |
if (dutyCycle < 1023) | |
dutyCycle++; | |
if (dutyCH1 < 1023) | |
dutyCH1++; | |
if (firstChannel) { | |
if (rgbTest && keepCH1) | |
analogWrite(CH1pin, dutyCH1); | |
else | |
analogWrite(CH1pin, dutyCycle); | |
Serial.print(F("dec duty cycle of CH1 to ")); | |
Serial.print(dutyCH1); | |
} | |
if (secondChannel && !rgbTest) { | |
analogWrite(CH2pin, 1023 - dutyCycle); | |
Serial.print(F(" duty cycle of CH2 set to ")); | |
Serial.print(1023 - dutyCycle); | |
} | |
if (rgbTest) { | |
if (secondChannel) | |
analogWrite(CH2pin, dutyCycle); | |
if (thirdChannel) | |
analogWrite(CH3pin, dutyCycle); | |
Serial.print(F(" duty cycle of CH2 & CH3 set to ")); | |
Serial.print(dutyCycle); | |
} | |
Serial.println(); | |
if (voltageOutput) { // this prints the current value after a delay | |
delay(150); | |
float volts = 3.3 * analogRead(A0) / 1024; | |
Serial.print(F("ADC input voltage = ")); | |
Serial.println(volts); | |
} | |
break; | |
case '-': // - decrement the duty cycle, min / max ignored | |
if (dutyCycle > 0) | |
dutyCycle--; | |
if (dutyCH1 > 0) | |
dutyCH1--; | |
if (firstChannel) { | |
if (rgbTest && keepCH1) | |
analogWrite(CH1pin, dutyCH1); | |
else | |
analogWrite(CH1pin, dutyCycle); | |
Serial.print(F("dec duty cycle of CH1 to ")); | |
Serial.print(dutyCH1); | |
} | |
if (secondChannel && !rgbTest) { | |
analogWrite(CH2pin, 1023 - dutyCycle); | |
Serial.print(F(" duty cycle of CH2 set to ")); | |
Serial.print(1023 - dutyCycle); | |
} | |
if (rgbTest) { | |
if (secondChannel) | |
analogWrite(CH2pin, dutyCycle); | |
if (thirdChannel) | |
analogWrite(CH3pin, dutyCycle); | |
Serial.print(F(" duty cycle of CH2 & CH3 set to ")); | |
Serial.print(dutyCycle); | |
} | |
Serial.println(); | |
if (voltageOutput) { // this prints the current value after a delay | |
delay(150); | |
float volts = 3.3 * analogRead(A0) / 1024; | |
Serial.print(F("ADC input voltage = ")); | |
Serial.println(volts); | |
} | |
break; | |
case 'd': case 'D': // 300d sets the duty cycle for CH1 to 300 in HOLD, min / max ignored | |
command.remove(command.length() - 1); | |
dutyCycle = (uint32_t) (command.toInt()); | |
if (dutyCycle > 1023) | |
dutyCycle = 1023; | |
dutyCH1 = dutyCycle; | |
Serial.print(F("duty cycle of CH1 set to ")); | |
Serial.print(dutyCH1); | |
if (secondChannel && !rgbTest) { | |
analogWrite(CH2pin, 1023 - dutyCycle); | |
Serial.print(F(" duty cycle of CH2 set to ")); | |
Serial.println(1023 - dutyCycle); | |
} | |
if ((secondChannel || thirdChannel) && rgbTest) { | |
if (secondChannel) | |
analogWrite(CH2pin, dutyCycle); | |
if (thirdChannel) | |
analogWrite(CH3pin, dutyCycle); | |
Serial.print(F(" duty cycle of CH2 and/or CH3 set to ")); | |
Serial.print(dutyCycle); | |
} | |
if (firstChannel) | |
analogWrite(CH1pin, dutyCycle); | |
if (voltageOutput) { // this prints the current value after a delay | |
delay(150); | |
float volts = 3.3 * analogRead(A0) / 1024; | |
Serial.print(F("voltage = ")); | |
Serial.println(volts); | |
} | |
Serial.println(); | |
break; | |
case 'f': case 'F': // 100f sets the PWM frequency to 100Hz, default ~1KHz | |
command.remove(command.length() - 1); | |
freqPWM = (uint32_t) (command.toInt()); | |
analogWriteFreq(freqPWM); | |
Serial.print(F("PWM frequency ")); | |
Serial.print(freqPWM); | |
Serial.println("Hz"); | |
break; | |
case 'p': case 'P': // 10000p sets the pause between duty cycle changes to 10ms | |
command.remove(command.length() - 1); | |
pauseDutyCycle = (uint32_t) (command.toInt()); | |
pwmTimeout.reset(pauseDutyCycle); | |
Serial.print(F("delay between duty cycle changes ")); | |
Serial.print(pauseDutyCycle); | |
Serial.println(" us"); | |
break; | |
case 'o': case 'O': // o toggles printing duty cycle values to serial terminal | |
valueOutput = !valueOutput; | |
break; | |
case 'v': case 'V': // v toggles printing the read ADC values to serial terminal | |
voltageOutput = !voltageOutput; | |
if (voltageOutput) { | |
Serial.println(F("analog read displayed")); | |
delay(150); | |
float volts = 3.3 * analogRead(A0) / 1024; | |
Serial.print(F("voltage = ")); | |
Serial.println(volts); | |
} else { | |
Serial.println(F("analog read disabled")); | |
} | |
break; | |
case 'm': case 'M': // 10m sets the minimum PWM duty cycle to 10/1022 | |
command.remove(command.length() - 1); | |
minDutyCycle = (unsigned int) (command.toInt()); | |
Serial.print(F("minimum duty cycle ")); | |
Serial.println(minDutyCycle); | |
break; | |
case 'x': case 'X': // 900x sets the maximum PWM duty cycle to 900/1022 | |
command.remove(command.length() - 1); | |
maxDutyCycle = (unsigned int) (command.toInt()); | |
Serial.print(F("maximum duty cycle ")); | |
Serial.println(maxDutyCycle); | |
break; | |
case 't': case 'T': // 500t plays a 500Hz tone, 0t or t stops the tone | |
command.remove(command.length() - 1); | |
toneFreq = (unsigned int) (command.toInt()); | |
if (toneFreq == 0) { | |
noTone(TONEpin); | |
Serial.println(F("tone stopped")); | |
} else { | |
tone(TONEpin, toneFreq, expiry); | |
Serial.print(toneFreq); | |
Serial.println(F("Hz tone output")); | |
} | |
break; | |
case 'e': case 'E': // expiry in ms for tone & servo commands | |
command.remove(command.length() - 1); | |
expiry = (unsigned int) (command.toInt()); | |
if ((expiry == 0) || (command.length() == 0)) { | |
expiry = 0; | |
Serial.println(F("expiry disabled")); | |
} else { | |
Serial.print(F("expiry for tone & servo = ")); | |
Serial.print(expiry); | |
Serial.println(F(" ms")); | |
} | |
break; | |
case 'q': case 'Q': // q toggles the siren tone on/off | |
sirenTone = !sirenTone; | |
if (!sirenTone) { | |
noTone(TONEpin); | |
Serial.println(F("siren tone stopped")); | |
} else { | |
// tone(TONEpin, sirenFreq ? 440 * 4 : 440 / 2); // alternating 1760/220Hz tone | |
tone(TONEpin, sirenFreq ? 440 : 585); // alternating polizei tone | |
Serial.println(F("siren tone output")); | |
} | |
break; | |
case 's': case 'S': // 90s puts the first servo at 90 degrees (neutral) | |
command.remove(command.length() - 1); | |
servo1Angle = (unsigned int) (command.toInt()); | |
if ((servo1Angle > 180) || (command.length() == 0)) { | |
servo1.detach(); | |
Serial.println(F("servo1 detached")); | |
} else { | |
servo1.attach(SERVO1pin); | |
servo1.write(servo1Angle); | |
Serial.print(F("servo1 angle ~ ")); | |
Serial.print(servo1Angle); | |
Serial.println(F(" degrees")); | |
} | |
break; | |
case 'a': case 'A': // 90a puts the second servo at 90 degrees (neutral) | |
command.remove(command.length() - 1); | |
servo2Angle = (unsigned int) (command.toInt()); | |
if ((servo2Angle > 180) || (command.length() == 0)) { | |
servo2.detach(); | |
Serial.println(F("servo2 detached")); | |
} else { | |
servo2.attach(SERVO2pin); | |
servo2.write(servo2Angle); | |
Serial.print(F("servo2 angle ~ ")); | |
Serial.print(servo2Angle); | |
Serial.println(F(" degrees")); | |
} | |
break; | |
case 'w': case 'W': // w toggles sweeping the servos from 0 to 180 and back | |
waveServos = !waveServos; | |
if (waveServos) { | |
Serial.println(F("sweeping servos")); | |
servo1.attach(SERVO1pin); | |
servo2.attach(SERVO2pin); | |
servo1.write(servo1Angle); | |
servo2Angle = 180 - servo1Angle; | |
servo2.write(servo2Angle); | |
delay(300); // give it a chance to slew to the initial position | |
} else { | |
Serial.print(F("stopping the servo sweep at ")); | |
Serial.print(servo1Angle); | |
Serial.println(F(" degrees (Servo1)")); | |
servo1.detach(); | |
servo2.detach(); | |
} | |
break; | |
case 'b': case 'B': // 1500b sets the 1st servo to 90 degrees, 'b' detaches the servo | |
command.remove(command.length() - 1); | |
servoHigh = (unsigned int) (command.toInt()); | |
if (command.length() == 0) { | |
stopWaveform(SERVO1pin); | |
Serial.println(F("servo1 detached")); | |
} else { | |
startWaveform(SERVO1pin, servoHigh, servoLow * 1000, 0); | |
Serial.print(F("servo1 pulse ")); | |
Serial.print(servoHigh); | |
Serial.println(F(" us")); | |
} | |
break; | |
case 'n': case 'N': // 20n sets a 20ms pause after the servo1 pulse, default 18 | |
command.remove(command.length() - 1); | |
servoLow = (unsigned int) (command.toInt()); | |
if (command.length() == 0) { | |
stopWaveform(SERVO1pin); | |
Serial.println(F("servo1 detached")); | |
} else { | |
startWaveform(SERVO1pin, servoHigh, servoLow * 1000, 0); | |
Serial.print(F("servo1 pause ")); | |
Serial.print(servoLow); | |
Serial.println(F(" ms")); | |
} | |
break; | |
case 'r': case 'R': // r toggles RGB test mode, sweeping all 3 PWM outputs simultaneously | |
rgbTest = !rgbTest; | |
if (rgbTest) { | |
Serial.println(F("sweeping all 3 PWM channels")); | |
hold = false; | |
} else { | |
Serial.println(F("stopping the RGB channel sweep")); | |
thirdChannel = false; | |
stopWaveform(CH3pin); | |
hold = true; | |
} | |
break; | |
case 'k': case 'K': // k toggles freezing CH1 PWM in RGB test, +/-/d still effect CH1 | |
keepCH1 = !keepCH1; | |
if (keepCH1) { | |
dutyCH1 = dutyCycle; | |
Serial.print(F("freezing CH1 PWM at ")); | |
Serial.println(dutyCH1); | |
} else { | |
Serial.println(F("sweeping CH1 with the other channels")); | |
} | |
break; | |
case 'j': case 'J': // 1020j sets the LED_BUILTIN to 1020 (dim), 'j' disables LED_BUILTIN | |
command.remove(command.length() - 1); | |
ledPWM = (unsigned int) (command.toInt()); | |
if ((ledPWM > 1023) || (command.length() == 0)) { | |
stopWaveform(LED_BUILTIN); | |
Serial.println(F("LED_BUILTIN detached")); | |
ledPWM = 1025; | |
} else { | |
// uint32_t ledHIGH = 1000 * ledPWM / 1023; | |
// uint32_t ledLOW = 1000 - ledHIGH; | |
// startWaveform(LED_BUILTIN, ledHIGH, ledLOW, 0); | |
analogWrite(LED_BUILTIN, ledPWM); | |
Serial.print(F("LED_BUILTIN PWM set to ")); | |
Serial.println(ledPWM); | |
} | |
break; | |
case 'l': case 'L': // 1020L sets the LED_BUILTIN to 1020 (dim) with startWaveform(high,low,0) | |
command.remove(command.length() - 1); | |
ledPWM = (unsigned int) (command.toInt()); | |
if ((ledPWM > 1023) || (command.length() == 0)) { | |
stopWaveform(LED_BUILTIN);; | |
Serial.println(F("LED_BUILTIN detached")); | |
ledPWM = 1025; | |
} else { | |
uint32_t ledHIGH = 1000 * ledPWM / 1023; | |
uint32_t ledLOW = 1000 - ledHIGH; | |
startWaveform(LED_BUILTIN, ledHIGH, ledLOW, 0); | |
Serial.print(F("LED_BUILTIN PWM set to ")); | |
Serial.println(ledPWM); | |
} | |
break; | |
case '&': // & toggles 8 channel PWM test on/off | |
eightChTest = !eightChTest; | |
if (!eightChTest) { | |
Serial.println(F("stopping 8CH PWM test")); | |
analogWrite(0, 0); | |
analogWrite(2, 0); | |
analogWrite(4, 0); | |
analogWrite(5, 0); | |
analogWrite(12, 0); | |
analogWrite(13, 0); | |
analogWrite(14, 0); | |
analogWrite(15, 0); | |
} else { | |
Serial.println(F("starting 8CH PWM test")); | |
analogWrite(0, 500); | |
analogWrite(2, 500); | |
analogWrite(4, 500); | |
analogWrite(5, 500); | |
analogWrite(12, 500); | |
analogWrite(13, 500); | |
analogWrite(14, 500); | |
analogWrite(15, 500); | |
} | |
break; | |
case 'y': case 'Y': // y toggles WiFi on/off | |
wifiDisabled = !wifiDisabled; | |
if (!wifiDisabled) { | |
initWiFi(); | |
if (otaEnabled) | |
initOTA(); | |
} else { | |
Serial.println(F("disabling WiFi")); | |
disableWiFi(); | |
} | |
break; | |
case 'z': case 'Z': // z does an ESP.restart() | |
Serial.println(F("restarting...")); | |
delay(500); | |
ESP.restart(); | |
break; | |
case 'i': case 'I': // i displays the current settings | |
{ | |
Serial.println(F("\nCurrent settings:")); | |
Serial.print(F("PWM frequency = ")); | |
Serial.print(freqPWM); | |
Serial.println(" Hz"); | |
Serial.print(F("PWM alternate sweep = ")); | |
if (hold && !rgbTest) | |
Serial.println(F("hold")); | |
if (!hold && !rgbTest) | |
Serial.println(F("running")); | |
if (rgbTest) | |
Serial.println(F("off")); | |
Serial.print(F("RGB sweep = ")); | |
if (!rgbTest) | |
Serial.println(F("off")); | |
if (rgbTest && keepCH1 && !hold) { | |
Serial.print(F("running, CH1 fixed at ")); | |
Serial.println(dutyCH1); | |
} | |
if (rgbTest && !keepCH1 && !hold) | |
Serial.println(F("running")); | |
if (rgbTest && hold) | |
Serial.println(F("hold")); | |
Serial.print(F("minimum duty cycle = ")); | |
Serial.println(minDutyCycle); | |
Serial.print(F("maximum duty cycle = ")); | |
Serial.println(maxDutyCycle); | |
Serial.print(F("PWM CH1 = ")); | |
if (!firstChannel) { | |
Serial.print(F("disabled")); | |
} else { | |
if (rgbTest && keepCH1) | |
Serial.print(dutyCH1); | |
else | |
Serial.print(dutyCycle); | |
} | |
Serial.print(F(" PWM CH2 = ")); | |
if (!secondChannel) | |
Serial.print(F("disabled")); | |
if (secondChannel && !rgbTest) | |
Serial.print(1023 - dutyCycle); | |
if (secondChannel && rgbTest) | |
Serial.print(dutyCycle); | |
Serial.print(F(" PWM CH3 = ")); | |
if (!rgbTest) | |
Serial.println(F("disabled")); | |
else | |
Serial.println(dutyCycle); | |
Serial.print(F("8 CH PWM test ")); | |
if (eightChTest) | |
Serial.println(F("running")); | |
else | |
Serial.println(F("stopped")); | |
float volts = 3.3 * analogRead(A0) / 1024; | |
Serial.print(F("ADC input voltage = ")); | |
Serial.println(volts); | |
Serial.print(F("pause between PWM changes = ")); | |
Serial.print(pauseDutyCycle); | |
Serial.println(F(" us")); | |
Serial.print(F("Tone output = ")); | |
if (toneFreq == 0 && !sirenTone) | |
Serial.println(F("disabled")); | |
else { | |
if (sirenTone) | |
Serial.println(F("siren tone output")); | |
else { | |
Serial.print(toneFreq); | |
Serial.print(F(" Hz duration = ")); | |
Serial.print(expiry); | |
Serial.println(F(" ms")); | |
} | |
} | |
Serial.print(F("Servo1 = ")); | |
if (servo1.attached()) | |
Serial.print(servo1Angle); | |
else | |
Serial.print(F("detached")); | |
Serial.print(F(" Servo2 = ")); | |
if (servo2.attached()) | |
Serial.print(servo2Angle); | |
else | |
Serial.print(F("detached")); | |
Serial.print(F(" servo sweep = ")); | |
if (waveServos) | |
Serial.println(F("on")); | |
else | |
Serial.println(F("off")); | |
Serial.print(F("LED_BUILTIN PWM = ")); | |
if (ledPWM < 1025) { | |
Serial.println(ledPWM); | |
// Serial.print(F(" @ ")); | |
// Serial.print(freqPWM); | |
// Serial.println(F(" Hz")); | |
} | |
else | |
Serial.println(F("disabled")); | |
Serial.print(F("WiFi ")); | |
if (WiFi.localIP()) { | |
Serial.print(F("connected at ")); | |
Serial.println(WiFi.localIP()); | |
} | |
else | |
Serial.println(F("disabled\n")); | |
break; | |
} | |
default: | |
break; | |
} | |
} | |
} | |
} | |
void disableWiFi() { | |
WiFi.forceSleepBegin(); // sleep the modem to reduce noise & WiFi interrupts during measurements | |
delay(10); // it doesn't always go to sleep unless you delay(10) | |
} | |
void initWiFi() { | |
/* Explicitly set the ESP8266 to be a WiFi-client, otherwise by default it | |
would try to act as both a client and an access-point and could cause | |
network-issues with other WiFi devices on your network. */ | |
GPOS = (1 << 4); // TP3 / D2 used for checking timer1Interrupt() latency | |
Serial.println(F("enabling WiFi")); | |
WiFi.persistent(false); | |
WiFi.mode(WIFI_STA); | |
WiFi.setOutputPower(5); // in dBm, set this higher or lower if you have connection issues | |
WiFi.config(staticIP, gateway, subnet); // if using static IP, enter parameters at the top | |
WiFi.begin(ssid, password); | |
delay(1); | |
Serial.print(F("Connecting to ")); | |
Serial.println(ssid); | |
Serial.print(F("my MAC: ")); | |
Serial.println(WiFi.macAddress()); | |
while (WiFi.waitForConnectResult() != WL_CONNECTED) { | |
Serial.print(F(".")); | |
delay(500); | |
} | |
Serial.print(F("IP address: ")); | |
Serial.println(WiFi.localIP()); | |
Serial.println(F("WiFi ready")); | |
if (MDNS.begin("esp8266")) { | |
Serial.println(F("MDNS responder started")); | |
} | |
if (!otaEnabled) | |
Serial.println(F("OTA disabled")); | |
GPOC = (1 << 4); // TP3 / D2 used for checking timer1Interrupt() latency | |
} | |
void initOTA() { | |
// Port defaults to 8266 | |
// ArduinoOTA.setPort(8266); | |
// Hostname defaults to esp8266-[ChipID] | |
// ArduinoOTA.setHostname("myesp8266"); | |
// No authentication by default | |
// ArduinoOTA.setPassword((const char *)"123"); | |
ArduinoOTA.onStart([]() { | |
Serial.println(F("OTA Start")); | |
}); | |
ArduinoOTA.onEnd([]() { | |
Serial.println(F("\nOTA Complete")); | |
}); | |
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { | |
Serial.printf("Progress: %u%%\n", (progress / (total / 100))); | |
}); | |
ArduinoOTA.onError([](ota_error_t error) { | |
Serial.printf("Error[%u]: ", error); | |
if (error == OTA_AUTH_ERROR) Serial.println(F("Auth Failed")); | |
else if (error == OTA_BEGIN_ERROR) Serial.println(F("Begin Failed")); | |
else if (error == OTA_CONNECT_ERROR) Serial.println(F("Connect Failed")); | |
else if (error == OTA_RECEIVE_ERROR) Serial.println(F("Receive Failed")); | |
else if (error == OTA_END_ERROR) Serial.println(F("End Failed")); | |
}); | |
ArduinoOTA.begin(); | |
yield(); | |
Serial.println(F("OTA enabled")); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment