RGB with two pins on ATtiny85

The ATtiny does have 3 PWM pins, but with only 5 pins total, it’s easy to run short. Fortunately, you can put two LEDs on a single pin using tristate logic.

I don’t think this counts as Charlieplexing, since Wikipedia says you need two I/O pins to Charlieplex two LEDs. So whatever you call it, you can save a precious pin. Can’t use a common cathode or common anode tricolor though – you need a 6-pin or 3 discrete LEDs.

Wire:
VCC → resistor → BLUE → PIN3
GND → resistor → GREEN → PIN3

``````//
// RGB from just two pins on ATtiny85
// RED LED on pin4, standard Timer1 PWM (don't want to multiplex RED because the Vf is too low and it may glow even when set to "off")
// GREEN and BLUE LEDs multiplexed on pin 3 using Timer0 ISR (their cumulative Vf is > 5V)
//
//
//                  ATtiny25/45/85
//                      +-\/-+
//              RESET  1|    |8  VCC
//   BLUE/GREEN  3/A3  2|    |7  2/A1
//       RED     4/A2  3|    |6  1
//                GND  4|    |5  0
//                      +----+
//
// Wire: VCC -> resistor -> BLUE  -> PIN3
//       GND -> resistor -> GREEN -> PIN3
//

// standard AVR macros for set bit and clear bit
#define sbi(num,bitloc) (num|=(1<<bitloc))
#define cbi(num,bitloc) (num&=~(1<<bitloc))
// nonstandard macros for dealing with multiplexed pin 3 in a time-efficient manner
#define digitalWrite3LOW  cbi(PORTB,PB3)
#define digitalWrite3HIGH sbi(PORTB,PB3)
#define pin3isHIGH        PORTB & 1<<PB3
#define pinMode3INPUT     cbi(DDRB,PB3)
#define pinMode3OUTPUT    sbi(DDRB,PB3)
#define pin3isAnOUTPUT    DDRB & 1<<DDB3

// provide nice human names for array index
#define RED   0
#define GREEN 1
#define BLUE  2
byte outputLED[3] = { 0, 0, 0 };

// =====================================================================================================================================
void RGBon()
{
noInterrupts();
TCCR0A = (1 << WGM01); // Set Clear Timer on Compare Match (CTC) mode, clearing other bits
TCCR0B = (1 << CS00) | (1 << CS01); // clock select, clkI/O/64 from prescaler, clearing other bits
TIMSK |= (1 << OCIE0A); // Timer/Counter0 Output Compare Match A Interrupt Enable, preserving other bits so we don't break millis()
OCR0A = 255;
interrupts();
pinMode(4, OUTPUT);
analogWrite(4, 1); // RED LED uses standard PWM
}

// =====================================================================================================================================
ISR(TIM0_COMPA_vect)
{
if(pin3isAnOUTPUT)
{
if(pin3isHIGH) // green -> OFF (deadtime)
{
pinMode3INPUT; // leaves pullup on
digitalWrite3LOW; // turn off pullup
OCR0A = 255 - outputLED[GREEN] - outputLED[BLUE];
}
else // blue -> green
{
digitalWrite3HIGH;
OCR0A = outputLED[GREEN];
}
}
else // OFF -> blue
{
pinMode3OUTPUT; // defaults to LOW
OCR0A = outputLED[BLUE];
}
}

// =====================================================================================================================================
// call setColor with the desired LED you wish to change, with the intensity of 0-255
void setColor(const byte color, const byte value)
{
outputLED[color] = value >> 1; // same as (value / 2), only faster
if(color == RED)
{ analogWrite(4, outputLED[RED] + 1 ); }  // RED LED uses standard PWM
}

// =====================================================================================================================================
// setting '0' values won't actually turn the LED quite all the way off; have to call this to get it completely dark
void RGBoff()
{
TIMSK &= ~(1 << OCIE0A); // Timer/Counter0 Output Compare Match A Interrupt Disable, preserving other bits so we don't break millis()
analogWrite(4, 0);
}

// =====================================================================================================================================
void setup()
{
RGBon();
}

// =====================================================================================================================================
void loop()
{
for(byte i = 0; 1; i++) // infinite demo loop
{
setColor(RED, i); // call setColor with the desired LED you wish to change, with the intensity of 0-255
setColor(BLUE, i+64);
setColor(GREEN, i+128);
delay(10);
}
}
``````

This is a great hack to save a pin, but please note it is at the expense of about 50% brightness.

I think Adafruit Neopixels or similar would provide greater functionality with only one data pin used.

Great! even though i dont understand this fully yet, in time though ) i got a baby girl on the way so i ordered Adafruit Neopixels WG2811 and a bluetooth, maybe it will help me stopping her crying Thanks bud

sogseal: i got a baby girl on the way so i ordered Adafruit Neopixels WG2811 and a bluetooth, maybe it will help me stopping her crying

I very much doubt that.

To stop (prevent) babies crying, you pick them up and nurse them.