Introduction: Rotating Bike Lights

About: Born in Berlin in 1985, engineer, contrarian, 'The Big Bang Theory' fan, my other blog: www.tiny-labs.com - find me on Twitter @pixelgeb and reddit u/Stishio

As a disclaimer, this project is round about six (or seven?) years old. I did this during my electrical engineering study in the embedded engineering class with my good friend Manu. The whole class had the task to build an electrical driven bicycle with motor, display and some extra features. We did the lighting for the bike. I intended to create something special. My idea was to mount some LEDs directly on the wheels and let them rotate around. Switching the LEDs "on" and "off" in the right moment ("On" when the diodes are facing the front/rear, otherwise "off") will fool the human eye and creates a static light frame to the front and to the back.

Unfortunately I did not pursue the project after I had finished it. I'm now focused on woodworking projects :) I have a lot of old projects with micro controllers (µC) lying around. I'll add the interesting ones to instructables when I have time for it. You can check my very old blog about my projects: www.tiny-labs.com . I hope some of you find them interesting, although there are many superior projects out there.

I try to remember everything and to write it down. Feel free to ask me any questions in the comments or via PM.

Enjoy :)

Step 1: Concept

The functionality is visualized in the small animation. I separate the wheel into 12 sectors. Each wheel is mounted with 12 pairs of LEDs - the front with white LEDs, the rear with red LEDs. Due to the rotation of the wheels, it's necessary to calculate the right switching time for each pair. Therefore I need to know the time in which the wheel performs one rotation. Now I can calculate the "on" and "off" times for each pair of LEDs for the next rotation. I want the four front facing LEDs and the four rear facing LEDs to be switched on. If the wheel rotates one segment, the LED, which is leaving the front/rear is switched off, and the LED, which is entering the front/rear is switched on. It's a little bit complicated to describe it with words. I think the animated GIF illustrates the idea behind it.

For example, this is the switching table for the front:

//		 Time segments
//     |00|01|02|03|04|05|06|07|08|09|10|11|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   01|  |  |  |  |  |  |  |  |##|##|##|##|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   02|  |  |  |  |  |  |  |##|##|##|##|  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
// L 03|  |  |  |  |  |  |##|##|##|##|  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   04|  |  |  |  |  |##|##|##|##|  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
// E 05|  |  |  |  |##|##|##|##|  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   06|  |  |  |##|##|##|##|  |  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
// D 07|  |  |##|##|##|##|  |  |  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   08|  |##|##|##|##|  |  |  |  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
// S 09|##|##|##|##|  |  |  |  |  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   10|##|##|##|  |  |  |  |  |  |  |  |##|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   11|##|##|  |  |  |  |  |  |  |  |##|##|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   12|##|  |  |  |  |  |  |  |  |##|##|##|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//

Each LED with ## is switched on. The length of one segments equals the rotation time dived by 12. This leads me directly to the next question.

How to measure the rotation time?

This is very easy. Basically I do the same what a simple 5$ bike computer does. I use a magnet and a reed switch or hall sensor (I used the hall sensor later, but a simple reed switch would do the same magic) to measure the rotation time. When the magnet triggers my sensor, I start a clock (a very precise clock) and when the sensors is triggered again, I save the time went by between the two events and restart the clock for the next and so on and on. Now I simply dived the time by 12 and so I got the duration for a segment.

Switching the LEDs

The wheel is spinning and I have the duration for one segment. When the sensor is triggered I use the segment time from the previous rotation to switch the LEDs in the upcoming rotation. I have my precise clock reset and start running at the beginning of the next rotation. Now I use my time table form above the switch the LEDs on and off according to the segments I'm currently in. This process is repeated for every rotation. If there a slight differences in the rotation speed (the biker goes faster or slower) you can see slightly the light frame moving along the wheel. The travel speed of a bike is usually constant and slowly changed so there is now problem here. The critical moments are the starting phase and when the bike stops again. To be honst, I haven't implement anything for this solution. If you start driving your bike, the lights will start function again. A solution for standing still could be a gyroscope to measure the position of the wheel and to switch on the LEDs which are currently in front/rear position. These component are pretty cheap nowadays. I'll add a section later on for possible changes.

