Introduction: LED Sensor - TicTacToe Game

About: I'm 18 years old, just finished school and start now to study electrical engineering :)
When i first heard about using LEDs as Sensors i didnt know in how far this could be used to make something usefull. After a lot of testing and research i ended up designing a TicTacToe-Game using only LEDs as input. The downside of using only LEDs as input is, that always a little bit of ambient light is needed for the LEDs to detect a finger. When i was 14 i build a first version of the game which can be seen here on youtube. In terms of this contest i decided to keep the hardware but redesign the Software, in order to make the computer enemy faster and clean up the code.

I wanted to make an instructable wich is easy to rebuild, makes fun and also uses some research.

Step 1: Things U Will Need!

Things you need for this instructable:

- 9x Duo LEDs
- 18x series resistor for the LEDs (390 ohm should do it)
- 1x 10K resistor as a pullup for the reset pin
- 1x ATMega32/16
- 1x On/Off switch
- 1x 5V power supply
- enclousure
- stripboard
- wires
- programmer to flash µC

Step 2: How Does It Work?

Step 1: LED is driven in normal mode, light is emitted (this step can be omitted)
Step 2: LED is driven in reverse biased mode, the LED is charged like a capacitor. The more light shines on the LED, the faster the LED is discharged.
Step 3: One can measure the voltage at the cathode.

Both, cathode and anode of the LED are connected to a controller pin. That way one can reverse bias the LED, configure cathode pin as input or use the LED to emit light ;) Instead of measuring the voltage at the cathode pin, the µC measures the time the pin has not ground level, which is way easier to implement. On the left oscillogram a finger is held on top of the LED, as one can see the curve goes down very smooth and doesn't even reach ground level. The other oscillogram shows the curve of the LED with no finger held on top of the LED. The curve reaches ground level fairly quickly, this means one can clearly distinguish between finger and no finger. So the phenomenen that an LED can be used as a light dependent capacitor, makes it possible to recongnize if a finger is held on top of the LED.

Step 3: Wiring It Up!

The wiring is pretty easy, the ATmega32/16 has 4 I/O ports with 8 pins each. The switch is used to cut off the power supply, the 10K resistor and 100nF capacitor are standard parts to bring the ATmega32/16 to life. The LEDs cathodes of the first eigth LEDs are wired to PORTA (cat1 -> PA0, cat2 -> PA1, ..., cat8 -> PA7). The first eight red anodes are wired to PORTB (anr1 -> PB0, ..., anr8 -> PB8). The first eigth green anodes are connected to PORTC (ang1 -> PC0, ..., ang8 -> PC8). The last LED, LED9 is connected to PORTD as follows: cat9 -> PD7, anr9 -> PD6, ang9 -> PD6.

In the beginning i tried to multiplex the LEDs in a matrix which would have saved a lot of controller pins, but it turned out that the LEDs need about 200 milli seconds to discharge. This may sound little but it makes it impossible to multiplex the LEDs without flickeringm so this is why we need so many pins.

In the picture the wiring looks a bit messy but it works :) One can also see the power supply i used for the game. I first used some small batteries which had a voltage of 12V and a voltage regulator. Those batteries were drained to quickly so i searched for an alternative and found out that one can open a 9V block battery. After opening one has 6, 1,5V batteries. Three of them in series are suitable to supply the power for the game and wouldn't be dead too soon. Mine are actually already lasting for 3 years ;)

Step 4: Enclosure

Next step is to create an ecnlosure for the game. In the picture u can see the package of some delicous licorice, i used sand paper to get rid of the coating. After cleaning the box, i drilled 9 holes on top for the LEDs and one hole for the switch at the side. Everything fitted perfectly. Of course u can use any kind of enclosure for ur game! The LEDs need to be arranged in the order which is shown in the second picture. They can also be arranged in other ways but then one needs to change the functions in the code which check if a player won. I used a piece of wood and some hot glue to keep the LEDs in place, after fixing the LEDs i used some tape to attach the LEDs to the enclosure. (You can see this in the second picture of the previous step.) Since the enclusre is made of metal make sure the PCB doesn't make contact with it, i used a piece of cardboard to isolate the PCB.

