Lab 8
Hardware Datapath Components
Honor Statement
This is an individual assignment. The code you write, use for the demo and
submit should be wholly your own and not produced by working in teams or using,
in part or in whole, code written by someone else (found online, from a fellow
student, acquaintance, etc.). You will be asked to verify this when you submit
your code on Vocareum by signing your name in the honor.txt
file on Vocareum.
Penalties for violation include a 0 on the assignment and a potential further
deduction or referral to Student Judicial Affairs.
Introduction
In this lab exercise you will use the ADC code you wrote in Lab 7 to interface the microcontroller to a potentiometer and to the buttons on the LCD module. These will be used as inputs to a moderately complex digital circuit to control the color and brightness of an LED. The circuit utilizes some of the hardware functional components we have studied in the lectures. This assignment will use a three-color LED (red, green and blue) where the color to be illuminated is selected using the LEFT and RIGHT buttons on the LCD. When these buttons are pressed the LCD will indicate which LED color is on and that color will light up. The brightness of the each LED color has two modes that are selected by pressing the UP or DOWN buttons. If the DOWN button has been pressed the brightness of the LED is determined by a pulse-width modulation (PWM) signal that controlled by the position of the potentiometer. So as you twist/rotate the potentiometer with your screwdriver, the brightness of the LED should increase or decrease. If the UP button has been pressed, then that LED color is set to full brightness and can not be adjusted by the potentiometer.
This lab uses several new components that were not provided as part of your lab kit at the start of the semester but were included in the bag of parts containing the servo motor that was handed out for Lab 7.
To see a short video demonstrating the operation of lab, click here.
For a copy of the Lab 8 grading sheet, click here.
Overview of Circuit
A block diagram of the circuit you will be building is shown below. It consist of five components:
-
A variable resistor (“potentiometer”) that provides a voltage between 0 and 5 volts to one of the analog-to-digital converter inputs to the Arduino.
-
An Arduino that is used to convert the analog voltage level to a digital value and also used to determine if any of the buttons on the LCD have been pressed. Based on these inputs the Arduino produces a PWM signal.
-
An 8-bit shift register that is loaded from the Arduino and stores the 2-bit selector numbers for the decoder, and 3 bits to enable full brightness for each of the LEDs.
-
A 2-to-4 decoder that is used to select which of the three LEDs to illuminate with the PWM signal from the Arduino.
-
A set of three AND gates to allow each LED color to be forced to be on all the time regardless of the state of the PWM signal.
In the sections below we will describe the circuit in more detail including showing how to wire most of it together.
Take care when you start wiring. Some of your demo points are for using APPROPRIATE colors (red = 5V, black = GND) and neatness.
Getting Started
Set up the Lab 8 assignment the same as has been done previously by creating a lab8 folder in your ee109 folder.
- From the class web site, download the file lab8.zip. This file contains lab8.c and Lab8_Answers.txt.
- Extract the files into the lab8 folder.
- Add a copy of Makefile, adc.c, adc.h, lcd.c, lcd.h from a previous lab to the lab8 folder.
- Modify the Makefile to work for the Lab 8 files. It should have
lab8.o
,lcd.o
andadc.o
on the OBJECTS line.
The Lab 8 program will be used during the installation of the hardware components to confirm that the components are working correctly. Because of this it’s necessary to get it running and downloaded to your Arduino even though the hardware hasn’t been installed yet.
If you look at the lab8.c file you will see that much of the code has been provided for you. At the start of the program add code to do the following:
- Initialize the LCD as has been done in previous labs.
- Configure the DDR bits for outputs on PB3, PC3 and PC5.
- Put up a splash screen with your name.
Once this has been done you are ready to move on to Task 1 and start adding additional code to interface with some of the hardware.
Task 1: Write the ADC routines
The Arduino’s analog-to-digital converter (ADC) module is used in this lab to adjust the width of the PWM signal going to the LEDs, and also to determine if one of the buttons on the LCD has been pressed.
Writing the code to operate the ADC module was one of the tasks in Lab 7 and
you should be able to copy the adc.c and adc.h files from your lab7
folder to
the lab8
folder. If you did not complete Lab 7 and do not have a functional
adc.c
file you will have to go complete this task as described in the writeup
for Lab 7 before you can move on to the rest of Lab 8.
Information on using the ADC module is available in a lecture slide set. A more in-depth review of this material is provided in a separate document “Using the Atmel ATmega328P Analog to Digital Conversion Module available on the class web site. Refer to any of these resources for information on configuring the various registers in the module and how to do the conversions.
Task 2: Determine the LCD buttons values
As part of Lab 7 you should have determined what value is returned by the ADC
for each of the five buttons on the LCD. These values will have to be edited
into the lab8.c
files. If you did not complete Lab 7 you will have to do
Task 2 in Lab 7 to determine these values.
Task 3: Install and Test the Potentiometer
The first part of the circuit uses a potentiomter to adjust the duty cycle of a PWM signal generated by one of the Arduino TIMER modules in the same manner as it was used in Lab 7. In this lab there will be several other components installed on the breadboard so we recommend that the potentiometer be installed near one end of the breadboard, perhaps between rows 5 and 10 of the breadboard. If you have to move the potentiometer, make sure to install it properly so the three pins are in three different 5-hole connection strips as was done in Lab 7.
As was done in Lab 7, make the following connections to the potentiometer.
-
Using one of the jumpers make a connection from the slider pin’s 5-hole strip to the Arduino A1 (ADC channel 1) input.
-
Using a wire connect one of the other two pins (either one) to the 5V bus on the breadboard.
-
Use a jumper to connect the 5V on the Arduino to the 5V bus on the breadboard.
-
Do the same for ground. Connect a wire from the remaining pin of the potentiometer to the ground bus, and use a jumper to connect ground from the Arduino to the ground bus.
Once the potentiometer is installed it’s highly recommended that you confirm that you have the potentiometer connected properly by using the DMM as was done in Lab 7. Check that the voltage on the slider pin can be changed by rotating the control. The DMM should show +5V when rotated fully in one direction and 0 when rotated to the other limit.
A second test of the potentiometer using the ADC is also recommended at this
point. This will confirm that the voltage can be converted by the ADC into a
number between 0 and 255. Your lab8.c
file has a while(1)
loop for testing
the ADC. Flash the new code to your Arduino, and then try rotating the
potentiometer back and forth.
The program should be displaying the numerical values of its conversions of the voltage on channel 1, and these should be close to 0 at one end of the rotation and close to 255 at the other. If you are not seeing this, you will need to fix the problem before using the potentiometer and ADC code in the next task.
NOTE: The while(1) loop that was used for Task 3 can now be deleted or commented out in your lab8.c file. The while(1) loop that is below that section of the file is the code that will do the rest of the lab assignment.
Task 4: Generate the PWM Signal
The next step is to write code to allow the digital value converted from the potentiometer analog input to control the duty cycle of a PWM signal generated by one of the TIMER modules. For this task we have to use the 8-bit TIMER2 module since it is the only one that has a PWM output that is accessible when the LCD is attached to the Arduino.
As was done in the Lab 7 where you used TIMER2 to control the position of the servo motor, TIMER2 will be used in the “Fast PWM” mode where it counts continuously from 0 to 255 and then starts over. At the start of the pulse period (count = 0) the OC2A output signal, which appears on Arduino port D11 (Port B, pin 3), will go to the high state to start the pulse. Register “OCR2A” is used to store a value that determines the pulse width by telling the timer when to terminate the pulse. During each pulse period, the timer counts up incrementing the count value, and when it reaches the value in OCR2A the output signal goes back to zero while the timer continues to count up to 255. The counter then resets back to zero and the process is repeated for the next pulse.
To control the brightness of the LED, we would like to generate a PWM signal with a period of 1ms or as close as possible to that. This means TIMER2 must be clocked at a rate that makes it count 256 times in 1ms, or about 3.9μs per count. The 16mHz Arduino clock goes through about 62 clock cycles ever 3.9μs which is too fast. If we use a prescalar of 64 this slows the clock for TIMER2 down to 250kHz. At this rate it will do 256 counts in 1.024ms which is close enough.
The code you wrote in Lab 7 to initialize TIMER2 can be reused here, but make sure to change the line that sets the prescalar so it’s using a factor of 64. The CS22, CS21 and CS20 bits in the TCCR2B register should be set to 100 for a prescalar value of 64. You also don’t need TIMER2 to generate any interrupts so make sure to NOT enable TIMER’s overflow interrupts.
As was done in Lab 7, the width of the PWM signal is controlled by the value stored in the OCR2A register. For this lab, this is the value returned by the analog-to-digital conversion of the voltage from the potentiometer. In the main loop of your code, after getting the converted value, simply copy it to the OCR2A register. This way every time the potentiometer is varied, the ADC will produce a different value and this will change the PWM signal accordingly.
Once you have made these change to the code, download it to the Arduino. To see if it’s working, connect a scope proble to the PB3 (D11) output of the Arduino and try rotating the potentiometer. It should change the duty cycle of the PWM signal from close to 0% to being 100%
Checkpoint: Show the PWM signal on the scope to one of the teaching staff to record that you have the checkpoint task completed for this lab. Demonstrate that turning the potentiometer adjusts the duty cycle of the PWM signal across its full range.
The Circuit for Controlling the LEDs
Note: The following is a description of the LED control circuit. Don’t start wiring the circuit until you have finished reading this section and have an understanding of how it works, and then move on to Task 5 below to do the wiring.
The main part of the Lab 8 circuit contains the circuitry to control which LED is affected by adjusting the PWM signal, and also provides the ability to force an LED to full brightness. The schematic diagram is shown below
74LS164 Shift Register
The shift register is controlled by two signals from the Arduino.
- PC3 is the data to be stored in the shift register. Your code will have to put the required bit on PC3 before generating the clock signal to load it into the shift register.
- PC5 is the clock signal to store the data on PC3 in the first stage of the shift register (Q0). Your code will have to generate the 0→1→0 signal on PC5 for the clock.
The shift register stores five bits that control the multiplexer and the decoder.
- Bits Q1 and Q0 contain the 2-bit number connected to the S1:S0 decoder selector bits for determining which of the decoder outputs will illuminate the attached LED.
- Bits Q4, Q3 and Q2 contain the 3 bits which can be used to force one or more of the LEDs to be at full brightness. Q4 controls the blue LED, Q3 the green LED, and Q2 the red lED
Note that you can not load the individual bits in the shift register. Each time your code needs to change any of the these bits, it must reload all five bits in the shift register.
74LS139 Dual 2-to-4 Decoder/Demultiplexer
The decoder/demultiplexer is used to determine which LED color is illuminated by the PWM signal. This IC contains two independent 2-to-4 decoders/demultiplexers. This IC is called a “decoder/demultiplexer” since it can serve either function depending on how it is used. In this lab assignment we will use one of them as a “demultiplexer” (reverse multiplexer).
This demultiplexer has active low outputs meaning that the selected output will be in the 0 state and all the other outputs will be in the 1 state. This is the opposite from the decoders that were discussed in the lecture where the selected output was a 1 and all the others were 0. The enable input (EN) is also an active low input so when EN is a 1 this is the disabled state and all the outputs are 1’s. We can operate the device as a demultiplexer by connecting the input signal (the PWM signal from the mux) to the EN enable input.
- If EN is a 1, all the outputs are a 1, including the selected one.
- If EN is a 0, the two bits from the shift register determine which of the four demultiplexer output goes to the 0 state.
When used in this manner the PWM signal is effectively connected to whichever output is selected by the two selector bits, essentially a “demultiplexing” operation.
Brightness Control Gates
The Y0, Y1 and Y2 outputs from the 74LS139 are each connected to one input of three AND gates which are actually NAND gates with a NOT gate on the output to produce the equivalent of an AND operation. The other input of each gate comes from the 3 bits stored in the shift register in bits Q2, Q3 and Q4
- If this bit is a 1, the output of the decoder passes through the AND gate to the LEDs and can control the brightness based on the PWM signal.
- If this bit is a 0, the output of the AND (NAND+NOT) gate is zero which forces the LED to be on 100% of the time resulting in the full brightness.
The output of the NOT gates are connected through current limiting resistors to the three colors of the RGB LED. When the gate output is in the 0 state, that LED color will illuminate.
Installing the ICs on the Breadboard
In addition to the potentiomer you just installed, the circuit for Lab 8 uses four integrated circuits that will have to be installed on the breadboard and wired correctly. One of the ICs (74HCT04) was in the original set of components provided at the start of the semester. The other three should have been in the components handed out for Lab 7.
Note: Some of the ICs supplied are from the “74LS” family of ICs, and some may be from the newer “74HCT” family. ICs from these two familiies are compatible and can be connected together. In the discussion or diagrams below it may mention a 74LS139 but if yours is a 74HCT139 it works exactly the same.
Before installing them on the breadboard make sure that you can identify the proper way to orient the IC. All ICs have a marking on the package to identify pin number 1 as shown below.
There are numerous ways the ICs can be positioned on the breadboard. However the length of the wiring connections that will have to be made can be reduced significantly by careful selection of where to install the ICs. To simplify the wiring connections we strongly recommend that you install the ICs in the positions shown below.
The rows of holes on the breadboard are numbered from 1 to 63 and we recommend installing the ICs so that pin 1 of each IC is in the following positions:
- 15: 74LS164 shift register
- 24: 74LS139 decoder
- 34: 74HCT00 NAND gates
- 43: 74HCT04 NOT gates
The potentiometer can be installed in the space between rows 1 and 10, and the space in rows 51 to 63 will be used for the multicolor LED and associated resistors.
This circuit requires that many of the IC pins be connected to power or ground. To greatly reduce the length of this wiring we strongly recommend installing two wires as shown in the diagram above the that connect the ground bus along the bottom of the board to the ground bus along the top, and similarly for connecting the two power buses together. This will allow you to connect the IC pins to power or ground with very short pieces of wire.
Task 5: Build the Shift Register, Decoder and AND Gate Circuit
In this task we will build the part of the circuit with the shift register, decoder, NAND and NOT gates. The pinout diagrams for the shift register and decoder are shown above. The diagram for the NAND and NOT gates are below.
-
Install the 74LS164, 74LS139, 74HCT00 and 74HCT04 integrated circuits on the breadboards and make the power and ground connections to them.
-
Add any additional connections to power and ground on ICs where logic 1 or 0 inputs are required.
-
Make the connections between the shift register outputs Q0 and Q1 to the decoder S0 and S1 selector bits as shown above.
-
Using a jumper from your lab kit, make the connection between the Arduino PB3 output and the decoder EN input.
-
Using the jumpers from your lab kit, make the connections for the shift register clock and data from the Arduino PC5 and PC3 outputs.
-
Make the connection between the Y0, Y1 and Y2 outputs of the decoder and three of the NAND gates. There are four two-input NAND gates in the 74HCT00 IC, so just pick any three of them to use.
-
Make the connections between the shift register outputs Q2, Q3 and Q4 and the three NAND gates that you selected to use in the previous step.
-
Make the connections between the three NAND gate outputs and the inputs of three of the NOT gates. There are six NOT gates in the 74HCT04 so just pick any three of them to use.
This completes the installation and wiring of the four integrated circuits. Make sure the wiring is neatly done and the wires are not excessively longer than needed to go between two points.
Task 6: Install the RGB LED
The final component to install on the breadboard is a multicolor LED. The LED is included in the same bag of parts from Lab 7 that contained the four ICs used above. The LED contains three separate LED elements inside it, one glows red, one glows green and the third glows blue, which leads to them being called “RGB LEDs”. The three LEDs inside it have separate cathode (lower voltage) leads, but their anode leads, the one that goes to the higher voltage, are connected together so it is referred to as a “common anode” device. On the package, the common anode lead can be identified since it is longer than the other three. When wiring up an RGB LED, all three elements need to have separate current limiting resistors as shown below.
It is recommended that you use the 240Ω resistors from your parts bag for the red and blue LEDs, and use one of the 680Ω resistor for the green LED.
Do the following steps to install the RGB LED.
-
Install the LED on the breadboard being careful to have all four leads of the LED in four separate wiring blocks.
-
Connect the common anode lead (the longer one) to the +5V bus.
-
Connect the three current limiting resistors to the LED red, green and blue leads.
-
Connect the other end of the resistors to the NOT gate outputs as shown on the schematic above. Hint: To make it easier to debug, consider using red wire to connect the red segment, green wire for the green segment, and blue wire for the blue segment.
Task 7: Finishing the Program
The lab8.c file provided for you contains several parts of the program that are
already written. All the code for reading the button presses using the ADC and
updating the LCD screen is provided and should not have to be modified. This
part of the program modifies the variables “color
” to have the values 0, 1 or
2, and modifies the elements of the “level
” array to be either 0 or 1.
Whenever any of these variables are changed, the new values must be transmitted
to the shift register using two functions that you will have to write (the
function skeletons are in the lab8.c file).
-
shift1bit
- This function take a single argument “bit
”. If the argument is zero, a 0 is shifted into the shift register. If the argument is non-zero, a 1 is shifted into the shift register. This function has to set the proper value on the PC3 output, and then generate the clock pulse on the PC5 output. -
shift_load
- This function is used to load the shift register with the selector numbers for the decoder, and with the three bits for forcing an LED to be on all the time. This function has five arguments: “demux
” containing the number from 0 to 2 for the decoder/demultiplexer selector bits. The other three arguments “r”, “g” and “b” are the brightness settings for each LED. A zero value will turn that LED on all the time. A non-zero value will allow the PWM signal to control the LED’s brightness.
Whenever shift_load
is called it must transfer all 5 bits (2 for the demux, 3
for the brightness) to the shift register, so it should make five calls to
the shift1bit
function. The shift_load
function must also send the bits
in the right order so they end up in the correct positions in the register
after all five bits have been clocked into the register.
Write the code for the shift1bit
and shift_load
functions and you can then
test the program to see if it works correctly. Below are some things to test.
-
When colors are in the PWM mode (a “P” shows above the color on the LCD) pressing the left and right buttons on the LCD change the color and matches the color indicated on the LCD.
-
When the up and down button are pressed the LED brightness mode changes. In the PWM mode the brightness of the selected color can be adjusted and this is indicated on the LCD by a “P” above the color. In the fully on mode the selected color is at full brightness and this is indicated by a “∗” above the color.
If it is not working correctly, try checking the items below using the scope to observe various signals.
-
Check that the shift register bits change as expected when the buttons are used to change the brightness or color settings.
-
Check that the decoder outputs change when the left and right buttons are pressed to select a color to illuminate.
Results
When your program is running you should be able to confirm the following
-
Pressing the left and right buttons changes which color LED is illuminated.
-
Rotating the potentiometer changes the brightness of the LED of the selected color.
-
Pressing the up and down buttons changes the brightness mode of the LED. In PWM mode the potentiometer can change the brightness. In full on mode the selected color is on at full brightness.
-
The brightness mode for a color is retained if the buttons are used to switch to another color.
-
Try setting all three colors to the full on mode and this should make LED glow with an almost white color.
-
The power and ground wiring should be neatly done using short wires that make the connection from the power and ground buses to the correct pins. See the demo board at the podium for an example.
-
The other wiring between the IC pins, resistors and LED should be neatly done and not use excessively long wires.
Once you have the assignment working demonstrate it to one of the instructors. The answers to the review questions below should be edited into the Lab8_Answers.txt file. The Lab8_Answers.txt file and all source code (lab8.c, lcd.c, lcd.h, adc.c, adc.h and Makefile) must be uploaded to the Vocareum web site by the due date. See the Assignments page of the class web site for a link for uploading.
Please make sure to save all the parts used in this lab in your project box. These may be needed in the semester project. We suggest also saving all the pieces of wire you cut and stripped since those will be useful in later labs.
Review Questions
Answer the following questions and submit them in a separate text file (“Lab8_Answers.txt”) along with your source code.
-
We would like to add a feature where if the Select button is pressed on the LCD, it turns the LED off completely, and then turns it back on when Select is pressed again. Explain how this could be done without having to make any changes to the wiring of the circuit .
-
When TIMER2 is counting, the count value is kept in the
TCNT2
register and is constantly being compared for equality (and only equality) to the values in theOCR2A
register to determine when to terminate the PWM pulse. Suppose at some point your program adjusts the PWM width by changing theOCR2A
register, and the newOCR2A
value is lower than the value that is currently in theTCNT2
register. What will happen to the output signal during this pulse period?