/*
FadeWOD & analogWriteRead, adapted from
https://www.arduino.cc/en/Tutorial/BuiltInExamples/Fade
https://github.com/arduino/arduino-examples/blob/main/examples/01.Basics/Fade/Fade.ino
Simulation at https://wokwi.com/arduino/projects/323945277471851092
and https://wokwi.com/arduino/projects/323946131184681555
Forum https://forum.arduino.cc/t/what-is-the-inverse-of-analogwrite-pin-val/960774
Arduino CC0-1.0
DaveX 2022-02-18 CC SA
This example shows how to fade an LED on pin 9 using the analogWrite()
function without blocking.
The analogWrite() function uses PWM, so if you want to change the pin you're
using, be sure to use another PWM capable pin. On most Arduino, the PWM pins
are identified with a "~" sign, like ~3, ~5, ~6, ~9, ~10 and ~11.
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Fade
*/
int led = 9; // the PWM pin the LED is attached to
int brightness = 0; // how bright the LED is
int fadeAmount = 5; // how many points to fade the LED by
int analogGetPwm9(uint8_t pin){
// based on 9 = OC1A from
// https://upload.wikimedia.org/wikipedia/commons/c/c9/Pinout_of_ARDUINO_Board_and_ATMega328PU.svg
return ((TCCR1A & bit(COM1A1))? OCR1A:digitalRead(9)*255);
}
// the setup routine runs once when you press reset:
void setup() {
// declare pin 9 to be an output:
pinMode(led, OUTPUT);
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop routine runs over and over again forever:
void loop() {
// non-blocking wrapper
const unsigned long adjustInterval = 30;
static unsigned long lastAdjust = 0;
if ( millis() - lastAdjust > adjustInterval) {
lastAdjust += adjustInterval;
// set the brightness of pin 9:
analogWrite(led, brightness);
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (brightness <= 0 || brightness >= 255) {
fadeAmount = -fadeAmount;
}
// wait for 30 milliseconds to see the dimming effect
//delay(30); // handled by adjustInterval
// ***************
// This `analogWriteRead(pin);` functionality is what I'm looking for:
Serial.println(analogGetPwm(9));
// ***************
} // end of millis() adjustInterval code
simLamp();
}
void simLamp(void){
//
digitalWrite(LED_BUILTIN, (analogGetPwm9(9) > 80));
// Halt and Catch Fire: (try 255)
if (analogGetPwm9(9) == 254)
while(true)
;
}
int analogGetPwm(uint8_t pin)
{
// We need to make sure the PWM output was enabled for those pins
// that support it before reading their OCRnx register.
//
// Derived from https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring_analog.c#L96
// based on https://forum.arduino.cc/t/what-is-the-inverse-of-analogwrite-pin-val/960774
//
int val;
switch (digitalPinToTimer(pin))
{
// XXX fix needed for atmega8
#if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__)
case TIMER0A:
// connect pwm to pin on timer 0
if ((TCCR0 & _BV( COM00)) {
val = OCR0 ; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 1;
}
break;
#endif
#if defined(TCCR0A) && defined(COM0A1)
case TIMER0A:
// connect pwm to pin on timer 0, channel A
if (TCCR0A & _BV(COM0A1)) {
val = OCR0A; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR0A) && defined(COM0B1)
case TIMER0B:
// connect pwm to pin on timer 0, channel B
if (TCCR0A & _BV(COM0B1)) {
val = OCR0B; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR1A) && defined(COM1A1)
case TIMER1A:
// connect pwm to pin on timer 1, channel A
if (TCCR1A & _BV( COM1A1)) {
val = OCR1A; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR1A) && defined(COM1B1)
case TIMER1B:
// connect pwm to pin on timer 1, channel B
if (TCCR1A & _BV( COM1B1)) {
val = OCR1B; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR1A) && defined(COM1C1)
case TIMER1C:
// connect pwm to pin on timer 1, channel C
if (TCCR1A & _BV( COM1C1)) {
val = OCR1C; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR2) && defined(COM21)
case TIMER2:
// connect pwm to pin on timer 2
if (TCCR2 & _BV( COM21)) {
val = OCR2; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR2A) && defined(COM2A1)
case TIMER2A:
// connect pwm to pin on timer 2, channel A
if (TCCR2A & _BV(COM2A1)) {
val = OCR2A; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR2A) && defined(COM2B1)
case TIMER2B:
// connect pwm to pin on timer 2, channel B
if (TCCR2A & _BV(COM2B1)) {
val = OCR2B; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR3A) && defined(COM3A1)
case TIMER3A:
// connect pwm to pin on timer 3, channel A
if (TCCR3A & _BV(COM3A1)) {
val = OCR3A; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR3A) && defined(COM3B1)
case TIMER3B:
// connect pwm to pin on timer 3, channel B
if (TCCR3A & _BV(COM3B1)) {
val = OCR3B; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR3A) && defined(COM3C1)
case TIMER3C:
// connect pwm to pin on timer 3, channel C
if (TCCR3A & _BV(COM3C1)) {
val = OCR3C; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR4A)
case TIMER4A:
//connect pwm to pin on timer 4, channel A
if (TCCR4A & _BV(COM4A1)) {
val = OCR4A; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR4A) && defined(COM4B1)
case TIMER4B:
// connect pwm to pin on timer 4, channel B
if (TCCR4A & _BV(COM4B1)) {
val = OCR4B; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR4A) && defined(COM4C1)
case TIMER4C:
// connect pwm to pin on timer 4, channel C
if (TCCR4A & _BV(COM4C1)) {
val = OCR4C; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR4C) && defined(COM4D1)
case TIMER4D:
// connect pwm to pin on timer 4, channel D
if (TCCR4C & _BV( COM4D1)) {
val = OCR4D; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR5A) && defined(COM5A1)
case TIMER5A:
// connect pwm to pin on timer 5, channel A
if (TCCR5A & _BV(COM5A1)) {
val = OCR5A; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR5A) && defined(COM5B1)
case TIMER5B:
// connect pwm to pin on timer 5, channel B
if (TCCR5A & _BV(COM5B1)) {
val = OCR5B; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
#if defined(TCCR5A) && defined(COM5C1)
case TIMER5C:
// connect pwm to pin on timer 5, channel C
if (TCCR5A & _BV(COM5C1)) {
val = OCR5C; // get pwm duty
} else {
val = digitalRead(pin) ? 255 : 0;
}
break;
#endif
case NOT_ON_TIMER:
default:
val = digitalRead(pin) ? 255 : 0;
}
return val;
}
namespace PwmShim {
// Use C++ namespace to wrap analogWrite in
// a function to save state
// Per https://forum.arduino.cc/t/what-is-the-inverse-of-analogwrite-pin-val/960774/26?u=davex
//
int pwm_state[NUM_DIGITAL_PINS];
void analogWrite(uint8_t pin, int val) {
// Wrop analogWrite() to save state in PwmShim::pwm_state
pwm_state[pin] = val;
//Serial.print("in my function : ");
//Serial.print(pin); Serial.write(' '); Serial.println(val);
::analogWrite(pin, val);
}
}