ECE 110/Fall 2022/Digital Logic

From PrattWiki
Jump to navigation Jump to search

This is a support page for the ECE 110 lab on binary and digital logic.

Pre-Laboratory Exercise

The 2-bit counter example is at: ECE 110: 2-bit counter. If you would like to Tinker the model, you will need to be logged into Tinkercad before clicking the link. If all you want to do is look at the code or simulation, you can do that without logging in.

Code Overview

The goal for this code is to set up two digital output pins (P2 and P3) to serve as the 1's and 2's digit of a 2-bit binary number. In the setup, the code will initialize each channel and set the output LOW. In the loop, there is a loop that will go through the valid possible values of a 2-bit binary number (0, 1, 2, 3). This inner loop will print the decimal equivalent of the number to the Serial Monitor and then use a function send_to_lights() to do the work of determining which lights should be on and which should be off. The inner loop waits for half a second so we humans can track the lights as they change rather than enduring a stroboscopic light show.

Global Variable

The setup, loop, and send_to_lights() functions all need to know how many lights (bits) there are. NL is the number of lights and also the number of bits. Setting this as a global variable means later code can use that value rather than having a hard-coded number of lights.

// Set up Global variable
int NL = 2;

setup

There are two main parts to the setup. First, we will use the Serial Monitor to be able to track values. Second, we need to set up the pins on the Arduino as digital outputs and then set them to 0 so the lights all start off. Since we want to expand this code, the easiest way to do that is to run a loop that sets each pin. The loop variable could either be the power of 2 each pin represents (0 and 1) or the actual pin being used for those powers of 2 (2 and 3). In this code, the light variable is the pin being used, so the light variable should loop from 2 to one more than the total number of lights (in this case, that would be 3).

void setup()
{
  // Start Serial Monitor
  Serial.begin(9600);
  // Initialize pins for lights and set low (off)
  for (int light=2; light<=NL+1; light++){
    pinMode(light, OUTPUT);
    digitalWrite(light, LOW);
  }
}

loop

The loop function is itself going to contain a loop that iterates through all the possible values of a 2-bit binary number. The n value will start at 0 and iterate until reaching $$2^{NL}-1$$; for two lights, that means it will go through 0, 1, 2, and 3 before the inner loop ends (only to get called again when the loop function...erm...loops!). The inner loop will print the value being represented on the lights, call the send_to_lights(n) function (passing the value to be represented to that function), and then delaying by half a second. Note that the pow(2, NL) code essentially calculates $$2^{NL}$$, however the result is a floating point number, and there may be roundoff. Though the fact that we are using a < operator means slight smaller values than a true $$2^{NL}$$ would still work properly, round(pow(2, NL)) guarantees that the result from pow() is rounded to the nearest integer.

void loop()
{
  for (int n=0; n<round(pow(2, NL)); n++)
  {
    Serial.println(n);
	send_to_lights(n);  
	delay(500);
  }
}

send_to_lights

This code will take a decimal value and then loop through the lights to determine how each light should be set. As in the setup, there is a loop that loops through the pin numbers of the lights. The core of this loop is the bitRead(val, light-2) part. Arduino has a reference page on [https://www.arduino.cc/reference/en/language/functions/bits-and-bytes/bitread/ bitRead(). The main idea is that you can give it an integer value for the first argument and a particular bit to read. The function will convert the integer value into binary and then return the bit you asked for. The second argument is basically which bit do you want, where bit 0 would be the LSB or 1's digit, bit 1 would be the 2's digit, etc. Here are some examples of responses from bitRead()

bitRead(6, 0) -> 0 // since 6 is 110 in binary and the 2^0 or 1's digit is 0
bitRead(6, 1) -> 1 // since 6 is 110 in binary and the 2^1 or 2's digit is 1
bitRead(6, 3) -> 0 // since 6 is 110 (thus 0110) in binary and the 2^3 of 8's digit is implicitly 0

This means we can use a loop to interrogate each bit in the number and send that bit's value to the light using digitalWrite() - conveniently, digitalWrite() interprets 1 as HIGH and 0 as LOW for its second argument. As in the loop function, we have a decision to make about the looping variable - it could either be the digital pin we are setting or the bit location. To keep this loop consistent with loop's loop, the variable is the pin number, meaning the bit we are looking for is two less than the light number (i.e. the light connected to P2 needs bit 0, the light connected to P3 needs bit 1, etc).

Circuit Overview

Each bit will be represented by a different color light. The least significant bit will be a red light at the far right of the circuit board; more significant bits will be further to the left. Because the Arduino produces 5 V, and 5 V is higher than the maximum recommended voltage across an LED, we will put a 470 $$\Omega$$ resistor in series with the LED before connecting each bit's circuit to ground.

Experimental Exercises

Generating Random Numbers

The function random(a, b), where a and b are integers, will generate a random integer [a, b) (that is, between a (inclusively) and b (exclusively). If you wanted to roll a six-sided die, for example, you would use random(1, 7).

Getting an Integer from the Serial Monitor and Doing Something With It

See Worst Game Ever

For this game, the computer will generate a random number between 0 and 3. It will then expect you to type the number into the Serial Monitor input and send it. The Arduino will keep monitoring the Serial Monitor until it receives data. It will then use the Serial.parseInt() function to take the data it received and convert the information into an integer. Once it has the integer, it will increment the total number of times the game has been played. It will then use an if tree to print whether the answer was correct. Also, if the answer was correct, it will increment the variable keeping track of the correct number of answers. Finally, it will print out some boilerplate text and values as needed to communicate the state of the game.


Exploration

Checking Gates

Here are some Tinkercad simulations showing the wiring and code for checking the various gates: