ATtiny13 – controlling LEDs WS2811/WS2812

There was a time when controlling RGB LEDs was not always an easy task. I this article I would like to show how to make it without difficulty using one ATtiny13 and LEDs based on WS2811/WS2811 driver.

The addressable LEDs are using protocol similiar to OneWire (very time-depended protocol) and can be connected together to create a strip of LEDs. The brightness of each LED color can be adjusted using pulse-width modulation to one of 256 different levels. That means there are 16,777,216 (2563) possible combinations of colors. We can produce any color from white (all colors on) to pseudo-black (all colors off).

There are a few existing libraries that can help us to do that on ATtiny13 – i.e. light_ws2812 (tested with v2.4) or pololu-led-strip-avr. In my projects I decided to use light_ws2812 because it occured to be more stable and predictible for this small chip. Due to ATtiny13 limitations we can’t controll huge number of addressable LEDs but it’s far enough to manage up to eight LEDs. I’ve created several demo examples which are presented bellow. Have fun!

Parts List

Circuit Diagram

Examples

Classic Rainbow

Software for “Rainbow on single LED”

This code is written in C and can be compiled using the avr-gcc. More details on how compile this project is here. Complete code is on GitHub.

#include <avr/io.h>
#include <util/delay.h>
#include "light_ws2812.h"

struct pixel {
	uint8_t g;
	uint8_t r;
	uint8_t b;
};

int
main(void)
{
	struct pixel p = {255, 0, 0};

	/* loop */
	while (1) {
		if (p.r > 0 && p.b == 0) {
			p.r--;
			p.g++;
		}
		if (p.g > 0 && p.r == 0) {
			p.g--;
			p.b++;
		}
		if (p.b > 0 && p.g == 0) {
			p.r++;
			p.b--;
		}
		ws2812_setleds((struct cRGB *)&p, 1);
		_delay_ms(10);
	}
}

Software for “Rainbow on several LEDs”

This code is written in C and can be compiled using the avr-gcc. More details on how compile this project is here. Complete code is on GitHub.

#include <avr/io.h>
#include <util/delay.h>
#include "light_ws2812.h"

#define	PIXEL_NUM	(7)

struct pixel {
	uint8_t g;
	uint8_t r;
	uint8_t b;
} pixels[PIXEL_NUM];

int
main(void)
{
	uint8_t i;
	struct pixel p = {255, 0, 0};

	/* loop */
	while (1) {
		if (p.r > 0 && p.b == 0) {
			p.r--;
			p.g++;
		}
		if (p.g > 0 && p.r == 0) {
			p.g--;
			p.b++;
		}
		if (p.b > 0 && p.g == 0) {
			p.r++;
			p.b--;
		}
		for (i = 0; i < PIXEL_NUM; ++i) {
			pixels[i] = p;
		}
		ws2812_setleds((struct cRGB *)pixels, PIXEL_NUM);
		_delay_ms(10);
	}
}

Circular LED chaser

This code is written in C and can be compiled using the avr-gcc. More details on how compile this project is here. Complete code is on GitHub.

#include <avr/io.h>
#include <util/delay.h>
#include "light_ws2812.h"

#define	PIXEL_NUM	(8)
#define	DELAY		(60)

struct pixel {
	uint8_t g;
	uint8_t r;
	uint8_t b;
} pixels[PIXEL_NUM];

static void setpixel(uint8_t id, struct pixel *p);

int
main(void)
{
	uint8_t i, k = 0, r = 255, g = 0, b = 0;
	struct pixel p = {0, 0, 0};

	/* loop */
	while (1) {

		/* set the color */
		p = (struct pixel){g, r, b};
		for (i = k; i < (PIXEL_NUM + k); ++i) {
			setpixel(i % PIXEL_NUM, &p);
			_delay_ms(DELAY);
		}

		/* clear the color */
		p = (struct pixel){0, 0, 0};
		for (i = k; i < (PIXEL_NUM + k); ++i) {
                        setpixel(i % PIXEL_NUM, &p);
			_delay_ms(DELAY);
                }

		/* choose next color */
		if (r == 255) {
			g = 255;
			r = 0;
		} else if (g == 255) {
			g = 0;
			b = 255;
		} else { // b == 255
			b = 0;
			r = 255;
		}

		/* set pixel shift */
		k = ++k % PIXEL_NUM;
	}
}

void
setpixel(uint8_t id, struct pixel *p)
{

	pixels[id] = *p;
	ws2812_setleds((struct cRGB *)pixels, PIXEL_NUM);
}

References

Leave a Comment