Step 2: Circuit Diagram

I start with the circuit diagram. I need 12 LEDs for each site of a wheel, thats 24 LEDs for each wheel, 48 in total. To control the diodes, I use a micro controller from ATMEL, the ATTiny2313. It has enough ports for my 12 pairs for LEDs. To measure the timing, I use a hall effect sensor. A battery pack of AAs will power everything. I need a switch and some passiv electronic components (resistors and capacitors).

This is the complete list for one wheel:

  • ATTiny2312
  • 24 LEDs (white for front, red for rear)
  • Battery pack for 3 AA
  • On/Off switch
  • LED for on/off status
  • Resistor 220 Ohm (status LED)
  • Resistor 10k Ohm (pull-up for the reset port)
  • Hall or reed switch
  • Capacitor 100nF (smoothing the power supply)
  • 6-pin connector for ATMEL programmer (optional)
  • Wires (a lot of them :D)

I use a ATMEL programmer and ATMEL Studio to flash my bit-code to the micro controller. You can use command line tools as well. You can switch to a different micro controller too. The following source code are written to work with the ATTiny, but it should be easy to adjust the code to your choice of control unit.

Step 3: The First Prototype

The first prototype was very quick and dirty. We used a lot of tape and a thick wire to mount the LEDs to the rims. The battery pack and the control unit were placed in the center of the wheel. It looks ugly, but was a solid construction actually. I will explain the source code later, please enjoy the videos first :D

In the first test only three pairs of LEDs were simultaneously switched on. The second test was with four pairs of LEDs. We kept the four LED version for the "final" version. The light band is longer in this case and so we can illuminate more of the street and the way ahead.

Step 4: The Second and Final Prototype

The second prototype had a casing for the electronics and a better execution of "taping" :D It was already mounted to our bike.The final version had to aluminum rims for the LEDs. The rims were coated with black paint. It looked awesome. Unfortunately I couldn't find a foto of the whole and final setup. Just from the front wheel.

Next step would be to improve the mounting system and the casing for the electronic, but we never did it actually. I'm a little bit sad looking back on this project. It has a lot of potential. Anyway enjoy the videos. The video with the rear lights had a software bug. That's why the red LEDs seem to jump. I fixed it afterwards.

Step 5: The Source Code

There are four relevant source files. You can find them as an attachment. I've added the makefile as well. The makefile configures the µC. You can adjust it to your choice of control unit.

  • main.c (main loop and init)
  • main.h (all defines and setup)
  • interrupts.c (interrupt runtimes)
  • functions.c (function ;)

The key features are outsourced to the interrupt runtimes to save energy. You could bring the µC to sleep.

main.c

This is the main loop. Main.c configures the ports, the interrupts and the interfaces which are needed and goes directly into the main loop.

//	=== LED timing diagram rear ===
// 
//				  Time segments
//     |00|01|02|03|04|05|06|07|08|09|10|11|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   01|  |  |  |  |  |  |  |  |##|##|##|##|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   02|  |  |  |  |  |  |  |##|##|##|##|  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
// L 03|  |  |  |  |  |  |##|##|##|##|  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   04|  |  |  |  |  |##|##|##|##|  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
// E 05|  |  |  |  |##|##|##|##|  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   06|  |  |  |##|##|##|##|  |  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
// D 07|  |  |##|##|##|##|  |  |  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   08|  |##|##|##|##|  |  |  |  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
// S 09|##|##|##|##|  |  |  |  |  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   10|##|##|##|  |  |  |  |  |  |  |  |##|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   11|##|##|  |  |  |  |  |  |  |  |##|##|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   12|##|  |  |  |  |  |  |  |  |##|##|##|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+


#include "main.h"	//Import all needed defines, makros, libraries, global variables

//=== Receiver ===

#define F_CPU 8000000UL

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

int main(void)
{
	unsigned char chr = '1';

	vTIMER0_ini();	//Initialize ans start timer 0 (overflow after 8*0.064ms), 8bit timer, prescaler 8, interrupt enable, no preload
	vPORTS_ini();	//Initialize all ports for LED usage
	vINT0_ini();	//Initialize external interrupt 0 (int0)
	sei();			//Global interrupt enable on	
	rf12_init();
	
	while(1)		//Endless loop
	{
		rf12_rxdata(&chr, 1);
		if (chr == '1')
		{
			switche_on = 1;
		}
		if (chr == '0')
		{
			switche_on = 0;
		}
	}
}

The main loop (while(1)) could be empty actually. This is the final version of the source code. I added a bluetooth module to the µC. The driver could use the display of the bike to switch the light on and off wirelessly. The source file "rf12.c" is included in the attachment. You can use it. If there are any questions feel free to ask me about it. This function is not necessary for the basic purpose.

I use two interrupts. The timer interrupt is my precise clock, which measures the rotation time. The second interrupt is fired when the port, to which the hall sensor is connected, has a rising edge. This will reset the timer and saves the segment time.

main.h

This is the main.h. It's the main header file.

//	=== Pin configurations on the ATTiny2313 and schematic of the project ===
//
//                                                                       VCC
//                                                                        +
//        VCC                                       _____   _____         |
//         +                            _____      |     \_/     |        |
//         |                            Reset O--1-|PA2      VCC |-20-O --'
//  .------o------.                                |             |                           LED8
//  |             |              CS ----- RXD O--2-|PD0       PB7|-19-O UCSK/SCL/PCINT7 ----->|---.
//  |  .-----.    |                                |             |                           LED7 |
//  |  | HAL |   .-.            SCK ----- TXD O--3-|PD1       PB6|-18-O MISO/DO/PCINT6 ------>|---o
//  |  |     |   | | 1.8k                          |             |                           LED6 |
//  |  |1 2 3|   | |            SDI --- XTAL2 O--4-|PA1       PB5|-17-O MOSI/DI/PCINT5 ------>|---o
//  |  '-----'   '-'                               |             |                           LED5 |
//  |   | | | Q   |             SDO --- XTAL1 O--5-|PA0       PB4|-16-O OC1B/PCINT4 --------->|---o
//  |   | | |     |                                |             |                           LED4 |
//  '---' | '-----o----------- CKOUT/XCK/INT0 O--6-|PD2       PB3|-15-O OC1A/PCINT3 --------->|---o
//        |              LED9                      |             |                           LED3 |
//        |         .----|<------------- INT1 O--7-|PD3       PB2|-14-O OC0A/PCINT2 --------->|---o
//        |         |    LED10                     |             |                           LED2 |
//        '---------o----|<--------------- T0 O--8-|PD4       PB1|-13-O AIN1/PCINT1 --------->|---o
//                  |    LED11                     |             |                           LED1 |
//                  o----|<---------- OC0B/T1 O--9-|PD5       PB0|-12-O AIN0/PCINT0 --------->|---o
//                  |                              |             |                           LED12|
//                  |                     .-- O-10-|GND       PD6|-11-O ICP ----------------->|---o
//                  |                     |        |_____________|                                |
//                  |                     |          ATTiny 2313                                  |
//                  |                     |                                                       |
//                 ===                   ===                                                     ===
//                 GND                   GND                                                     GND

// === LED Pins === //
#define PIN_LED1 0
#define PIN_LED2 1
#define PIN_LED3 2
#define PIN_LED4 3
#define PIN_LED5 4
#define PIN_LED6 5
#define PIN_LED7 6
#define PIN_LED8 7
#define PIN_LED9 3
#define PIN_LED10 4
#define PIN_LED11 5
#define PIN_LED12 6

// === LED Ports === //
#define PORT_LED1 PORTB
#define PORT_LED2 PORTB
#define PORT_LED3 PORTB
#define PORT_LED4 PORTB
#define PORT_LED5 PORTB
#define PORT_LED6 PORTB
#define PORT_LED7 PORTB
#define PORT_LED8 PORTB
#define PORT_LED9 PORTD
#define PORT_LED10 PORTD
#define PORT_LED11 PORTD
#define PORT_LED12 PORTD

// === LED Ports (ini) === //
#define PORT_INI_LED1 DDRB
#define PORT_INI_LED2 DDRB
#define PORT_INI_LED3 DDRB
#define PORT_INI_LED4 DDRB
#define PORT_INI_LED5 DDRB
#define PORT_INI_LED6 DDRB
#define PORT_INI_LED7 DDRB
#define PORT_INI_LED8 DDRB
#define PORT_INI_LED9 DDRD
#define PORT_INI_LED10 DDRD
#define PORT_INI_LED11 DDRD
#define PORT_INI_LED12 DDRD

// === LEDs off makros === //
#define mLED1_off(); PORT_LED1&=~(0x01<<PIN_LED1);
#define mLED2_off(); PORT_LED2&=~(0x01<<PIN_LED2);
#define mLED3_off(); PORT_LED3&=~(0x01<<PIN_LED3);
#define mLED4_off(); PORT_LED4&=~(0x01<<PIN_LED4);
#define mLED5_off(); PORT_LED5&=~(0x01<<PIN_LED5);
#define mLED6_off(); PORT_LED6&=~(0x01<<PIN_LED6);
#define mLED7_off(); PORT_LED7&=~(0x01<<PIN_LED7);
#define mLED8_off(); PORT_LED8&=~(0x01<<PIN_LED8);
#define mLED9_off(); PORT_LED9&=~(0x01<<PIN_LED9);
#define mLED10_off(); PORT_LED10&=~(0x01<<PIN_LED10);
#define mLED11_off(); PORT_LED11&=~(0x01<<PIN_LED11);
#define mLED12_off(); PORT_LED12&=~(0x01<<PIN_LED12);

// === LEDs on makros === //
#define mLED1_on(); PORT_LED1|=(0x01<<PIN_LED1);
#define mLED2_on(); PORT_LED2|=(0x01<<PIN_LED2);
#define mLED3_on(); PORT_LED3|=(0x01<<PIN_LED3);
#define mLED4_on(); PORT_LED4|=(0x01<<PIN_LED4);
#define mLED5_on(); PORT_LED5|=(0x01<<PIN_LED5);
#define mLED6_on(); PORT_LED6|=(0x01<<PIN_LED6);
#define mLED7_on(); PORT_LED7|=(0x01<<PIN_LED7);
#define mLED8_on(); PORT_LED8|=(0x01<<PIN_LED8);
#define mLED9_on(); PORT_LED9|=(0x01<<PIN_LED9);
#define mLED10_on(); PORT_LED10|=(0x01<<PIN_LED10);
#define mLED11_on(); PORT_LED11|=(0x01<<PIN_LED11);
#define mLED12_on(); PORT_LED12|=(0x01<<PIN_LED12);

// === LEDs off all makro === //
#define mLEDs_off(); PORT_LED1&=~(0x01<<PIN_LED1);PORT_LED2&=~(0x01<<PIN_LED2);PORT_LED3&=~(0x01<<PIN_LED3);PORT_LED4&=~(0x01<<PIN_LED4);PORT_LED5&=~(0x01<<PIN_LED5);PORT_LED6&=~(0x01<<PIN_LED6);PORT_LED7&=~(0x01<<PIN_LED7);PORT_LED8&=~(0x01<<PIN_LED8);PORT_LED9&=~(0x01<<PIN_LED9);PORT_LED10&=~(0x01<<PIN_LED10);PORT_LED11&=~(0x01<<PIN_LED11);PORT_LED12&=~(0x01<<PIN_LED12);

// === Global variables === //
volatile unsigned long ovrflw_cnt = 0;
volatile unsigned long segment_times = 1250;
//volatile unsigned char chr = '1';
volatile unsigned char switche_on = 1;
//volatile unsigned char chr = '1';

// === Libraries === //
#include <avr/interrupt.h>
#include "functions.c"
#include "interrupts.c"
//#include <avr/signal.h>
//#include <avr/io.h>
//#include <stdlib.h>

The main.h holds all defines and libraries. If you see a function call like mLED1_off() don't be confused. It isn't function call actually. It is a text macro, which will be replaced later by the define during the compiling progress. This is a typical way to program among embedded programmer. It makes reading the source code so much nicer without wasting precious memory.

There are also some global variables to keep track of the segment time and the time overflow counts.

interrupts.c

This holds all interrupt routines.

