Multiplexer Guessing Game

Multiplexer Guessing Game

Introduction

In this project, we will demonstrate how to use a multiplexer (also referred to as a mux) to select one of four buttons for input. If you are unfamiliar multiplexers, you can read more about them by following the red tab in the related materials section.

We will be using the SN74HC4851N multiplexer to implement a guessing game. The chipKIT™ will generate a random number from 0 to 3. This number will be fed into the multiplexer, selecting a corresponding input channel from 0 to 3. Connected to each input channel will be a button. The point of the game is to guess which button is randomly selected for us to press. When you guess the right button it will drive an LED by turning on the transistor. The transistor will be controlled with the multiplexer's output channel. After you have guessed the¬† correct¬†button, the chipKIT will sense you have won and create a new random button for you to guess. To prevent cheating (pressing every button at once), we will design a cheat sensing circuit paired with some cheat sensing code. All of this will be combined to create the multiplexer guessing game.

Before you begin, you should:
  • Know how to wire an external LED.
  • Understand current limiting resistors.
  • Know how to wire in a button.
  • Understand how multiplexers work in general.
After you're done, you should:
  • Understand how to use the SN74HC4851N multiplexer IC.

Inventory:

Qty Description Typical Image Schematic Symbol Breadboard Image
6 220 Ω resistor
4 Button
1 LED
1 ZVN2110A N-FET Transistor
1 SN74HC4851N Multiplexer

Basic Theory

Getting Familiar With the SN74HC4851N Multiplexer IC:

In order to complete this project, you will need to become familiar with the multiplexer provided in the Analog Parts Kit. The SN74HC4851N has four main categories of pins that are discussed below.

  • Input Pins: Y0–Y7
  • The first primary group of pins we will look at are the multiplexer's input pins. There are 8 input pins, which means the SN74HC4851N is a 8:1 (8 to 1) multiplexer. All of the input pins are labeled with a Y, followed by their number as seen in Fig. 1. Input pins Y0 through Y3 appear on the right side of the IC, while input pins Y4 through Y7 appear on the left side.

  • Selection Pins: A, B, C
  • The next group of pins we will look at is the selection pins. These are three pins labeled A, B, and C in the bottom right of Fig. 1. The order in which you drive these pins determines which input you select. The relationship between the input and selection pins is depicted below in Fig. 2.

  • Output Pins: COM
  • The SN74HC4851N multiplexer has one output pin which is is labeled COM. Because this multiplexer is analog, it will output the exact voltage seen on the selected input pin. In Fig. 2, the input pin names are listed under the output column. This is meant to signify that COM will be at the same voltage as the selected input pin.

  • Miscellaneous Pins: INH, GND, Vcc
  • The last couple of pins we will examine are Vcc, GND, and INH. The Vcc pin supplies power to the chip. It can accept voltages anywhere from -0.5 V to 7 V, however, it is recommended you use 3.3 V when working with the chipKIT. The GND pin does as its name implies and acts as the chip's grounding point. Finally, the INH acts as the “EN” (enable) pin commonly found on multiplexers. When INH is driven HIGH the multiplexer is disabled. Otherwise, if INH is driven LOW the multiplexer will function normally.

Figure 1. SN74HC4851N pin-out.
Figure 2. Mux function table.

Referring to Fig. 2, take note of the logic used to control the multiplexer. If you are unfamiliar with truth tables, follow the orange tab in the related materials section.

Since this multiplexer has 8 inputs, there are 3 selection pins. For this project, we are only going to need four input pins to connect to our four buttons. This means to select inputs Y0 through Y3, we only need to make use of two selection pins, A and B. So later on in our sketch, we will always drive the third selection pin (pinC) LOW.

Step 1: Assembling the circuit

Before we begin wiring the circuit we should consider how we will set it up. Since we have gone over how the multiplexer will work, we can focus on the other parts of the circuit. Let us examine how the win indicator will work for our project. This part of the circuit will consist of an N-FET transistor, LED, and current limiting resistor. When you guess the randomly selected button it will cause the mux's output pin to be driven HIGH. This in turn will drive the transistor's gate pin (center leg) HIGH and allow current to flow through it. In this sense, the transistor is acting as a electronically controlled switch. So when the transistor is switched on it will allow current to flow through the LED, light it up, and indicate the player has won.

The last part of the circuit we need to talk about is the button/cheat sensing circuit. It allows us to identify if multiple buttons are being pressed using a single analog input pin. The circuit is essentially a variable voltage divider. The cheat sensing point (labeled in Fig. 5 below) measures the voltage produced by the voltage divider. Pressing multiple buttons changes the resistance of the voltage divider, effecting its output. This allows the chipKIT to detect when you are attempting to cheat. If you would like to learn more about how the cheat sensing circuit works follow the yellow tab on the right.

Figure 3. Multiplexer guessing game circuit.

Assembly Steps:

NOTE: The text coloring in this section does not correspond to the MPIDE keyword color coding used elsewhere in the document.

Figure 4. Mux pin-out quick reference.
  1. Connect the chipKIT's 3.3V source to the bottom power rail.
  2. Connect the chipKIT's ground pin to the breadboard's bottommost blue ground rail.
  3. Connect the bottom and top rails to the breadboard. This will help with circuit organization later on.
  4. Place the SN74HC4851N mux IC so it straddles the breadboard's valley. Make sure you position it so it is exactly 9 holes from the left, as shown.
  5. Connect the bottom 3.3V rail to the Vcc pin on the mux.
  6. Run a wire from the mux's ground pin to the uppermost blue ground rail.
  7. Connect chipKIT pin 41 to mux pin INH. See Fig. 4 for demux IC pinout.
  8. With a white wire, connect chipKIT pin 40 to mux pin A.
  9. With a grey wire, connect chipKIT pin 39 to mux pin B.
  10. With a brown wire, connect chipKIT pin 38 to mux pin C.
  11. Place one button so its right side is lined up with column 35. Place another button so its right side is lined up with column 40. These buttons will be known as “B0” (Button 0) and “B1” (Button 1) respectively. The node connected to B0's right side will be highlighted in orange and referred to as Node A. The node connected to B1's right side will be highlighted in yellow and referred to as Node B.
  12. Place another button so its right side is lined up with column 45. Place one more button so its right side is lined up with column 50. These buttons will be known as “B2” (Button 2) and “B3” (Button 3) respectively. The node connected to B2's right side will be highlighted in green and referred to as Node C. The node connected to B3's right side will be highlighted in light blue and referred to as Node D.
  13. Connect the left side of each button you just placed to the bottommost 3.3V power rail.
  14. Place one end of a 220 Ω resistor in bottommost hole of Node A. Place one end of another 220 Ω resistor in bottommost hole of Node B. Connect both the free ends of the aforementioned resistors to a new node. This new node will be highlighted in purple and referred to as Node E.
  15. Place one end of a 220 Ω resistor in bottommost hole of Node C. Place one end of another 220 Ω resistor in bottommost hole of Node D. Connect both the free ends of the aforementioned resistors to a new node. This new node will be highlighted in grey and referred to as Node F.
  16. Connect Node F to Node E.
  17. Place a 220 Ω resistor that connects Node E to ground. This will complete the cheat detecting circuit for our project
  18. Run a wire from the chipKIT's A1 (analog 1) pin to Node E. In this context Node E represents the cheat sensing point for our cheat detecting circuit. For further clarification the cheat sensing point is also labeled in the schematic below.
  19. Run an orange wire from Node A to mux pin Y0.
  20. Run an yellow wire from Node B to mux pin Y1.
  21. Run an green wire from Node C to mux pin Y2.
  22. Run an blue wire from Node D to mux pin Y3.
  23. Place a ZVN2110A N-FET Transistor oriented exactly as shown. If the transistor is facing the wrong way, or you accidentally used a ZVP2110A P-FET, the circuit will not function properly.
  24. Connect the transistor's source pin (leftmost leg) to ground.
  25. Connect the transistor's gate pin (center leg) to the mux's INH pin.
  26. Place an LED so its cathode is connected to the transistor's drain pin (rightmost leg). This will be the win indicator LED.
  27. Place a 220 Ω current limiting resistor that connects the LED's anode to the topmost 3.3V rail.
  28. Run a wire from the chipKIT's A0 (analog 0) pin to LED's anode. This is the win sensing point of the circuit. For further clarification the cheat sensing point is also labeled in the schematic below.

Figure 5. Multiplexer Guessing Game Circuit Schematic.

The schematic for the circuit can be seen in Fig. 5 above.

Step 2: Writing the sketch

Selecting a Random Button:

Before we begin writing the sketch, we should discuss exactly what we want it to do. The first thing we want the sketch to do is is pick a random button for us to select. To do this we will generate a random number between 0 and 4 using the random() function. This random number will be fed into a function called selectButton(). The selectButton() function is responsible for sending the random number to the multiplexer's select pins in binary form. Once the mux knows the button number, it will make a complete circuit between the specified button and the transistor controlling the win LED.

Checking for Cheating:

Now that we have an idea of how we are going to select a random button, let's examine how we will sense and interpret button presses. We will need our sketch to be able to determine when the correct button is being pressed and how many buttons are being pressed at once. To prevent cheating it will be necessary to know if more than one button is being pressed. The checkCheatStatus() function verifies whether one or more buttons are being pressed. It does this by checking if the voltage read by the cheatPin is greater than 1.7. We use the value 1.7 because pressing a single button will produce around 1.6 V, while pressing any more buttons will exceed 1.7 volts. These voltage values are all determined by how we setup our cheat sensing circuit. For more info on this check out the page on multi-button input circuits by clicking the yellow tab above.

Checking for Winning:

With anti-cheat barriers in place, our next task is to consider how we will determine if someone has won the guessing game. To do this we will use a function called checkWinStatus(). This function checks two things to determine if a player has won. First, it checks that no cheating has been detected by the checkCheatStatus() function. Second, it verifies that the winPin is reading a value above 0.7 volts. If you want to see the actual voltages being read by the cheatPin and winPin, open up MPIDE's serial monitor by clicking the icon in the top right corner of the window.

Putting it all Together:

