Gates
Logic gates
are the simplest building blocks of computer hardware.
They implement one operation, such as
an &
or |
, that use a very small
number of bits.
We are going to implement a few of these in this lab.
We will also build a few simple memory elements.
However, we are going to start by building a “blink” circuit.
A bit about the Arduino
- Arduino Uno
- Uno schematic
- ATmega328/P datasheet — summary and complete (see pages 13, 14, 98 & 99)
- Arduino = Processing + Wiring
- Arduino Language
Reference —
setup()
andloop()
- Arduino is based on C++ but pointers are discouraged
- 0 is false and non-zero is true.
Making sure it can works
There are a few things we must verify before we start this lab.
Getting in the right group
Start up a command-line session and type the following command:
id
This will list the Linux groups to which you belong.
Make sure that you are a member of the group dialout
.
If you aren’t, get in touch with the instructor.
Making sure the Arduino is recognized
Using the USB cable, connect your Arduino to your workstation.
Use should be able to use the USB ports on the monitor.
List the devices on the USB bus with the following command:
lsusb
If you don’t see the Arduino listed, get in touch with the instructor.
Making sure the Arduino device file is present
Type the following command to make sure the Linux has allocated
a device file for your Arduino.
ls -l /dev/ttyACM*
You should a device file name similar to
/dev/ttyACMX
which is writeable by members of the dialout
group.
Remember the name!
Having up-to-date software
The Arduino IDE is frequently updated
due to the steady release of new Arduino-compatible devices.
We need to use a more recent version of
Arduino than is distributed with Ubuntu.
Type the command:
/usr/local/bin/arduino &
If it doesn’t work, again get in touch with the instructor.
You should be able to lock the latest version of
Arduino to your Launcher by dragging
/opt/share/applications/arduino.desktop
to the Launcher.
An exploration of the Arduino, ATmega328, and C++
In this part of the lab, you are going to turn an LED on and off as you are introduced to many things that will appear later in this course.
Connecting the IDE to the board
Make the following choices in the Arduino IDE to direct the IDE’s attention to your board.
- Tools → Board → Arduino/Genuino Uno
- Tools → Serial Port → /dev/ttyACMN
Blinking the LED
Open Blink tutorial, However, don’t use a breadboard! On the Arduinos we have, pin 13 is already connected to a built-in LED and current-limiting resistor. Also, don’t connect an LED to your Arduino! Cut-and-paste the blink program into a new sketch and run it. You should see the LED blink.
Change the blink rate. Make it blink as fast as you can without it looking like a somewhat dimmed LED.
Blinking the LED with memory
In embedded systems,
“special function registers” are to read and write pins.
These special function register look like a memory location to a C program.
In this section,
you’ll skip the digitalWrite
and write
directly to the pin.
This will test your mastery of C and Java’s bit operations.
Printing in the serial monitor
You will use two very important features of the Arduino language in this part of the lab. Take a look at the following references so that you can do the next part of the lab.
Add a call to Serial.begin(9600)
in your setup
function to initialize the serial port.
Now add a statement to print the variable PORTB
in binary (using BIN
) in your loop
function
after each call to digitalWrite
.
Build and run your program. You will need to do Tools → Serial Monitor to see the output of your program.
Be sure PORTB
is being printing within the
serial monitor. The output line should look something like the
following:
PORTB=11001100
Read the documentation for
Serial.print()
until you get this right.
Special function registers of the ATmega328
The variable PORTB
is a special memory location within
the ATmega328 chip. Writing to this location sets the output of
pins 8 to 13 of the Arduino
to either 0 (low) or 1 (high).
In embedded microcontrollers these pins are called
GPIO, general-purpose input/output, pins.
Look at
the
Arduino page for port manipulation to see how to
change PORTB
without calling DigialWrite
,
along with a reason why you might want to do this.
(By the way, you really shouldn’t do this.)
Modify your loop
function so that it turns the
LED on and off directly, that is, with statements similar to
PORTB |= Bxxxxxxxx
;
and
PORTB &= ~Byyyyyyyy
;
Try to figure out the xxxxxxxx
and yyyyyyyy
on your own.
It will be good practice with bit manipulation.
Big hint: Pin 13 corresponds to bit 5 of PORTB
.
By the way, the rightmost bit is number 0.
C++ implementation of Arduino classes
Serial
is an object within the
C++ class HardwareSerial
and print
is
a method of HardwareSerial
.
The HardwareSerial
class extends the Stream
class,
and
The Stream
class extends the Print
class.
Every Computer Science guru must know a little C++. So let’s take a guided tour of some C++ modules. Just be glad we no longer teach CSCI 202 using C++.
First connect to the Arduino GitHub in a new tab and navigate to the directory hardware/arduino/avr/cores/arduino. Take a look at the following files: (I’m serious. You need to know how to use GitHub.)
- HardwareSerial.h — Class definition for
HardwareSerial
- HardwareSerial.cpp — Class implementation for
HardwareSerial
- Stream.h — Class definition for
Stream
- Stream.cpp — Class implementation for
Stream
- Print.h — Class definition for
Print
- Print.cpp — Class implementation for
Print
Next, take a look at how the
C code implements GPIO in
wiring_digital.c where you will find
the C function
Digital Write
(around line 137).
Setting an individual bit is accomplished by use of
masking
operations inside this if
statement:
if (val == LOW) { *out &= ~bit; } else { *out |= bit; }
The *
in the above code segment is the C and C++
dereference operator for pointers.
Most likely, the instructor will guide you through this.
Input to the Arduino
Right now, your Arduino has only one output. In this part of the lab, you will also process input.
Start by taking a look at an Arduino lesson, from Adafruit, on Digital inputs. Best to open it in a second browser window for this task.
Building a breadboard
Stop the Arduino IDE and unplug your Arduino.
Get a breadboard (the half-size or even the mini will work fine) and create a circuit similar to that shown in Adafruit’s digital inputs lesson but include a second LED connected to the Arduino output pin of your choice. (I suggest pin 3.)
You must use a current limiting resistor for each LED, because only pin 13 is connected through a resistor on the Arduino board. You do not need a pullup resistor for your switches, because there is an internal pullup of 20 to 50 kΩ in the ATmega328 chip. This is common for microcontroller chips.
Wire up your breadboard so that in has two input switches and two output LED’s.
Have someone, maybe a fellow classmate, check your wiring.
By the end of this class you should know how to wire up an LED and button switch without looking at any reference.
Loading the initial program
Restart the Arduino IDE and cut-and-paste the program from the digital inputs lesson into a sketch.
Test the program.
Improving the program
Meaningful variable names
Change the names of the variables to something more suggestive than
buttonApin
and
ledPin
.
I suggest you use
leftSwitch
, rightSwitch
,
leftLight
and rightLight
to hold the
pin numbers.
However, be like a real C programmer, and declare the
pin variables with the const
modifier.
(Google for it.)
Modify your program so that the left switch turns the left LED on and off, and right switch turns the right LED on and off,
Meaningful function names
Think a little about how your program reacts to the switches and
LED’s. What value is read when then switch is pressed:
HIGH
or LOW
?
What value is written to turn on the LED:
HIGH
or LOW
?
It can be confusing to remember if the “output” of the
switch was 0 or 1 when it was pressed.
Let’s write two functions to help us out here.
switchRead
, likedigitalRead
, has a single parameter. It returns 1, if the switch is pressed, and 0, if the switch is not pressed.ledWrite
has the same parameters asdigitalWrite
. It turns the LED on, if its second parameter is non-zero, and off, if its second parameter is zero.
Keep in mind that in C/C++, 0 is false
and non-zero is
true
.
These two functions are very short, probably just a single
if
—else
statement.
(You should be able to write the function headers all
by yourself with no references.
Don’t interview for a job before you can do this.)
Aim for a loop
that looks like this.
void loop() { boolean leftPressed = switchRead(leftButton) ; boolean rightPressed = switchRead(rightButton) ; ledWrite(leftLED, leftPressed) ; ledWrite(rightLED, rightPressed) ; }
By the way, boolean
is really just another way of
saying int
in C. There really isn’t a boolean
type.
Change the boolean
to int
to prove you are
a true or, at least old-fashioned, C programmer.
Again, test your program to verify this change.
The AND and OR
Modify your program so that the left LED displays the AND
(C/Java &
)
of the two inputs and the right LED displays the OR
(C/Java |;
).
The AND
is on only when both buttons are pressed.
The OR
is off only when both button are unpressed.
Do this without any
if
—else
statements in the
loop()
. Just use C’s logical operators
and two simple statements.
This JavaScript page illustrates what your program should be doing.
The NAND and NOR
Modify your program so that the left LED displays the NAND
of the two inputs and the right LED display the NOR
.
The NAND
is off only when both buttons are pressed.
The NOR
is on only when both button are unpressed.
(These gates are the basic building blocks on digital logic.)
Do this without any
if
—else
statements in the
loop()
. Just use C’s logical operators
and two simple statements.
If you can’t figure out the NAND
and NOR
,
try out this
JavaScript page.
Another hint: NAND
is NOT-AND and
NOR
is NOT-OR.
An interesting fact: NAND
is the most common gate
in digital design.
The SR latch
A latch is not a gate, but we are going to do one anyway.
Create an SR latch with your Arduino. Assume your switches are S (for set) and R (for reset) and call your LED’s Q and Q'. (This is the standard.) When the S button is pressed the Q should be turned on. When the R button is pressed the Q should be turned off. The Q' output is always the opposite of the Q. You may assume that no one ever presses both S and R at the same time. If they do, the SR latch is allowed to self destruct.
You may want to add an extra variable to your program that records the present value of the flip-flop, but this really isn’t necessary.
Show off your latch.
Here’s a link to a JavaScript SR latch.
The SR latch is basis of the SRAM (Static Random Access Memory). This fast memory used to implement processor registers.
The D latch
The D latch has one data input and enable (or clock) input. The D latch “reads” and remembers its data input only when the clock is 1. While the clock is 0, changes in the data input are ignored. The initial state of the flip-flop should be 0 for the D.
Create a D latch with an Arduino program. This one might just be a little easier than the SR latch. Remember, the initial value of the D flip-flop should be 0.
Here’s a link to a JavaScript D latch.
The D positive edged flip-flop
The D flip-flop (regretably, generally called the master-slave flip flop) has one data input and one clock input. The D flip-flop “reads” and remembers its data input only when the clock changes from 0 to 1.
The edge-triggered flip-flop is one of the most used memory elements of the processor. They are usually implemented by connecting two SR latches, but that&rsqsuo;s not a natural way to simulate them in a C program.
Create a D flip-flop with an Arduino program. This time the solution is a little harder. Your program must remember the old value of the clock to determine when the clock has changed from 0 to 1.
Here’s a link to a JavaScript D flop-flop.