//	=== LED timing diagram rear ===
// 
//				  Time segments
//     |00|01|02|03|04|05|06|07|08|09|10|11|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   01|  |  |  |  |  |  |  |  |##|##|##|##|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   02|  |  |  |  |  |  |  |##|##|##|##|  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
// L 03|  |  |  |  |  |  |##|##|##|##|  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   04|  |  |  |  |  |##|##|##|##|  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
// E 05|  |  |  |  |##|##|##|##|  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   06|  |  |  |##|##|##|##|  |  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
// D 07|  |  |##|##|##|##|  |  |  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   08|  |##|##|##|##|  |  |  |  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
// S 09|##|##|##|##|  |  |  |  |  |  |  |  |
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   10|##|##|##|  |  |  |  |  |  |  |  |##|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   11|##|##|  |  |  |  |  |  |  |  |##|##|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+
//   12|##|  |  |  |  |  |  |  |  |##|##|##|
//   --+--+--+--+--+--+--+--+--+--+--+--+--+


SIGNAL (INT0_vect)
{
	if (ovrflw_cnt > 20)	// Debouncing (~10,24ms)
	{
		//Calculate the time for one segment, 12 segments equal one revolution
		segment_times = ovrflw_cnt / 12;
		//Reset counter, time for the next revolution is measured
		ovrflw_cnt = 0;
		//Start of time segment 00
		if (switche_on == 1)
		{
			mLEDs_off();	//Reset all LEDs to start fresh
			mLED11_on();		
			mLED10_on();
			mLED9_on();
			mLED8_on();
		}
	}
}

SIGNAL (SIG_TIMER0_OVF) //8*0.064ms
{
	ovrflw_cnt++;
	if (switche_on == 1)
	{
		if (ovrflw_cnt == (segment_times * 1))		//Start of time segment 01
		{
			mLED12_on();
			mLED8_off();
		} 
		if (ovrflw_cnt == (segment_times * 2))		//Start of time segment 02
		{
			mLED1_on();
			mLED9_off();
		} 
		if (ovrflw_cnt == (segment_times * 3))		//Start of time segment 03
		{
			mLED2_on();
			mLED10_off();
		} 
		if (ovrflw_cnt == (segment_times * 4))		//Start of time segment 04
		{
			mLED3_on();
			mLED11_off();
		} 
		if (ovrflw_cnt == (segment_times * 5))		//Start of time segment 05
		{
			mLED4_on();
			mLED12_off();
		}
		if (ovrflw_cnt == (segment_times * 6))		//Start of time segment 06
		{
			mLED5_on();
			mLED1_off();
		} 
		if (ovrflw_cnt == (segment_times * 7))		//Start of time segment 07
		{
			mLED6_on();
			mLED2_off();
		} 
		if (ovrflw_cnt == (segment_times * 8))		//Start of time segment 08
		{
			mLED7_on();
			mLED3_off();
		} 
		if (ovrflw_cnt == (segment_times * 9))		//Start of time segment 09
		{
			mLED8_on();
			mLED4_off();
		} 
		if (ovrflw_cnt == (segment_times * 10))	//Start of time segment 10
		{
			mLED9_on();
			mLED5_off();
		} 
		if (ovrflw_cnt == (segment_times * 11))	//Start of time segment 11
		{
			mLED10_on();
			mLED6_off();
		}
	}
	if (switche_on == 0)
	{
		mLEDs_off();
	}
}

There are two interrupts. INT0_vect is responsible for the hall sensor. It will be triggered when the magnet passes the hall sensor. The interrupt routine saves calculates and saves the segment time and resets the timer interrupt.

SIG_TIMER0_OVF is the timer interrupt. The time is measured using the overflows of the timer. The number of overflows during one revolution of the wheel equals the time for one rotation. Therefore the number of overflows divided by 12 equals the time for one segment. When the timer is reset, it counts again the overflows and switches the LEDs on and off accordingly to the segments the timer is in.

functions.c

Some functions, who could guess so :D

void vPORTS_ini (void);
void vTIMER0_ini (void);
void vINT0_ini (void);
//void vLED_on (char LED_number);
//void vLED_off (char LED_number);
//void vLED_off_all (void);
//void vUSART1_ini (void);

