CSE466 Lab 2: “Interrupts”
Objectives
The goal of this lab is to introduce various features and modules of the
ATmega16 while introducing how to program the microcontroller using C. In this
lab you will learn the following:
- how to operate an
oscilloscope;
- how to program a timer
interrupt;
- how to debounce a button in
software;
- how to use the A/D converter
and its interrupt features.
This lab assignment has 3 required sections and 1 optional section that can
be completed for extra credit. Some of the sections have multiple graded parts
so make sure to save ALL the graded parts so they can be turned-in and/or shown
to the TAs for grading. The deliverables section below outlines exactly what
will be graded.
Section A: Introduction &
Tutorial
1. Setup
the C programming environment
2. Complete
the Oscilloscope tutorial
3. Add
additional hardware to your breadboard
Section B: Timers
1. Reimplement
your “One Minute Counter” from Lab 1 in C (instead of assembler) and compare
the code sizes.
2. Reimplement
the counter (again) but use a timer interrupt to control counting rate instead
of a delay loop. In addition, the counter should also be able to start, stop,
and change direction based on the two added buttons. (GRADED DEMO)
Section C: Analog to Digital
Converter
1. Read
the analog value coming from the potentiometer or photoresistor and output the
most significant 8-bits in hexadecimal notation to the two 7-segment LED
displays. Use a button to toggle between displaying ADC values from the
potentiometer and the photoresistor. (GRADED
DEMO)
2. Use
the potentiometer to create an adjustable light sensor that turns on an LED
when the light level drops below the value of the potentiometer. (GRADED DEMO)
Section D: Create a light meter
(EXTRA CREDIT)
See
Extra Credit Page
Suggested Reading / Helpful Hints
- The
following sections of the ATmega16 datasheet might be helpful for this lab
- Interrupts
- 8-bit
Timer2
- Analog
to Digital Converter
- Here is a reference on
bypassing, a technique to reduce noise in your circuit: http://www.seattlerobotics.org/encoder/jun97/basics.html.
- Even though the ATMega16 is
an 8-bit processor, an int is 16 bits.
- Debouncing a button is
essentially an averaging or smoothing of the input value. This is often referred to as low-pass
filtering because only the long-term variations (at low frequency)
are used (passed) and rapid changes (at high frequency) are
discarded. A good way to do this in
software is to sample a button several times and take the average or mode
(the most common value across all the samples – this is like voting for
Boolean values).
Resources
Lab
2 Schematic
Brief
introduction to AVR Programming
avr-gcc manual
Application
notes section for the AVR 8-bit RISC family
Suggested Steps
Section A: Introduction &
Tutorial
- The recommended program for
development for this class is Programmers’ Notepad. We have provided a sample project that will copy a constant from
program memory and displays it on PORTB. When the sample program is
uploaded to your breadboard an “8” should appear on the 7-segment display
attached to PORTB. If you would like more information on the makefile,
programmers notepad, and winAVR please refer to install_config_WinAVR.pdf . To make Programmers’ Notepad easy to use
for 466 the lab staff has added 3 useful commands to the tools menu:
·
“Tools -> Make
All” – build all the possible output files for the project
·
“Tools -> Make
Clean” – delete all output files from the project
·
“Tools ->
Program” – launch MegaLoad
- Go through the entire Oscilloscope Tutorial (consult the Oscilloscope Manual as needed)
- Add two buttons (pins 18
and 19), a potentiometer (pin 40), a LED (pin 21), a wire to Vcc (pin 32),
a photoresistor (pin 39) and bypass capacitors to complete the circuit
shown in the schematic
on your breadboard. Again, before powering your circuit back up, you
should confirm that you don't have any shorts between Vcc and ground with
the multimeter.
Question 1: What is
the appropriate range of values for the two button pull-up resistors? (Refer to
datasheet)
Question 2: What is
the purpose of the bypass capacitors? Why might they be useful for this lab?
Section B: Timer
PART 1:
- Rewrite the last lab in C.
Try to mimic the original behavior as much as possible since the idea is
to compare the code size of your hand-generated assembly to the code size
of what the compiled code generated by the C compiler. Use the
oscilloscope to confirm that your board is counting at or very close to
1Hz.
Question 3: Record the
code size of the two hex files (assembly and C). Both of these numbers will
show up in the compiler output. For the assembler, it is listed as
"Code" in the program memory usage. It is listed as ".text"
in the gcc output. Which one is larger?
PART 2:
- Reimplement the 1Hz counter
by eliminating the delay loop and replacing it with code that uses the
output compare interrupt from timer2 to do the timing. Documentation for
the avr-gcc compiler is available at http://www.nongnu.org/avr-libc/user-manual/index.html From that link, go to the modules
section and then the Interrupts and Signals entry. Remember, when writing
the interrupt handler routine, you'll want to minimize the amount of code
in it. Interrupt handlers are meant to be very fast, and do only the work
that is critical to do right at that instant. There is no way that anyone
will be able to notice if your LEDs update even a few milliseconds late, so
the LED update code should not be in the handler. Documentation on timer2
including all the related registers is available in the datasheet in the
course pak.
- Implement the stop-start
button so that pressing the button will cause the counter to toggle between
counting or halting. The left (tens digit) decimal point should indicate
whether the counter is running by being on when the counter is running and
off when the counter is stopped. It would probably be a good first step to
get the switch debounced (see the hint on debouncing). You can
either use timer0 for debouncing or figure out a way to use timer2 for
both the counting and debouncing. Remember that if you push the button and
hold it for a long time, it should still only register as a single push.
- Implement the up-down
button so pressing the button will change the direction of counting. The
decimal point on the right (ones digit) should be on when counting up and
be off when counting down. Note that even when the counter is stopped, the
system should still process an up-down button press by immediately
updating the direction and decimal point state.
Question 4: Why
debounce a button?
Section C: ADC Suggested Steps
PART 1:
- Create a hexadecimal display that can properly output
an 8-bit value on the two 7-segment LED displays that combine to make the
8-bit value (one 7-segment LED will represent the high 4-bit nibble and
other will represent the low 4-bit nibble). You should implement a lookup
table in program memory to convert a 4-bit nibble (in binary) to a
hexadecimal number. The hexadecimal letters should all be uppercase except
for the letters ‘b’ and ‘d’ which should be lowercase to avoid repeated
symbols. The easiest way to ensure that you can properly output all of the
8-bit values properly in hex is to create a simple hexadecimal counter
that counts from 00 to FF. (NOTE: Displaying an 8-bit value will be useful
this quarter as a debugging mechanism so the code will most likely be
reused.)
- Implement a program that continually displays the
analog value of the potentiometer on the two 7-segment LED displays. You
should read the section in the datasheet on the Analog to Digital
Converter to find out how to obtain the analog value. You'll want to use
the interrupts to tell you when the conversion is complete. Also note that
the ADC has 10-bit resolution but only 8-bits are needed for the display,
so you can throw away the 2 least significant bits. Note that the
datasheet describes a nice way to get the 8 most significant bits.
- Use a button to toggle between
the system displaying 8-bit analog values from the potentiometer or the
photoresistor. The two 7-segment displays should either show the 8-bit
value of the potentiometer (decimal points off) or photoresistor (decimal
points on).
Question 5: Does
brighter light or dimmer light give you a higher analog value? What is
happening to the resistance?
PART 2:
- Use the potentiometer and
photoresistor to create an adjustable light sensor that will turn lights
on when it becomes dark. The photoresistor will be used to monitor the
current light level of the surrounding environment. The potentiometer will
be used to adjust the level at which the sensor will trigger the lights to
come on. This will allow the user to customize their home so the lights
turn on and off at the desired darkness. Once the photoresistor reports
that the level of darkness specified by the potentiometer has been
reached, the ATmega16 should turn on the lights. (In this case the light
is an LED attached to pin 21.) Once it becomes light enough the ATmega16
should turn off the LED.
- To determine the voltage
difference between the potentiometer and photoresistor you should use an
ADC differential channel. The potentiometer should be the positive
differential input and the photoresistor should be the negative
differential input. The ADC will return a signed number (in two’s
complement) that represents the voltage difference between the two
differential input channels. The two 7-segment displays should display
this signed 8-bit value by using the tens digit decimal point to represent
the negative sign.
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
- If we want to lower the power consumption of our light sensor we may want to set a slower sample rate. We can lower CPU utilization by using a timer to
wake-up the processor to trigger an ADC sample. You can safely assume that
updating the light state (on or off) can take place a second after the
ambient light level has changed. This means that you should design your
system to sample at a reasonable rate so that it would be possible to use less
power.(NOTE: You are NOT required to put it into a low power or sleep mode). If you
sample approximately every 100-500 ms (depending on the amount of
smoothing) your system should still be sensitive to changing light
levels. For this lab you need to sample the ADC on the order of
milliseconds.
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 2, Section B, Part 1” for the counter that is a
rewrite of your assembly counter).
Answers to the Five Lab Questions.
Section B, Part 1:
- Turn in a hard copy of
your code
- It should count upwards
from 0 to 59 and start over at 0 after it reaches 59.
- The tens digit of the
current count value should be displayed on the left 7-segment display,
and the ones digit should be displayed on the right 7-segment display.
- The count rate should be 1
Hz.
Section B, Part 2:
- Demonstrate your counter
to a TA. You can either do this during this lab, or during the first 1/2
hour of the next lab.
- It should have a reasonable
user-interface. (i.e. make sure buttons are responsive but not overly
sensitive).
- Changing counting direction
should work properly and the decimal points should represent the current
state of the counter. The low decimal point should be lit when counting
upwards, and off when counting downwards. The high decimal point should
be lit when the counter is running and off when the counter is stopped.
The low decimal point should still change state even when counting is
stopped but the up-down button is pressed.
- Counting should happen at 1
Hz.
- Turn in hardcopy of your
commented C code.
- Make sure that your
interrupt handler is as minimal as possible. Points will be docked for
updating the displays inside of the interrupt handler.
Part C, Part 1:
- Demonstrate your light/potentiometer
reader to a TA. You can either do this during this lab, or during the
first 1/2 hour of the next lab.
- The display should be able
to range from very close to 0 when the pot is turned all the way one way
to very close to 0xff when the pot is turned the other way.
- The decimal point should
show whether the values being displayed are from the potentiometer or the
photoresistor.
- It should be
reasonably responsive to changes of the potentiometer or in the level of
light.
- Turn in hardcopy of your
commented C code.
Part C, Part 2:
- Demonstrate your light
sensor to a TA. You can either do this during this lab, or during the first
1/2 hour of the next lab.
- The decimal point should
show whether the value being displayed is positive or negative.
- The LED should not flicker
excessively and the readings should be somewhat stable when the
surrounding light is staying constant.
- Turn in hardcopy of your
commented C code.
- Should sample the ADC on
the order of milliseconds