Step 5: Program/Code

I used a cheap development board from a german company to burn the code into the controller, but you can use anykind of ISP programmer to flash the ATmega32/16.

The rar-archive contains the source files and a hex-file (located in the default folder) for an ATmega32, but i recommend building the source by yourself because u may have to adjust some values according to your LEDs. Different LEDs maybe need different times to charge/discharge so one has to try out some values. The source code is split into 5 files:

 - TicTacToe_atm32_rev2.c This file contains the main routine and some functions.
 - led.c/led.h These files conatin every LED specific code, e.g. the function "get_field()" which returns the pressed LED.
 - computer_enemy.c/computer_enemy.h As the name says these files contain the AI.

The code should be documented fairly well, but if there are question go ahead and ask in the comments.

Step 6: How Does the Code Work?

In the picture you can see a rough flowchart how the code works. It begins with the initialization of the I/O-ports and determines the enemy. As soon as the enemy is determined, one can see there are two different strings the green one is the mode "human vs. human" and the red shows the cycle of the mode "human vs. computer". Both cycles start with the get field fucntion, which reads the leds and returns a value between 1-9 for a specific field. The next function sets a field, one has to pass the color and the field. The left coloum toggles the color and checks the winner, if a winner is found, the winning row flashes and the board is reset. The sequence starts again but this time the looser begins with his move. The second coloum first checks a winner, then moves the computer and then checkes the winner again. There are two checks in the right coulum because when playing vs the computer always the human has the first move. So one has to check for a winner after every move.

To count the wins of a player, one should add a function "show_wins()", and two global variables:

int wins_red = 0;
int wins_green = 0;


void show_wins(void){
    for(int i=0;i<wins_red;i++){
        set_field(i, 1);
    _delay_ms(300); //wait 100 ms
    //TODO: clear_board() function

for(int i=0;i<wins_green;i++){
        set_field(i, 0);
    _delay_ms(300); //wait 100 ms
    //TODO: clear_board() function

This function first sets as many leds as there are wins counted by the integer. Another way is to directly manipulate the ports ;) (Not more than 9, there should be a check performed if there are more wins than fields!) The next step is to call this function when a winner is found this can be done either by a seperate if-statement after which evaluates the value of the function "check_winner()" or directly in the "check_winner()" function, right before the "return 1;" statement. Also one has to increment the two integers "wins_red++" (wins_green++), this should be done in the "check_winner()" function. This can be done by an if-statement:

if(player == 1){

Thisstatement should be located also before the "return 1;" statement ans also before the "show_wins()" function so one always counts all wins.

This was only one idea how to add more funcitonality to the game. Another idea could be to also count draws or add a little beeper to play some melody if someone won.

Step 7: Use Your Game!

Although not everything was explained in detail, i hope you were able to build a Tic Tac Toe game. It actually is a lot of fun to play with and a nice project because it can be build from few parts. This is only one example for what LEDs can be used, there is much more potential in those small diodes. They can for example be used to measure the brightness or to transmit data. Have fun exploring :)

Playing the game:
When powering it up, there is a short initialization sequence. While this sequence the ambient light is measured and a value for the discharging time is calculated. This makes it possible to play the game in different environments. After the initialization is done, one can choose between human vs. human (green) or human vs. computer (red). In the middle coloum one can select the difficulty of the computer enemy (1-3) while 1 is random moves. The enemy with difficulty 2 the enemy tries to win and blocks ur winning moves and the third difficulty uses the negamax algorithm to always calculate the best move. The algorithm tries every move, this is why the first move takes some time. Since you can't read LEDs which are enabled without a flickering, one has to select the LEDs above or below the green or red LED. Also you have to restart the game if u want to select an easier computer enemy.
Microcontroller Contest

Participated in the
Microcontroller Contest