Pages: [1]   Go Down
Author Topic: RGB with two pins on ATtiny85  (Read 720 times)
0 Members and 1 Guest are viewing this topic.
Idaho, US
Offline Offline
God Member
*****
Karma: 19
Posts: 868
Special User
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
//
// 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);
  }
}
« Last Edit: November 24, 2013, 12:15:58 am by tylernt » Logged

SF Bay Area
Offline Offline
Edison Member
*
Karma: 11
Posts: 1244
Arduino Ninja
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Unique RGB LED Modules and Arduino shields: http://www.macetech.com/store

US
Offline Offline
Full Member
***
Karma: 4
Posts: 183
Electronics are the new Legos
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

NSW Australia
Offline Offline
Faraday Member
**
Karma: 84
Posts: 3439
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Pages: [1]   Go Up
Jump to: