Introduction: Tic Tac Toe on the Arduino With Multiplexing
[beginner-intermediate level]
Multiplexing.
I know a ton of instructables exist on it already, but I felt like making one and decided to start with something simple. Also, I wanted to make Tic Tac Toe!
What is it?
Multiplexing is a smart way of using your outputs and inputs. Instead of dedicating each input to a single source and each output to a single actuator, you can make combinations to be able to reach many more targets (with which I mean sensors and actuators).
What allows us to do that is timing. For example an input source, like a button or a sensor, often doesn't need to be read 100% of the time. Relative to the speed of any modern processor, a button press takes a long time and reading it's input a few cycles later will not change it's value. As you might suspect already, the same holds for a lot of actuators, like LEDs (which, if activated frequently enough, will look like they are burning constantly).
Some targets don't need to be accessed as frequently. This is a more rare application. An example for infrequent access is a bluetooth headset with line-in. Think of the switch between line-in and bluetooth, do we still need to access the inactive component? This is something that could be done using multiplexing (although it probably isn't).
For both cases the time that's left can be spent on other inputs and outputs. And that part is multiplexing.
This instructable will focus on targets that need to be accessed frequently.
But how can you do that?
In short: we apply a coordinate system to our targets (so each target gets a unique coordinate) and have our Arduino address each coordinate individually. Well, maybe it's best to explain that using an example.
You know how chess boards can have numbers and letters on the sides? That's a coordinate system. Those allow a player to uniquely identify each position on the board. In our case, each position will be a target.
Now, how can we apply that to electronics?
If you imagine a 3x3 grid (!) of LEDs, and want to control each of those lights individually, you'd need 9 outputs and a ground. However, using multiplexing you'd only need 6 outputs and no ground. Each output is then responsible for either a row or a column. This way we can address coordinates individually.
However, the downside is: there's limits on what you can address at a time. In general you can address every target in a row OR in a column at once (so for a 3x3 grid of buttons that means you only need to do 3 addressing rounds to read all buttons).
It might sound counter-intuitive to control an electronic circuit that is connected to only outputs. But it's as simple this: if you set one output to 0V, that turns into a ground. The target can then use the 5v of the other output as a source.
What am I going to show you?
Well, as I said: I wanted to make Tic Tac Toe.
This simple game has a 3x3 grid of positions, which can be either a cross or a circle. I decided to indicate crosses and circles with differently colored LEDs. Effectively, that makes it a 3x3x2 LED grid..
On top of that, a player needs buttons to indicate what position he chooses. I decided to use a button for each position, for each player, so that means 18 buttons in total to be read. So again, that is another 3x3x2 grid. (You could save outputs by making arrow buttons and a select button, but that wasn't the point of this instructable).
Wait! 3x3x2? You didn't say anything about a third dimension!
Well, to be honest, that's also not what we want to implement (we could, but let's keep it simple), so we're going to make a 3x6 grid! This covers the same amount of targets as a 3x3x2 grid and simplifies the thing a whole lot.
I'll add 2 more separate LEDs to indicate whose turn it is, but there's no multiplexing going on there. Ow and I'm going to connect everything to a single Arduino Uno. So we're going to connect 20 LEDs and 18 buttons to an Arduino Uno which only has 14 digital connections and 6 analog connections. So let's go to the first step!
Step 1: Requirements
1x Arduino Uno
10x LED of color 1
10x LED of color 2
I used Red and White (or green in the schematics)
19x 330 ohm resistor
or anything else that keeps your leds from frying, but keeps them lit. Yes, 19 isn't a typo.
6x 680 ohm resistor
The only reason these are used is to keep the button inputs from fluctuating when no button is pressed. There's a very very large range of other values that can do that job as well.
18x buttons (6x6 mm)
6x mini breadboards
You can use different types of course, then you might even get away with using just 4 (or even 3 if you use the big ones I guess). Do make sure they can click together (and removing the power lanes might be a nice option), it'll make things way easier.
1x small breadboard
This one is kinda optional, you can check step 5 to see what it is used for. Again: any other breadboard will do, even mini, you'll just have to puzzle a bit.
A whole bunch of breadboard wires. I counted 58 in my setup, but definitely get more.
Personally I never have enough of these things, and it's quite annoying to be blocked in your progress by lacking something as simple as a wire instead of a component.
Optionally: a set of tweezers can be a big relief sometimes.
I get most of my things from ebay, since it's really cheap and gets delivered to your home for no extra cost (if ordered from the right countries).
Step 2: LED Grid Fun 2x2
Let's start with an easy one, a 2x2 LED grid, which we'll expand on later. Use the 330 ohm resistors. If you're feeling confident, you can skip to the next step (or even to the one after that).
Try to follow the example shown in the figure exactly. While connecting this, try to understand what connections you're making and what they do. One tip: try to make smart use of the different colors of your wires (for example: green for columns, yellow for rows, etc.).
I chose the positions in such a way that the LEDs should form a nice square. So if you're using the large breadboards, try to take the power lanes into account if you want a nice square shape (or like I said: remove the power lanes if possible).
Here's a small piece of code that should show you if you connected everything properly. The LEDS should light up individually, clockwise. This is also an example of a slow type of multiplexing (only 1 light active at a time).
If you have no coding experience, there are plenty of tutorials on that and I highly promote playing with what you just build (1. Try to make it go counter-clockwise. 2. Try to make a pattern: 3 circles clockwise, 2 circles counter-clockwise).
Step 3: LED Grid Fun 2x2x2
Here's an extra level of complication: the second color of LEDS! As I said before: we're not going to do 3 dimensions, so we're making a 2x4 grid.
Again, as in step 2, follow the example shown in the figure exactly. Try to see it's just more of the same, and that the colors you're adding form a separate column.
For the fun of it, try to expand the test program from step 2 to include the new lights (and if you feel like a challenge: have one color rotate clockwise, and the other counter-clockwise, at the same time!)
Step 4: LED Grid Fun 3x3x2
Aaaaand more of the same! Do it!
I've added 2 test programs for this one.
- Will simply turns lights on and off like the previous programs.
- Is a small introduction into fast multiplexing. This allows multiple lights to be turned on at once.
Attachments
Step 5: Buttons!
Alright, now here's where things become a tiny bit more complex (only a little bit, I promise!). Of course, we're again implementing a 3x6 grid. The LED grid is not included in the schematic (to keep me from making schematical spaghetti), but do keep it connected to the Arduino! For this step use the 680 ohm resistors.
For the LED grid you've been able set things up as I had explained them: with actual columns and rows. However, I decided to put all buttons for a single player on a single breadboard. As it turns out, it fits, but hardly! (You might want to "convince" some buttons to use less space by bending the pins a tiny bit).
It forced me to rearrange the connections in such a way that the rows and columns don't match the physical location of the rows and columns.
What that means is that, for instance, the button that Arduino thinks is in the first row and first column, isn't actually in the first row and first column of your breadboard. (Yes, that means we need to compensate for that in the software).
Of course I could have used more breadboards and made this as easy as the LED grids, but I decided to keep it in to demonstrate the difference between your perception and the perception of the Arduino.
The program I added is the full program for Tic Tac Toe. There's one more tiny step you need to do, but you could already start playing (if you connected everything right;) ).
Step 6: Status Light
Well, to finish, here's an easy task for you: the status light! This light indicates whose turn it is.
I hope you had fun building Tic Tac Toe and learned something from it. Have fun playing Tic Tac Toe!
7 Comments
6 years ago
A lot fun.thank u,One adjustment may be necessary which is not stated . After test 3-2 u need to change the polarity of all the leds to opposite direction to match the code. Otherwise When u run the code all the leds will light and if u press the button u wont be able to see any change in leds !!!
Reply 6 years ago
Hi, Sorry for the confusion (and the late reply to your messages). You are indeed correct. I made the final version on real hardware before creating the first steps on the simulator, but apparently I mistook the direction of the leds in the simulator. I'll add a fixed version of the final code.
Reply 6 years ago
I uploaded a new version of LedControl.h, which fixes my mistake in the orientation of the leds. I also uploaded a new version of Test3_2.ino, since I also wrote that using the setup I made with the reversed leds. I mistakenly thought the simulator I used (circuits.io) couldn't properly handle it (since the hardware was showing me different things and I know some extra effort must have gone into making such a thing work in a simulator). But the simulator works just fine with it:).
It might take a short while before the Instructable is updated. I changed the values of all outputs connected to the LEDs (HIGH (5v) to LOW (0v) and vica versa), which flipped the direction of the current flow. It still flows on the exact same paths, but just in the opposite direction.
Reply 6 years ago
Its ok brother.
One thing: How u have assigned the button positions? U declarwed 2 2d arrays conataining a value for each position and then the actual positon is calculated from a calculation of values of these two arrays . How is this working? If u explain it would be very nice. :D
Reply 6 years ago
I set the buttons in such a way that each button can make a unique connection between two wires. No buttons are allowed to (be able to) connect the same two wires as other buttons!
For example: if you look at the schematic image in step 5, you can see that the button in the top left (of the left board) connects the green and grey wires. These two wires can only connect to each other, if that specific button is pressed, and nowhere else. These unique combinations are made everywhere.
Sidenote: The arrays represents the left breadboard in the schematic. The same coordinates are mirrored for the right breadboard, which you can see applied in the function "convert_button_white_x(..)". I'll ignore that difference for now and focus on the left breadboard.
Each wire is connected to a pin. For me, it's easiest to think that those pins represent the "coordinates" that the Arduino 'sees'. However, those coordinates don't match the actual physical coordinates of the buttons because of the wiring. The 2 2d arrays contain the actual physical coordinates of the buttons, which are located at the Arduino "coordinates". To fill this array, it's best to follow the wires towards the board. For this code, I chose that the analog wires/pins represent the x coordinates and the digital wires/pins represent the y coordinates of the 2d arrays.
For example: the green and grey wires. The green wire is connected to digital pin 11 (BUTTON_POWER_PIN_1). It's the first pin out of three (as can be seen from the order of the "button_power_pins" array), so we'll assign this "Arduino coordinate" y = 0 (we start counting at 0). The grey wire is connected to analog pin 2 (BUTTON_RED_3), the third pin out of three (as can be seen from the order of the "button_red_pins" array), so "Arduino coordinate" x = 2. If you track those two wires in the schematic, you'll find that they are both connected to the same button at column 0, row 0. These are the values which are inserted in the arrays at indices [2][0]. So, button_conversion_x[2][0] == (column) 0, and button_conversion_y[2][0] == (row) 0.
So with the found actual coordinates, we can control the leds. The pins of the leds do match the actual coordinates, so no more conversion is necessary.
Reply 6 years ago
Thank you again
6 years ago
Looks like fun :)