Go Down

Topic: RGB with two pins on ATtiny85 (Read 914 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
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy