Apple-style LED Pulsing Using a $1.30 MCU
by hardwarehank in Circuits > Electronics
14727 Views, 58 Favorites, 0 Comments
Apple-style LED Pulsing Using a $1.30 MCU
The Atmel ATTiny85 chip is an 8-pin MCU that is totally awesome. If you've been programming with the bigger boys (the ATMega series), these are a nice adventure - you're rather limited in the number of output pins, but a creative design gives us a lot of flexibility in a very small package.
You've seen them - those "Apple computers." Probably in the hands of some Hipster in Portland, while riding his fixie and wearing those thick framed glasses. That pulsating light when Apple laptops are asleep is so ... sooooothing. You just want to go to sleep watching it. You know you do.
Today, we're going to replicate that using our ATTiny85. It's really easy, and most of it can be implemented in hardware instead of code (!!!).
You've seen them - those "Apple computers." Probably in the hands of some Hipster in Portland, while riding his fixie and wearing those thick framed glasses. That pulsating light when Apple laptops are asleep is so ... sooooothing. You just want to go to sleep watching it. You know you do.
Today, we're going to replicate that using our ATTiny85. It's really easy, and most of it can be implemented in hardware instead of code (!!!).
Supplies
- Breadboard
- Breadboard wires
- 1 LED
- ATTiny85 (the 45 or 25 will probably work, but I haven't tested them)
- An ISP programmer (or other, if you know how to use it) - I use the USBtinyISP.
- A computer with avrdude and avr-gcc
- Optional: an oscilloscope
Understanding PWM
In this guide, we're going to use Fast PWM, which is just one of the modes available on our little chippy friend. I've attached Atmel's very educational document on PWM - I suggest you read it and familiarize yourself with the magic.
Downloads
The Datasheet - Your New Best Friend
The ATTiny 25/45/85 datasheet is the core of this project. Without it, we'd all be lost, poking our chips with sticks and screaming like chimpanzees. Well, most of us, anyway.
Download it and go to section 11 and just take 30 minutes and read the entire thing. Trust me, it's worth it - it's a lot better than randomly paging through it for hours trying to debug your code! :P
Download it and go to section 11 and just take 30 minutes and read the entire thing. Trust me, it's worth it - it's a lot better than randomly paging through it for hours trying to debug your code! :P
Downloads
Bread It Up, Homie
Let's do some breaddage. I've attached a picture, but the rest is up to you, young padawan. Read the datasheet pinout and the pinout of your programmer and get that mojo workin'. There's like a million guides on how to do this, so do your homework. This is a skill you should have - datasheets are the bomb, yo.
The Code
Here's my code. Hopefully it's commented well enough.
/* LED Pulsate with PWM */ #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include <avr/sleep.h> int main() { // Turn on LED output pin DDRB |= _BV(DDB0); // Clear OC0A on match TCCR0A |= _BV(COM0A1); // Set timer to count with F_CPU / 64 TCCR0B |= _BV(CS10); // F_CPU TCCR0B |= _BV(CS01) | _BV(CS00); // /64 prescale // Use Fast PWM, OCRA TOP TCCR0A |= _BV(WGM00); TCCR0A |= _BV(WGM01); //TCCR0B |= _BV(WGM02); // Initial value for our pulse width is 0 OCR0A = 0x00; uint8_t dir = 1; // Direction uint16_t div = 500; // # of clocks per inc/decrement uint16_t stall = 0; // Initial stall counter uint16_t stall_time = 500; // # of clocks to stall at top/bottom for(;;) { // We only want to update every div counts if(TCNT0 % div != 0) continue; // Stall at the top and bottom, and change direction if(OCR0A == 255 || OCR0A == 0) { // Switch directon at top if(OCR0A == 255) dir = -1; else { // Disable LED at bottom // And switch direction DDRB &= ~(_BV(DDB0)); dir = 1; } while(stall < stall_time) { ++stall; _delay_ms(10); } // Turn output back on if necessary if(OCR0A == 0) DDRB |= _BV(DDB0); stall = 0; } // General case - increment direction either way OCR0A += dir; } return 0; }Hopefully, this code is self-documenting. Basically, we're changing the pulse width every few hundred clocks in one direction or the other. We have a special case for when we get to the top or bottom (change direction and linger), just like the Apple stuff does. There's another special case when we want to completely turn off the LED at the bottom - if we don't do this, it still has a (1/256)% duty cycle, and you can see it. Otherwise, the code should be rather concise. Constructive criticism encouraged.
The Result
Here's a short video of the result. I'm pretty happy with it. Get some of the chips and go to town!