void vTIMER0_ini (void)
{
	TCCR0A = 0x00 | (0 << COM0A1) | (0 << COM0A0) | (0 << COM0B1) | (0 << COM0B0) | (0 << WGM01) | (0 << WGM00);
	// TCCR0A = 0x00
	TCCR0B = 0x00 | (0 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (0 << CS02) | (1 << CS01) | (0 << CS00); //010 - 8 prescaler
	// TCCR0B = 0x01
	TCNT0 = 0x00;
	// TCNT0 = 0
	TIMSK |= (0 << OCIE0B) | (1 << TOIE0) | (0 << OCIE0A);
	// TIMSK = 0x02
}

void vINT0_ini (void)
{
	GIMSK |= (0x01 << 6);
	//Interrupt enable INT0
	MCUCR |= (0x01 << ISC01) | (0x00 << ISC00);
	//ISC01 = 1, ISC00 = 0: Iterrupt flag on rising edge
}

void vPORTS_ini (void)
{
	PORT_INI_LED1 |= (0x01 << PIN_LED1);
	PORT_INI_LED2 |= (0x01 << PIN_LED2);
	PORT_INI_LED3 |= (0x01 << PIN_LED3);
	PORT_INI_LED4 |= (0x01 << PIN_LED4);
	PORT_INI_LED5 |= (0x01 << PIN_LED5);
	PORT_INI_LED6 |= (0x01 << PIN_LED6);
	PORT_INI_LED7 |= (0x01 << PIN_LED7);
	PORT_INI_LED8 |= (0x01 << PIN_LED8);
	PORT_INI_LED9 |= (0x01 << PIN_LED9);
	PORT_INI_LED10 |= (0x01 << PIN_LED10);
	PORT_INI_LED11 |= (0x01 << PIN_LED11);
	PORT_INI_LED12 |= (0x01 << PIN_LED12);
}
/*
void USART1_ini (void)
{
	UBRR1H = (unsigned char) (BAUD>>8);
	UBRR1L = (unsigned char) BAUD;
	UCSR1C = (0 << UMSEL1) | //asynchronous
			(0 << UPM10) | (0<<UPM01) |	//Mode 00: no parity
			(0 << USBS1) | 	//1 stop bit
			(1 << UCSZ11) | (1 << UCSZ10);	//Mode 011: 8 bit data
	UCSR1B = (0 << RXCIE1) | (1 << TXCIE1) | (0 << RXEN1) | (1 << TXEN1) | (0 << UCSZ12);
	UCSR1A = (0 << U2X1);
}
*/

These are the functions to set up the µC. I could have used defines here as well...I don't know why I didn't do it actually :) Doesn't matter. This has the same result.

vPORTS_ini configures the ports as outputs.

vINT0_ini configures the interrupt to look on this port and to wait for a rising edge (hall sensor sees magnet).

vTIMER0_ini sets the parameters for the timer interrupt. How fast it runs etc.

USART1_ini is not used here. It configures the UART interface. A similar functions is found in the rf12.c source file. It's needed for the connected bluetooth module, which is nothing else than a wireless UART (RS232) interface.

Step 6: Missing Features and What Can Be Improved

Well everything worked fine. But there is still a lot of work to do. The software is fine. But the casing and the mounting system has to be improved. It should be waterproof and easily mountable. We used a lot of tape and a simple plastic case.

Another possible improvement concerns the batteries. You could use a more efficient µC to increase the battery life. You could replace the batteries with accumulators. It's possible to connect the electronics to the dynamo of the bike using sliding contacts. Maybe it is possible to harvest energy through the rotation of the wheel.

As I've already mentioned that there are some states of a ride I haven't covered yet. For example standing still with the bike. I would try to turn on the front facing LEDs and the rear facing LEDs. Therefore you would need a sensor which measures the position in space, like a gyroscope. Maybe the gyroscope could replace the hall sensor as well.

There a lot of possible ideas. Feel free to do whatever you want with this project. Please add some fotos and/or a comment if you do so. I would love to see your version of it. Have fun and enjoy :)

Lights Contest 2017

Participated in the
Lights Contest 2017