This is a small project I’ve been working on for quite a while. I used it to learn more about the AVRs. It was helpful more than I thought. Made me learn calculation by bit-shifting, timers, PWM controlling devices such as LEDs, the timer interrupts (although I removed them in the final version), sleep modes for very little power consumption, and other stuff.
The idea came from a necessity of mine while using my bike around. Street and road illumination is not always constant on my general routes. Even though I’m not a believer in high-powered-12-hour-running-time-with-Li-ion-batteries bike lights, there were times that I needed a bright light.
So the implementation makes it a bike light that responds to the environment via a simple photocell and an ATtiny13 MCU. It blinks when there is enough light that you can see where you are going and others around you can see you. So blinking is only for visibility so the bike light does not draw full current (controlled by PWM of course). If going into a dark patch of road, blinking stops, and the bike light goes into full blast mode with full power.
It uses a 3W led and it is not the best choice since I power it with two AA batteries. When batteries are full, I observed that it drains around 70-80 mA. It is not even close to the limits of the LED (350 ma), but it is restrained by the voltage provided by the battery. However, I’m cool with it since it’s more than enough for me. Putting in some normal 5 mm LEDs or Superflux LEDs provided no more than 10 mA current draw with the same batteries. I’ll give it a shot with 1W and 0.5W LEDs.
There is also a simple calibration function. You can press down a button for ~5 seconds and the bike light takes measurements for 1 second and uses that to set the threshold level between blinking and not blinking.
Also, I needed ATtiny13 to not respond to every little sensor measurement so I tried to add a little moving average. This was the most difficult to do in this project since using arrays is not possible to store the last 10 or 100 values etc. There is simply not enough RAM in this attiny13. The only viable way of doing it was with exponential moving averages but there are problems with floating points. You simply cannot do it in ATtiny13 with that amount of information coming from the sensor. However, You can turn those floating points into integers and do a division, but then there is another problem with the division too. You can do it, but it is not really fast. So the bike light becomes kind of unresponsive while blinking. However #2, you can do the division by bit-shifting and it works! So that was that.
I needed a debouncer of course, and it detects it in every CPU cycle whether the button is pressed or not. That is kind of overkill to detect buttons. The proper way of doing it would be, to use the timer interrupts to detect the switch 100 times per second (100 Hz). That was one part of the project that I failed. Even though my prototype on Arduino worked with timer interrupts, I couldn’t get it to work in ATtiny13. It interfered with INT0 (which is used to wake up the device) or something else. I don’t know.
There are four modes in the code. Zeroth of them shuts down the CPU and ADC to save power. The first of them is automatic mode where the bike light responds to the environment. The second of them is On for all the time with the max current. The third of them is blink mode all the time with 20mA of current.
So that is it basically. I have the code here in this Gist. You can check it out. Also if you want to see it in action, watch the YouTube video: