CSE466-03au Lab Assignment 3 Revised 10/17/03 10:30 p.m.
See Revision to Part Four HERE.
Objectives
This is a 4 part lab. In it, you will:
- Reimplement your counter from the last lab, but this time
implement it in C instead of in assembler. Compare the word sizes of
your two versions and put the results in comments at the top of your C
file.
- Reimplement the counter, but this time, instead of using a delay
loop, use a timer interrupt to control the rate of count instead. The
counter should also be able to start, stop, and change direction based
on the buttons connected to pins 20 and 21. The left (high) decimal
point should indicate whether the counter is running, and the right one
should indicate whether the counter is counting up or down. Note that
even when stopped, it should be able to switch between counting up and
counting down.
- Read the analog value coming from the potentiometer and output
the most significant 8-bits to the leds.
- Read the analog value coming from the photoresistor. The values
may not swing all the way from 0 to 0xff, but you will calibrate it
based on a very bright light source, and a very dark light source to
make the output on the displays swing from 0.2 to 50, matching the
Weston light meter supplied as a reference. One of your buttons should
toggle between the raw ADC output displayed in hex (8 msbs), and the
calibrated engineering units corresponding to the Weston light meter.
The other button should allow you to start and stop the adc reading so
that you can see just a snapshot of the adc values. The Weston light
meter is kept in the lab office, on the bench.
In this lab you will learn the following:
- how to program a timer interrupt
- how to debounce a button in software
- how to use the A/D converter including using the A/D complete
interrupt
- how to scale data without using floating point math
Steps
- Rewrite the last lab in C. Try to mimic the behavior as much as
possible since the idea is to compare the code size of your compiled
assembly to the code size of what the C compiler generates. Confirm it
works on your board, and then record the code size of the two hex files
in the comments at the top of your C file. Both of these numbers will
show up in the compiler output. For the assembler, it's listed as "Code"
in the program memory usage. It's listed as ".text" in the gcc output.
End of part 1
- If you haven't already done so, , add the pot, photoresistor and
buttons 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.
- Dump the loop delay routine and replace it with interrupts from
timer0. Documentation on writing an interrupt handler is available at
http://savannah.nongnu.org/download/avr-libc/doc/avr-libc-user-manual/.
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's critical to do right
that microsecond. There is no way that anyone will be able to notice if
your led updates even a few milliseconds late, so the led update code
should not be in the handler. The code for the example setup only has a
single line in the handler that compiles to 3 assembly instructions
(no, it's not a function call). Documentation on timer0 including all
the related registers is available in the datasheet (coursepak).
- Write code so that pressing the stop-start button halts and
resumes counting. It would probably be a good first step to just get the
switch debounced (see the hint on debouncing) and get it to turn
the decimal point on the high display on and off. You can either use
timer2 for debouncing or figure out a way to use timer0 for both the
count 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.
- Write code so that pressing the up-down button changes the
direction of counting. The decimal point on the low display should be
lit when counting upwards. Note that even when the count is stopped, the
system should respond to up-down button presses and the decimal point
should still update.
End of part 2
- Write the code to read the analog value from the potentiometer.
This will require reading the section in the datasheet on the A/D
converter. You'll want to use the interrupts to tell you when the
conversion is complete. Also note that the A/D has 10-bit resolution,
but you only need 8 for the display, so you can just throw away the 2
least significant bits. Note that there's a nice way to do this shown in
the datasheet.
End of part 3
See Revision to Part Four HERE.
- Read all 10-bits from the photoresistor, but since you only have
2 hex displays, still output just the 8 most significant bits to the
display. At this point, you'll want to figure out whether brighter light
or dimmer light gives you a higher analog value.
- Add a display routine that uses the calibration values so that
when you calibrate it with a bright light, and darkness, and then shine
a medium light on it, it should register 0.2 and 50 (in decimal),
calibrated to the Weston light meter we have supplied. This will require
you to use the bright and dark values as endpoints and interpolate
between them for intermediate values, showing 2 significant digits. See
the hint on interpolating. You must convert your values to engineering
units of "light" as measured by the Weston meter. The meter works on a
logarithmic scale, as opposed to the linear scale output by the ADC.
For a discussion of the Weston meter's dial, see http://www.johndesq.com/pinhole/westonscales.htm
. The meter is calibrated in foot-Lamberts.
End of part 4
Helpful Hints
- Even though the ATMega16 is an 8-bit processor, an int is 16
bits.
- Debouncing a button is essentially low-pass filetering the value
of a button. In an analog circuit, you'd just add a low-pass filter to a
button's signal to debounce it. In software, a good approximation of a
low-pass filter is to take a number of samples and average them.
- When interpolating, you usually will use floating point
arithmetic to calculate your intermediate values. Unfortunately, we
don't have any hardware support on this chip for floating point
operations. gcc does provide software emulation of floating point, but
it's extremely inefficient on this chip (1000+ cycles for a 16-bit
divide). Because of this, you are not allowed to use floating point on
this assignment. However, you can use fixed point arithmetic. Since the
numbers coming off of the A/D are going to be 10 bit, and you've got
16-bit integers, you can left shift your value by up to 6 and get up to
6 bits of fractional precision. Remember that the Weston meter works on
a logarithmic scale, as opposed to the linear scale output by the ADC. A
look-up table might be a good idea here. You'll need more precision on
one end of the scale than on the other.
- Many of you have experienced erratic behavior of your circuit
because of noise. Here is a reference on bypassing, a technique to
reduce noise in your circuit: http://www.glencoe.com/ps/ee/williamson/bypass.html.This is required reading. Use the
suggestions here in your circuit.
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, part1 for the
counter that is a rewrite of your assembly counter).
- Any extra calculations or data that we've asked for.
Part 1:
- Turn in a hard copy of your code
- It should count upwards from 0 to 0xff and start over at 0x00
after it reaches 0xff.
- The high nibble of the current count value should be
displayed as a hex digit on the left 7-segment display, and the low
nibble should display as a hex digit on the right 7-segment display.
- The rate of count should be between 0.5 and 2 Hz.
- You should have the word count of both this program and your
assembly in the comments at the top.
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 reasonble user-interface. Ie. make sure
buttons are responsive but not overly sensitive.
- The low decmial 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.
- Changing counting direction should work properly, Ie it can't
continue counting for one number in the wrong direction.
- Counting should happen at a leisurely pace (between 0.5 and 2
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 3:
- Demonstrate your 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.
- It should be reasonably responsive to changes of the
potentiometer.
Part 4:
- Demonstrate your light meter to a TA.
- The user should be able to toggle between a free running mode
in which the display updates as soon as there is a new value sampled
from the A/D, and a freeze mode in which the displays remain at the
most recent sampled value before the freeze mode was entered. The
photoresistor is probably going to be pretty noisy, so it may jump
around a lot in the free running mode. When you freeze it, it should
stop jumping around so you can read a value off of it.
- The user should be able to toggle between raw hex values
output by the ADC and the calibrated values that match the Weston meter.
These will be on the slope of the low range of the Weston meter, which
goes between 0.2 and 50 units.
- It should not roll over (overflow) when it saturates. We will
test your meter by matching it to the Weston meter with different light
sources.
2.Turn in a hardcopy of your C code
- Do not use floating point arithmetic anywhere in your code
- Keep your interrupt handlers small.