Go Down

Topic: RGB with two pins on ATtiny85 (Read 838 times) previous topic - next topic

tylernt

Nov 24, 2013, 04:25 am Last Edit: Nov 24, 2013, 06:15 am by tylernt Reason: 1
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

Code: [Select]

//
// 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)
//
// http://code.google.com/p/arduino-tiny/ pinouts
//
//                  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);
 }
}

macegr

This is a great hack to save a pin, but please note it is at the expense of about 50% brightness.
Unique RGB LED Modules and Arduino shields: http://www.macetech.com/store

TheKitty

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

sogseal

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  :smiley-sweat: Thanks bud

Paul__B


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.

Go Up