I want to try to make the built in LED on my Nano fade using code. Is that possible even though it isn't on a PWM pin?
or read up on software pwm.
It’s not too hard, once you understand what PWM is.
I’ve run 72 channels with no problems.
(24x RGB LEDs)
1 Like
You can use a technique called "bit angle modulation" and here are two demonstrations, one doing it all in a loop and another using a timer interrupt. The version using the timer makes the brightness fading a little smoother to my eye. If you go on Youtube and search for "Arduino bit angle modulation", you can watch a video I made about the technique.
Version one, not using a timer interrupt:
#define PIN_LED 13
byte _bamCount;
uint8_t _ledBrightness = 0;
uint8_t _fadeUp = 1;
uint32_t _currentMillis, _lastUpdateMillis;
void setup()
{
pinMode(PIN_LED, OUTPUT);
}
void loop()
{
_currentMillis = millis();
// Once every 50 milliseconds, change the led brightness.
// It cannot go over 15 so when it gets that bright, change it back to 0.
if (_currentMillis - _lastUpdateMillis > 49)
{
_lastUpdateMillis = _currentMillis;
if (_fadeUp)
{
_ledBrightness++;
if (_ledBrightness == 15) _fadeUp = 0;
}
else
{
_ledBrightness--;
if (_ledBrightness == 0) _fadeUp = 1;
}
}
bitAngleModulationHandler();
}
void bitAngleModulationHandler()
{
_bamCount++;
if (_bamCount > B1111) _bamCount = B0001; // Ensure counter goes from 1 to 15
// if led brightness is 10 (binary B1010)
if (_bamCount == B0001) { updateLeds(0); } // cycle 1 led off
else if (_bamCount == B0010) { updateLeds(1); } // cycle 2 led on
// B0011 cycle 3 led still on
else if (_bamCount == B0100) { updateLeds(2); } // cycle 4 led off
// B0101 cycle 5 led still off
// B0110 cycle 6 led still off
// B0111 cycle 7 led still off
else if (_bamCount == B1000) { updateLeds(3); } // cycle 8 led on
// B1001 cycle 9 led still on
// B1010 cycle 10 led still on
// B1011 cycle 11 led still on
// B1100 cycle 12 led still on
// B1101 cycle 13 led still on
// B1110 cycle 14 led still on
// B1111 cycle 15 led still on
// So out of the available 15 cycles, a brightness of 10 sets the
// led to be on for 10 of them.
}
void updateLeds(byte bitPosition) {
// if brightness is 10 (binary B1010) and bit position is 0
// bitRead(B1010, 0) = 0 = false
bool isEnabled = bitRead(_ledBrightness, bitPosition);
digitalWrite(PIN_LED, isEnabled);
}
Version 2 using a timer:
#define PIN_LED 13
volatile byte _bamCount;
volatile uint8_t _ledBrightness;
volatile uint8_t _increaseBrightness;
uint32_t _currentMillis, _lastUpdateMillis;
void setup()
{
pinMode(PIN_LED, OUTPUT);
// Setup timer2 to cause an interrupt every 640 microseconds. 1024 prescaler / 16000000 clock frequency Hz * 10 counts
TCCR2A = _BV(WGM21); // CTC
TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); // 1024 prescaler
OCR2A = 10; // Output Compare Register A
TIMSK2 = _BV(OCIE2A); // Output Compare Interrupt Enable Match A
}
void loop()
{
_currentMillis = millis();
// Once every 50 milliseconds, change the led brightness.
// It starts at 0 and goes up to 15, then back down to 0, and repeats.
if (_currentMillis - _lastUpdateMillis > 49) {
_lastUpdateMillis = _currentMillis;
if (_ledBrightness == 0) _increaseBrightness = true;
else if (_ledBrightness == 15) _increaseBrightness = false;
if (_increaseBrightness)
_ledBrightness++;
else
_ledBrightness--;
}
}
ISR(TIMER2_COMPA_vect) // timer interrupt service routine
{
_bamCount++;
if (_bamCount > 15) _bamCount = 1; // Ensure counter goes from 1-15.
if (_bamCount == B0001) { updateLeds(0); }
else if (_bamCount == B0010) { updateLeds(1); }
else if (_bamCount == B0100) { updateLeds(2); }
else if (_bamCount == B1000) { updateLeds(3); }
}
void updateLeds(byte bitPosition)
{
digitalWrite(PIN_LED, bitRead(_ledBrightness, bitPosition));
}
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.