CSEP567 Lab 4: “LCD and ADC”
Objectives
The goal of this lab is to introduce how to program the microcontroller using C.
In this lab you will learn the following:
-
how to use a port for multiple purposes;
-
how to use the stdio functionality of avr-libc;
-
how to use the A/D converter and its interrupt features.
This lab assignment has 2 required sections and 1 optional section.
Suggested Reading
LCD Information
The LCD which you will be using has many advanced functions
(see the datasheet for a complete explanation), but you
will only be concerned with the following two:
-
Reset and clear the display.
-
Write characters to the display.
We are
using a LCD with a display area of 2 rows by 16 columns which gives a total of
32 characters that can be displayed at once.
The pin layout of the LCD follows:
Pin
|
Name
|
Function
|
1
|
GND
|
0 V
|
2
|
Vdd
|
5 V
|
3
|
Vo
|
1 V
|
4
|
RS
|
High: Data input
Low: Instruction input
|
5
|
R/W
|
High: Read from LCD
Low: Write to LCD
|
6
|
E
|
Enable the LCD
|
7
|
DB0
|
Data bus
|
8
|
DB1
|
9
|
DB2
|
10
|
DB3
|
11
|
DB4
|
12
|
DB5
|
13
|
DB6
|
14
|
DB7
|
Pins 1-3 are power supply connections and will be explained
later. Pins 4-14 are signals that you must supply. R/W specifies whether
you are reading or writing the display: Since you will only be writing to the
display, the R/W signal will always be 0. RS is used to determine whether you
are sending a command or ASCII data to the display. E (enable) is used to
provide a strobe that causes the operation to be executed. The enable E
is really a clock signal for the LCD that you must generate: the LCD
reads the signals being placed on its pins and commits a new
character or command on the negative edge of E. (NOTE: negative edge means
the signal is changing from 1 to 0, or Vcc to gnd) The data pins contain
either an ASCII character code or a command code depending upon the value of
RS. In Lab you will need to multiplex this data bus between the signals meant
for the LCD and signals meant for the 7-segment LED.
The following is a table with the codes for 5 of the
commands that you need to execute for this assignment. The first four should be
called in an intialization routine and executed in sequence on reset. Please
check the datasheet for the timings needed. The
last command is used to write a character to the display. You can look at the
documentation (see the datasheet) if you would like to
try out other commands.
Operation
|
RS
|
DB[7:0]
|
Clear Display
|
0
|
0000
0001
|
Function Set
|
0
|
0011
1000
|
Display On
|
0
|
0000
1100
|
Entry Mode Set
|
0
|
0000
0110
|
Write Character
|
1
|
DDDD
DDDD
|
Suggested Steps
Section I. LCD
-
Connect the LCD according to this schematic.
Note that the LCD pins connect directly to the processor PORTC pins, not on the
other side of the resistors. You will need to calculate what resistors you
will need to generate 1V.
-
Verify that everything is hooked up properly by using your two
functions from the prelab to initialize and
print characters to the LCD screen.
-
Next, include <stdio.h> in your code and near the top of main
add the following line of code: "fdevopen(lcd_putchar, NULL, 0);"
This will cause stdout to be directed to the lcd_putchar function (from prelab)
allowing printf's output to be directed to your LCD screen.
-
Modify your code so that it multiplexs PORTC between the LCD screen
and the 7-segment LED. To accomplish this take advantage of the
fact that the LCD screen will only read input on the negative edge of E. By
placing the needed data on PORTC for only a fraction of second and
then restoring the 7-segment LED data as soon as it's done sending
you should be able to use PORTC to control both devices. There might be a small
amount of flicker but by executing the LCD commands quickly it should
be miminal. NOTE: You need to be careful that another section of code does
not update PORTC values when the LCD functions are sending data on PORTC. (Ask
a member of the course staff if you are confused on how to multiplex)
Before moving to Section II demonstrate to a TA that the LCD screen is
working. The LCD will hopefully provide a useful debugging tool for the rest of
the labs that use the prototyping board.
Section II.
ADC
-
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. To increase accuracy use a large prescaler. 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.
Question 1:
Does brighter light or dimmer light give you a higher analog value? What is
happening to the resistance?
-
Use a button to toggle between the system displaying 8-bit analog values from
the potentiometer or the photoresistor.
-
Demonstrate that your multiplexing of PORTC is working correctly by recording
the value of the ADC every 10 seconds. Each line should display
either "Light: %d\n" or "Pot: %d\n" (depending
on which ADC is being read) and be followed by
a new line to demonstrate your wrapping. NOTE: The 7-segment LEDs should
be constantly updating.
Demonstrate Section II to a TA
(see delieverables section).
Section
III. Light Sensor (Optional, for fame and glory... no credit
involved)
-
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
Deliverables
For all files turned in, the comments at the top of the file
should contain:
-
Both partners' full name and login.
-
The lab number and the part of the lab (e.g. “Lab 4, Section 2”) for the LCD
and ADC
-
Demonstrate your light/potentiometer reader to a TA. Remember your code should
do the following
-
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 LCD screen 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.
-
Your code should track the position the next character will be displayed on the
LCD (2 rows, 16 columns) and automatically move the cursor as needed to the
beginning/home position of the next line. When reaching the end of the second
LCD line it should wrap to the beginning of the first line of the
LCD. (NOTE: That if you do not move the cursor the LCD will type off the
screen and you won't be able to see the text.)
-
Your code should recognize '\n' and move the cursor the the
appropriate line (wrapping).
-
Your code should clear each line before writting to it.
-
Turn in hardcopy of your commented C code and your answer to question 1.