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 given 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 interrupt
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.
- DON’T USE FLOATING POINT NUMBERS.
Suggested Reading
Resources
Brief
introduction to AVR Programming
avr-gcc manual - located at:
C:\WinAVR\doc\avr-libc\avr-libc-user-manual\index.html
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:
- Remove the 7-segment LED on
PORTC/D.
- 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). NOTE: To aid in debugging you
may want to add 3 separate LEDs in parallel to
your tri-color LED to see the light level of each color segment; however,
make sure the parallel LED is separate (i.e. has its own current limiting
resistor).
- A cable has been provided
for your accelerometer module, using black wire for ground, red for +5v,
yellow wire 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).
- 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 pre-scalar 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 one 7-segment LED displays to output the most
significant byte 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 de-bounce 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 one 7-segment LED displays to output the most significant byte of
your light level (or value of OCR2) in
hex.
PART 3:
- You will need to manually
generate three separate PWM signals to drive the tri-color LED. Use timer0
to generate 3 separate PWM signals for each segment. A period of
<15ms should not be visible to a human. (For the end of the lab we
encourage using a period less than 15 ms, but start at 15 ms and then reduce
it as a smaller period will be more taxing on the processor.)
- 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 of
the accelerometer 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 create a manual interrupt capture routine 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. (Note: The skeleton code being provided
is formatted to help minimize potential timing problems. We highly suggest
you bring your code into the skeleton, not the other way around.) Code
H->x-axis
S->y-axis
V->ADC value of potentiometer (this
controls brightness)
- Make sure to adjust the
three constants (COLOR_SPACE_MAX,
X_BASE, Y_BASE) to get the highest possible color
spectrum.
- To eliminate gitters/flickers 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
5. After this is
working (and you’ve added averaging) you can drop the PWM period to further
reduce flickering. However, if the period is dropped too far flickering will
increase.
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 file should 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 noticeable 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.