CSEP567 Lab 5: “Colors”

Objectives

The goal of this lab is to learn how to use pulse width modulation to control the brightness of the LEDs. In this lab you will generate various colors using a tri-color LED. 

Suggested Reading

The following sections of the ATmega16 datasheet might be helpful for this lab

  • Analog to Digital Converter 
  • 8-bit Timer0

    Resources

    Tri-Color LED Datasheet Note: We will be using Common Anode LEDs.
    Color Applets
    Brief introduction to AVR Programming
    avr-gcc manual

    Suggested Steps

    Section I: RGB

    1. Add the tri-color LED to your breadboard by connecting the Common Anode to Vcc, the red LED to pin 21 (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). Please DO NOT TRIM the tri-color LED leads. You may remove the LED and 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).
    2. Remove the 7-segment LED on PORTB. Move the LCD screen control lines (RS and E) to Pin 1 and 2. Move a button to Pin 3. Make sure this input remains an input as it will disrupt the ADC. From the datasheet:"AIN0, Analog Comparator Positive input. Configure the port pin as input with the internal pull-up switched off to avoid the digital port function from interfering with the function of the Analog Comparator."
    3. 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.
    4. Add two additional potentiometers to the ATMega16's ADC on pin 38 and pin 37.  
    5. Test that your PWM signals are working by obtaining ADC readings (0-255) from the 3  potentiometers ('R', 'G', and 'B') and use those values to determine each LED segment's postive duty cycle. Use the button on pin3 to toggle between obtaining ADC values from 'R', 'G', and 'B' (Remember to debounce your button). This means your programshould constantly read a potentiometer (e.g. 'R') until the user presses the button on Pin 3, then start to get ADC readings from a different potientiometer (e.g. 'G'). Each LED segment should vary its brightness with the value of its potentiometer thereby changing the color being generated by the tri-color LED. If you run into timing problems you might want avoid using free-running mode to trigger the ADC, a good alternative auto-trigger is Timer0 output compare (same interrupt that should be generating your PWM). Please refer to the ATmega16 datasheet on how to properly switch ADC channels. By using an alternative trigger source you should be able to update the ADMUX at the end of the ADC ISR. Use the largest ADC prescaler. 

    Demonstrate Section I to a TA.

    Section II:  HSV

    (Note: color spaces are discussed in the Oct. 27 lecture slides.) 

    1. Revise your code from Section I to include the provided HSV to RGB conversion code so that the HSV values determine the color of the tri-color LED. The HSV signals should be:
      H->ADC value of potentiometer (pin 37)
      S->ADC value of potentiometer (pin 38)
      V->ADC value of potentiometer (pin 40)
    2. To eliminate gitters make sure to average your values (H, S, & V).

    NOTE: You might want to average some of the ADC values to prevent the light from flickering on and off. A weighted moving average might be a good idea for smoothing. Below is an example formula for a weighted moving average where a larger value for x will cause “new value” to have a smaller affect on the average.

    average = ((previous average * (x -1)) + new value) / x

    Choosing X to be a number that is a power of 2 (e.g. 8 = 2^3) will allow you to eliminate the divide and replace it with a shift.

    For the purpose of this class DO NOT divide a floating point number on an ATmega. Keep everything in integers when dividing!

    Demonstrate Section II to a TA (see delieverables section).

    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:

    1. Demonstrate your HSV color generating system to TA.
      • It should be possible to display all major colors on your Tri-Color LED (The more distinct colors the better!).
    2. Turn in hardcopy of your commented C code and the answers to the questions in the lab.
      • 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.