0

I need to control 4 individual LEDs via PWM on an ATTiny85. I have found lots of info on how to control 3 LEDs. But apparently to control 4 with PWM, you have to really twist the 85 into knots. Is there an easier way to handle 4 LEDs on the 85, or would it be better to step over to the 84? If I went with the 84, would I be likely to run into the same brick walls as with the 85?

I found this code for controlling 4 on the 85, but it's above my skill level. Anyone see any issues with it?

/* Four PWM Outputs */

// ATtiny85 outputs
const int Red = 0;
const int Green = 1;
const int Blue = 4;
const int White = 3;
volatile uint8_t* Port[] = {&OCR0A, &OCR0B, &OCR1A, &OCR1B};

void setup() {
  pinMode(Red, OUTPUT);
  pinMode(Green, OUTPUT);
  pinMode(Blue, OUTPUT);
  pinMode(White, OUTPUT);
  // Configure counter/timer0 for fast PWM on PB0 and PB1
  TCCR0A = 3<<COM0A0 | 3<<COM0B0 | 3<<WGM00;
  TCCR0B = 0<<WGM02 | 3<<CS00; // Optional; already set
  // Configure counter/timer1 for fast PWM on PB4
  TCCR1 = 1<<CTC1 | 1<<PWM1A | 3<<COM1A0 | 7<<CS10;
  GTCCR = 1<<PWM1B | 3<<COM1B0;
  // Interrupts on OC1A match and overflow
  TIMSK = TIMSK | 1<<OCIE1A | 1<<TOIE1;
}

ISR(TIMER1_COMPA_vect) {
  if (!bitRead(TIFR,TOV1)) bitSet(PORTB, White);
}

ISR(TIMER1_OVF_vect) {
  bitClear(PORTB, White);
}

// Sets colour Red=0 Green=1 Blue=2 White=3
// to specified intensity 0 (off) to 255 (max)
void SetColour (int colour, int intensity) {
  *Port[colour] = 255 - intensity;
}  

void loop() {
  for (int i=-255; i <= 254; i++) {
    OCR0A = abs(i);
    OCR0B = 255-abs(i);
    OCR1A = abs(i);
    OCR1B = 255-abs(i);
    delay(10);
  }
}

2 Answers2

1

An easy strategy is to multiplex the 4 LEDs onto a single PWM pin. This will let independently control the brightness of each LED on the ATTINY using 5 pins total.

So, for example, you could connect all 4 of the cathodes together and connect those to a single PWM pin. Then you connect each of the 4 anodes to a different IO pin.

At any given moment, only one of the anodes is in output mode - the others are left floating. The means that at most 1 single LED is active and its brightness is controlled by the PWM duty cycle.

You can then use the overflow ISR for the PWM timer to activate the next LED in the sequence after each PWM cycle. You also update the PWM match to reflect the brightness of the next LED.

If you rotate though the LEDs quickly (faster than, say, 60 times per second), then visually they all just look like they are on at the desired brightness. PWM, after all, is just blinking an LED too quickly to see, so we are just adding a second dimension on to it.

One downside: Since only a single LED is on at any moment, the maximum total brightness will theoretically be 1/4 of what it would be if you drove all the LEDs independently. In practice this is likely an issue since the ATTINY is limited to how much current it can pass though all if its pins at once if you tried to light all the LEDs at the same time.

One hint: when setting up the PWM timer, make is so that the LED is OFF at the beginning of the cycle and turns on in the middle. This will give the ISR time to step to the next LED while all LEDs are off. This is better becuase it is Easy to see an LED that is on when it should not be, but not so easy to see an LED that is off when it should be on.

One suggestion: I will get flamed for this, but you can leave out any current limiting resistors when doing this since each LED is only on for at most 1/4 of the time. This will give you more brightness and also make it so you can dial down the PWM duty cycle so you have more off time at the beginning of each cycle to step to the next LED.

I have used this technique successfully many times, and even have been able to multiplex 6 RGB LEDs (three channels each) onto one chip and it works great.

Update the question if you have any questions about the details!

bigjosh
  • 1,273
  • 13
  • 19
1

If you want to save pins at the expense of a more complicated strategy, you can get away with only 3 pins by connecting the LEDs as two sets of two like this...

enter image description here

Instead of using the built in PWM, you will need to do the PWM manually by setting a timer and then changing the INPUT/OUTPUT and ON/OFF of each of the pins each time the timer expires.

+-----+----------+----------+----------+
| LED |    A     |    B     |    C     |
+-----+----------+----------+----------+
|   1 | OUTPUT 1 | INPUT    | OUTPUT 0 |
|   2 | OUTPUT 0 | INPUT    | OUTPUT 1 |
|   3 | INPUT    | OUTPUT 1 | OUTPUT 0 |
|   4 | INPUT    | OUTPUT 0 | OUTPUT 1 |
+-----+----------+----------+----------+

Update or comment if you want more details on this strategy.

bigjosh
  • 1,273
  • 13
  • 19