Now that we have gone through what all the major functions will look like, we should discuss how we will combine them. Inside the loop() function we will use an if statement that constantly checks to see whether a player has won. If a player did win, we will call a function that waits for the button to be released and then generate a new random button number. Otherwise, if a player guessed incorrectly, or cheated, we will disable the mux to prevent the win LED from activating. We then wait until the the button is released before looping through the loop() function another time. This pretty much sums up how the sketch will work. For further explanation about each function, read through the comments in the sketch below.

				//Define digital Mux Control Pins
				int muxPinINH = 41, muxPinC = 40, muxPinB = 39, muxPinA = 38;
				//Define analog win/cheat sensing pins
				int winPin =0, cheatPin = 1;
				//Global Variable to keep track of winning button
				int winningButton = 0;
					
				///////////////////////////////////////Setup Function/////////////////////////////////////////////////////////////
				void setup()
				{
				  Serial.begin(9600);//Set up serial communication to display cheatPin, and winPin values
				  
				  pinMode(muxPinA, OUTPUT); 
				  pinMode(muxPinB, OUTPUT); 
				  pinMode(muxPinC, OUTPUT);
				  pinMode(muxPinINH, OUTPUT);
				  randomSeed(analogRead(11));//Seed the random function, with a random intial value from analog pin 11
				  winningButton = random(0,4);//Randomly choose the first winning button
				}
				
				
				///////////////////////////////////////Primary Loop Function///////////////////////////////////////////////////////
				void loop()
				{
				  showPinStatus();//print analog pin values to serial monitor
				  digitalWrite(muxPinINH, LOW);//Re-enable the mux in case it was disabled due to a incorrect guess or cheating
				  if(checkWinStatus() == true)
				  {//If you get here, a button was pressed and it was the winning button
				   waitForButtonRelease();//Wait for button to be released
				   winningButton = random(0,4);//Randomly choose a new winning button
				   
				  }
				  else
				  {//If you get here, the wrong button was pressed or cheating was detected
					digitalWrite(muxPinINH, HIGH);//Disable Mux to prevent LED lighting up when not winning
					waitForButtonRelease();//Wait for button to be released
				  }
				  //Let the multiplexer know which button to select
				  selectButton(winningButton);
				}

				
				///////////////////////////////////////////Functions///////////////////////////////////////////////////////////////
				void showPinStatus()
				{//Displays the CheatPin and windPin voltages on the serial monitor
				  Serial.print("CheatPin: ");
				  Serial.print(readVoltage(cheatPin));
				  Serial.print("  winPin: ");
				  Serial.print(readVoltage(winPin));
				  Serial.print("\n"); 
				}

				boolean checkWinStatus()
				{//check to see if the winPin is above 0V and if the cheat pin has not been activated
				  double Vin = readVoltage(winPin);
				  if((Vin < 0.7) && (checkCheatStatus() == false))
				  {
				   return true; 
				  }
				  else
				  {
				   return false; 
				  }
				}				

				boolean checkCheatStatus()
				{
				  double Vin = readVoltage(cheatPin);
				  if(Vin > 1.7)
				  {//When two or more buttons are pressed, the voltage read by cheat pin more than 1.6 volts
				   return true; 
				  }
				  else
				  {//When one button is pressed the voltage read by cheat pin is 1.6 volts
				   return false; 
				  }
				}

				void selectButton(int value)
				{//Send the selected button number to the multiplexer
				  switch(value)
				  {
					case 0://Select Button 0
						 //Send Binary value 000 to the mux
						 digitalWrite(muxPinC, LOW); 
						 digitalWrite(muxPinB, LOW);
						 digitalWrite(muxPinA, LOW);
					  break;
					case 1://Select Button 1
						 //Send Binary value 001 to the mux
						 digitalWrite(muxPinC, LOW); 
						 digitalWrite(muxPinB, LOW);
						 digitalWrite(muxPinA, HIGH);
					  break;
					case 2://Select Button 2
						//Send Binary value 010 to the mux
						 digitalWrite(muxPinC, LOW); 
						 digitalWrite(muxPinB, HIGH);
						 digitalWrite(muxPinA, LOW);
					  break; 
					case 3://Select Button 3
					     //Send Binary value 011 to the mux
						 digitalWrite(muxPinC, LOW); 
						 digitalWrite(muxPinB, HIGH);
						 digitalWrite(muxPinA, HIGH);
					  break; 
				  } 
				}
				
				void waitForButtonRelease()
				{//This function loops and waits for a button to be released 
				 while(readVoltage(cheatPin) > 0.1)//While the any button is pressed
				 {//wait for button to be released 
				  showPinStatus();//print analog pin values to serial monitor
				 }
				 return;//Once button has been released, return
				}

				
				double readVoltage( int analogPin)
				{
				  int x = analogRead(analogPin);//Read value from the specified analogPin
				   
				  return ((x/1024.0)*3.3);//Convert value stored in x to a voltage, and return voltage
				}

Test Your Knowledge!

Now that you've completed this project, try experimenting with it.

  • Update the sketch so it limits the number of guesses you have.
  • Try modifying the cheat sensing circuit so it produces a unique voltage for each button and button combination. For details on how to do this, check out the interactive figure in the multi-button input circuit.


  • Other product and company names mentioned herein are trademarks or trade names of their respective companies. © 2014 Digilent Inc. All rights reserved.
  • Circuit and breadboard images were created using Fritzing.