CSE466 Lab 3: “Pulse Width Modulation”
Objectives
The goal of this lab is to generate various colors
using a tri-color LED. To select the color to be output we will
create a virtual knob by measuring accelerometer readings through pulse width
measurements. In addition, you will also use pulse width modulation to control
the brightness of the LEDs. In this lab you will learn the following:
-
how to read an accelerometer reading via pulse width measurement ;
-
how to use the input capture on the 16-bit timer on the ATmega16 to do so; and
-
how to adjust the intensity of a light using pulse width modulation.
Important Warnings
Do NOT do either of these two things:
-
The ADXL202EB (the accelerometer evaluation board used in the
lab) is not reverse polarity protected. Do not reverse the +5V and ground
terminals as it will damage the ADXL202EB and make the part unusable.
-
Do not drop the ADXL202EB on a hard surface as it may generate
several thousand g's of acceleration, enough to damage the accelerometer.
Hints
-
Take this lab step by step and incrementally test
your code to make sure that it is working as you expected. Coding the entire
project first then trying to debug a problem can be challenging without the
usual forms of debugging. Make sure to test pieces of code one at a time and
convince yourself that they are working before moving on to another piece.
-
The lab is broken up into multiple parts to make the lab simpler
with smaller/simpler tasks that will build to the final result. It is a
good idea to save a copy of your code after each step. If for some reason you
are unable to complete the lab partial credit will be givin for each completed
step.
-
Utilize the 7-segment LED displays for debugging. WARNING: If you update the
7-segment LED displays each time through your main loop you might not be able
to read the numbers because it will be changing the number on the order of
milliseconds.
-
With a small enough period, a human eye should not
be able to perceive any flickering of the LED when the button is not pressed.
If you are seeing flickering it is most likely timing related, such as an
interupt being to long. You should try to eliminate any flicker from your
LED's, however, you should focus on completing the lab first instead of
spending huge amounts of time trying to troubleshoot.
-
Focus on making your system have a reasonable
interface. Do not get stuck trying to get timing calculations to work out
perfectly. The accelerometer is inherently noisy. The important thing is to
create an interface that “feels” right to a human. People will not notice
timing errors on the order of microseconds (maybe not even a few
milliseconds depending on where it is in the code).
-
We are using 2g accelerometers – that means they
detect accelerations up to two times the force of gravity. The parts should not
be subjected to too much more than this – being dropped or banged on a hard
surface. Your calculations can assume that you are only using gravity to
determine how far a user has turned the accelerometer to the left or right. By
using this assumption your calculations will be incorrect because they will not
take into account the force you yourself apply in starting and/or stopping the
accelerometer. Treat this(the starting/stopping acceleration) as noise as it is
difficult to account for this systematically in your calculations.
Suggested Reading
Resources
Brief
introduction to AVR Programming
avr-gcc manual
Application
notes section for the AVR 8-bit RISC family
Accelerometer(ADXL202)Datasheet (also
in CoursePak)
AccelerometerApplication Note on using the Duty Cycle
Output
Tri-Color LED Datasheet Note: We will
be using Common Anode LEDs.
Color Applets
Suggested Steps
PART 1:
-
Make a cable for your accelerometer module, using black wire for ground, red
for +5v, yellow for the Y-axis output, white wire for the X-axis output, and
blue wire for the button (the other end of the button is connected to ground).
Cut the wires about 10" long, and strip and crimp a Molex contact on one end of
each wire. The TAs will demonstrate. Push the contacts into the connector in
the correct positions. Attach your accelerometer to your cable. It is
VERY IMPORTANT that the colors match exactly so no miss wiring takes place.
-
Wire your accelerometer module into your breadboard with the cable you made.
Attach the Y-axis output to ICP1 (pin 20) and the blue wire to the
INT1 pin to detect button presses. Remember to add a pull-up resistor to
the button circuit.
Plug the X-axis output into an unused row on your breadboard as we will use it
later in the lab.
-
Refer to page 9 of the accelerometer datasheet in your coursepak to determine
what resistor to add to the accelerometer board at R1. R1 should be
chosen such that the period of the accelerometer’s PWM period
is approximately 4ms. Trim the leads to fit.
-
Review important warnings (YES, AGAIN) and apply power to the
circuit. Observe the y-axis output with an oscilloscope. Measure the period and
min-max duty cycle.
Complete Worksheet.
PART 2:
-
Download the PWM sample code. It uses the
output compare capability of timer 2 to generate a PWM wave to control the
brightness of an LED connected to OC2 (pin 21). Modify PWM sample so that you
can control the LED brightness by adjusting the value of a potentiometer.
-
Implement a program that uses timer 1 input capture mode to determine the
positive duty cycle. To do this, time the length of the positive pulse of your
accelerometer (rising edge to falling edge) and the length of the period
(rising edge to next rising edge). Use the 7-segment LED to display a ‘1’ when
the accelerometer has a duty cycle less than 50% and a ‘2’ when the
accelerometer has a duty cycle greater than 50%.
NOTES:
-
You should choose as small a prescaler factor as possible for Timer 1 to
increase the accuracy.
-
Use TCNT1 and ICR1 to access 16-bit values instead of using the 8-bit registers
(i.e. ICRL & ICRH and TCNT1L & TCNT1H)
-
Remember to set TCNT1=0 when you want the counter restart at 0. The input
capture interrupt does not reset TCNT1 to zero automatically.
-
Combine step 1 and 2 so that when you turn the accelerometer to the right
it makes the LED brighter and when you turn it to the left it makes the LED
dimmer. NOTE: If you turn the accelerometer-based virtual switch past 90
degrees it will start to decrease again. Use the two 7-segment LED displays to
output the value of your light level (the value of OCR2) in hex.
-
Modify your code so that the brightness only changes when the button on the
virtual knob is pressed. (Remember to debounce your button.) When the
button on the accelerometer board is pressed the user could be at any angle so
you must record the current position as a reference to determine if the user is
turning right or left. Use the two 7-segment LED displays to output the value
of your light level (or value of OCR2) in hex.
PART 3:
-
Add the tri-color LED to your breadboard by connecting the Common Anode to Vcc,
the red LED to pin21 (use a 560 ohm current limiting
resistor), the blue LED to pin 19(use a 300 ohm current limiting
resistor), and the green LED to pin 18 (use a 300 ohm current
limiting resistor). You may remove the LED and the two buttons that were
previously attached to these pins. NOTE: To aid in debugging you may want to
add 3 seperate LEDs in parallel to your tri-color LED to see the light level of
each color segment; however, make sure the parallel LED is seperate (i.e. has
its own current limiting resistor).
-
You will need to manually generate three seperate PWM signals to drive the
tri-color LED. Use timer0 to generate 3 seperate PWM signals for each
segment. A period of <15ms should not be visible to a human.
-
Use the potentiometer and the ATMega16's ADC to test your manual PWM signal.
Use the ADC readings (0-255) to control the LEDs brightness. You might want to
avoid using free-running mode to trigger the ADC as it might cause timing
problems. A good auto-trigger is Timer0 output compare (same interrupt that
should be generating your PWM).
PART 4:
-
Use the input capture from Part 2 to drive the tri-color LED instead of
the ADC (Part 3).
PART 5:
-
Plug the x-axis of the accelerometer into INT0 (pin 16)
-
Use INT0 and Timer2 to determine the positive duty cycle of the x-axis.
-
Use the accelerometer x-axis, the accelerometer y-axis, and ADC to
drive each segment of the tri-color LED.
PART 6:
GOAL: To generate various colors on the tri-color LED using the accelerometer to
select color and the potentiometer to adjust brightness. A user should be
able to press the button and move the accelerometer until they find a color
they want. On button release the H & S value should lock in. A user should
be able to update the brightness of the color they choose by adjusting the
potentiometer at any time.
-
Use the provided HSV to RGB code to control the tri-color LED.
Code
H->x-axis
S->y-axis
V->ADC value of potentiometer (this controls brightness)
-
To eliminate gitters make sure to average your values (H, S, & V).
-
The color should only change while the user holds the button on the
accelerometer down. Brightness should update anytime the value of the
potentiometer is changed.
-
Suggested timer uses:
-
Timer0 -> used to generate the 3 PWM’s needed for the tri-color LED
-
Timer1 -> input capture for the y-axis (possible button polling)
-
Timer2 -> used with INT0 to perform input capture for the x-axis
Question 1: Describe the differences between the HSV and RGB color
spaces. In general, how can you convert between the two.
Question 2: Describe why the code in your interrupt
handlers could not be located in the main body of the program. Basically
explain your design and why it was important for the specific code to be in an
ISR.
Deliverables
For all files turned in, the comments at the top of the fileshould contain:
-
Both partners' full name, login and student number.
-
The lab number and the part of the lab (e.g. “Lab 3”).
-
Demonstrate part 6 to a TA. You can either do this during this lab, or during
the first 1/2 hour of the next lab.
-
You will not receive full points if there is noticible flicker on any of your
LED's when the button is not
pressed.
-
The light levels of the LED's should not change until the button is pressed or
your potentiometer is adjusted (which should only adjust the brightness).
-
It should be possible to display all major colors on your Tri-Color LED (The
more distinct colors the better!).
-
Turn in hardcopy of your commented C code.
-
Make sure that the code in your interrupt handler is as minimal as possible. It
is fine to update state or do a little bit of work in the interrupt handler. We
will grade on how you designed your program to minimize code in the interrupt
handler.