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 4 required sections. 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: Interrupts in Assembly
1. Implement
your “One Minute Counter” from Lab 1 (in assembly) using a timer interrupt to control counting rate instead of a delay loop. (GRADED DEMO DUE THIS WEEK)
Section B: Introduction &
Tutorial
1. Add
additional hardware to your breadboard
2. Complete
the Oscilloscope tutorial
3. Complete
the JTAG debugger tutorial.
Section C: Interrupt Timer in C
1. Reimplement the counter in C. In addition, the counter should also be able
to start, stop, and change direction based on the two added buttons. (GRADED DEMO)
Section D: 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)
Suggested Reading / Helpful Hints
- The
following sections of the ATmega16 datasheet might be helpful for this lab
(listed in table of contents).
- Interrupts
- 8-bit
Timer2
- Analog
to Digital Converter
- Here is a reference on
bypass capacitors, which are used 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 – located at:
C:\WinAVR\doc\avr-libc\avr-libc-user-manual-1.4.4.pdf
Application
notes section for the AVR 8-bit RISC family
Suggested Steps
Section A: Interrupts in
Assembly
- 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 on the interrupt jump
table and interrupt handlers can be found in the datasheet. 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.
Question 1: Why do the
Reset handler jump and Timer 2 interrupt handler jump need to be located at a
specific address?
Section B: Introduction &
Tutorial
- Add two buttons (pins 28 and
29), a potentiometer (pin 40), a LED (sharing pin 29 with one of the
buttons), a wire to Vcc (pin 32), a photoresistor (pin 39) and bypass capacitors to
complete the circuit shown in the schematic
on your breadboard. Make sure not
to forget the current-limiting resistor for the new LED, and pull-up
resistors for the two buttons. Pay
special attention to how the new LED is wired. It shares a pin with one of the
buttons. We can use this pin for both
button-sensing and driving the LED by controlling whether the pin is an
input or an output. 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 2: What is the
appropriate range of values for the two button pull-up resistors? (Refer to
datasheet)
Question 3: What is
the purpose of the bypass capacitors? Why might they be useful for this lab?
- Go through the entire Oscilloscope Tutorial (consult the Oscilloscope Manual as needed).
Section C: Interrupt Timer in
C
- The recommended program for
development for this class AVR
Studio. 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.
- Rewrite your interrupt timer
using C. Documentation for the avr-gcc compiler is available at
C:\WinAVR\doc\avr-libc\avr-libc-user-manual-1.4.4.pdf. From that link, go
to the modules section and then the Interrupts and Signals entry. You will be using the same interrupts as
before.
- 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 D: ADC Suggested Steps
PART 1:
- Read all of the directions for Part 1 before doing
ANYTHING. Often the next step reveals why the current one is
important.
- 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. (Hint: Displaying an 8-bit value will be useful
this quarter as a debugging mechanism so the code will most likely be
reused. i.e. it might be helpful if you write a function that takes an int from 0-255 as input and displays 00-ff on the LED displays.)
- 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 the button on pin 28 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:
- Read all of the directions for Part 2 before doing
ANYTHING. Often the next step reveals why the current one is
important.
- 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 29.) 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
Note: The atmega chip does not have hardware to handle floating point
numbers. DO NOT USE THEM.
- 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
Submit the files through Catalyst Tools at:
·
AA
section
·
AB
section
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 A, Part 1” for your assembly interrupt
counter).
Answers to the Five Lab Questions.
Section A:
- Turn in a soft copy of
your commented assembly code. You need to demo this during your lab
section.
- Your counter should be
functionally equivalent to the lab 1 final counter.
Section C:
- 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 soft copy 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.
Section D, 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 soft copy of
your commented C code.
Section D, 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 soft copy of
your commented C code.
- Should sample the ADC on the order of milliseconds