EE109 – Fall 2022 Introduction to Embedded Systems

EE109 – Fall 2022: Introduction to Embedded Systems

Lab 6

Analog to Digital Conversion

Honor Statement

This is an individual assignment. The code you write, use for the demo and submit should be wholly your own and not produced by working in teams or using, in part or in whole, code written by someone else (found online, from a fellow student, acquaintance, etc.). You will be asked to verify this when you submit your code on Vocareum by signing your name in the honor.txt file on Vocareum. Penalties for violation include a 0 on the assignment and a potential further deduction or referral to Student Judicial Affairs.


In this lab exercise you will use the Arduino's analog-to-digital (ADC) conversion capability to interface the microcontroller to a variable resistor, also known as a "potentiometer", and also to the buttons on the LCD module. The goal is to be able to implement a very simple video game on the LCD using the potentiometer and the buttons as the player's control. Writing the program will involve learning how to configure the ADC module by setting various register bits, how to initiate a conversion and how to draw characters on the LCD screen based on the conversion results.

Recommended viewing: Video on analog-to-digital conversion

Recommended reading: Chapter 7 in "Make: AVR Programming" on Analog-to-Digital Conversion

For a copy of the Lab 6 grading sheet click here.

Getting Started

Set up your Lab 6 assignment the same way we have done previous in labs by making a lab6 folder in your ee109 folder. You can copy the Makefile, lcd.c and lcd.h from Lab 5 to the lab6 folder.

From the class website download the file "" and extract the contents into the lab6 folder. The Zip file contains four files:

In previous labs we put the routines for the LCD in a separate file, lcd.c, with the function definition in lcd.h. For using the ADC, we now want to do the same thing by having the ADC functions and definitions in the files adc.c and adc.h.

Make sure to update your Makefile to replace lab5.o with lab6.o, and also add adc.o to the OBJECTS line.

The ADC Module

Information on using the ADC module is available in a lecture slide set. A more in-depth review of this material is provided in a separate document "Using the Atmel ATmega328P Analog to Digital Conversion Module" available on the class web site. Refer to any of these resources for information on configuring the various registers in the module and how to do the conversions.

Task 1: Write the ADC routines

The adc.c files contains the template for two routines that you will have to write.

The adc_init routine must set up the proper values in the ADMUX and ADCSRA registers. Diagrams of the registers are provided on the Lab 6 grading rubric for you to fill in the values.

The adc_sample routine is called to acquire a sample of the analog signal from the ADC. The channel to sample is specified as an argument from 0 to 5 when calling the adc_sample routine. The adc_sample routine is declared as a "unsigned char" function and the return value contains the result of the conversion and can be saved in an unsigned char variable. For example, to acquire a sample from ADC channel 2 and put the value in the variable data, the code would be

    data = adc_sample(2);

The routine should do the following.

  1. Set/clear the MUX[3:0] bits in ADMUX to select the input channel as specified by the argument to the function. Hint: Use bit copying.
  2. Set the ADSC bit in the ADCSRA register to a 1. This starts the conversion process.
  3. Enter a loop that tests the ADSC bit each time through the loop and exits the loop when ADSC is 0. This indicates that the conversion is now complete.
  4. Copy the 8-bit conversion result from the ADCH register and return it to the calling program.

The LCD Buttons

The buttons on the LCD use the ADC to determine which, if any, are being pressed. This is different than how buttons in previous labs were interfaced to the Arduino. Rather than having all the LCD buttons produce an individual digital signal, all five of them are instead interfaced through a multistage voltage divider creating a single analog signal that can be measured by the ADC. Depending on which button was pressed, or none, this circuit produces a different voltage between 0 and 5 volts, and this signal is attached to the ADC Channel 0 input to the Arduino. By using the ADC to convert this voltage to a number it's easy to determine if one of the five buttons was pressed.

Task 2: Determine the LCD buttons value

When a button is pressed the analog voltage on ADC channel 0 changes to a unique value that identifies the button that was pressed. However in order for your program to determine which button was pressed you have to know what the ADC output is for each button. The easiest way to do that is to write code to loop continuously reading the ADC result and writing the value to the LCD.

Use the ADC routines you just wrote to give the program the ability to use the ADC to read the button's analog signal. In the while(1) loop of the main routine add code to do the following.

  1. Call adc_sample with an argument of zero to read the value of the ADC channel 0 and store the returned value in a variable.
  2. Use the snprintf routine to format the ADC result into a string of numerical characters that can be displayed. (e.g. something like snprintf(buf, 5, "%4d", adc_result);
  3. Use your lcd_moveto function to move the cursor to the first character position on the first row.
  4. Use your lcd_stringout function to print the string on the display

Once the program is running, try pressing each button and see what value is displayed. You can record the values shown for each of the buttons on the Lab 6 grading sheet. These values will be used in later tasks. You should note that the ADC conversion results may not always be exactly the same each time a button is pressed. Due to electrical noise and thermal effects it may return, for example, 124 one time, 125 another and 126 yet another time. Your code must take this into account when working with the ADC results.

The Variable Resistor

For this lab assignment one of the inputs to the ADC of the Arduino will come from a variable resistor or potentiometer (or "pot" for short) hooked up to be a voltage divider. A potentiometer as shown below is a three-terminal device that has a fixed resistance between two of its wires and a third wire, sometimes called the "slider" that can be adjusted to give anywhere from zero to the full resistance between the slider wire and the other two. In short, the potentiometer operates as a voltage divider (two resistors in series) where the resistance in the numerator can be adjusted by dialing/spinning the "pot". Turn it fully one direction and you will see 0V on pin 2. Turn it fully in the other direction and you will see VS (5V) on pin 2. At any position in between you should the voltage on pin 2 scale linearly.

In schematic diagram above of a potentiometer, the total resistance between the top and bottom terminals of the potentiometer is given by R. Internally R can be viewed as two resistors R1 and R-R1 and in series so the resistance between the top and bottom terminals is fixed at R. Changing the position of the potentiometer's control changes the resistance of R1. Since the value of R is fixed, as R1 increases, R-R1 must decrease by an equal amount, and similarly if R1 goes down R-R1 must go up.

When hooked up as a voltage divider as above, we can see that V is given by

As the position of the slider is adjusted the value of R1 can change from R (making V=VS) to zero (making V=0). By adjusting the slider we can get any voltage from 0 to V=VS to appear on the slider terminal that will be connected to the ADC input.

Get the potentiometer from the parts provided in your kit and examine it. The resistance between the two fixed terminals (R in the above) is marked on the top next to the round control that is rotated. It should say "102" which is the resistance in the same format as used for marking fixed resistors: 1, 0, and two more zeros = 1000Ω.

The Circuit

The circuit is shown below. Note +5V and ground to the potentiometer are connected to your Arduino board's 5V and GND connectors.

On the potentiometer, the two pins that are on a line parallel to the sides of the device correspond to the top and bottom pins as shown above. The slider pin is the one offset from the other two.

To confirm that you have it connected properly, use the multimeter to check that the voltage on the slider pin can be changed by rotating the control.

Task 3: Check potentiometer and ADC routines

Before trying to use the potentiometer in the next part of this lab we recommend you check to see if it and the ADC routines are working. Your lab6.c file should still have the code to read the ADC value on channel 0 for the buttons. Change the channel number in the adc_sample function call to use channel 3 where the potentiometer is connected. Flash the new code to your Arduino, and then try rotating the potentiometer back and forth. The program should be displaying the numerical values of its conversions of the voltage on channel3, and these should be close to 0 at one end of the rotation and close to 255 at the other. If you are not seeing this, you will need to fix the problem before using the potentiometer and ADC code in the next task.

Task 4: Write the game

The game you are constructing works in the following manner.

  1. When your program starts it draws an 'X' character at a random position on the first row of the LCD.
  2. The 'X' character can be moved left or right by pressing the corresponding buttons on the LCD. Each time one of these buttons is pressed, the 'X' should move one column but stop when it hits the left or right side of the display.
  3. The position of the potentiometer determines the position of a caret '^' character on the second row. As the potentiometer is turned between the limits of its travel, the '^' should move back and forth between column 0 and column 15 of the second row.
  4. When the '^' is positioned under the 'X', and left there for two seconds, a message is printed on the screen saying you won the game.
  5. Once the game has been won, the program can just loop continuously doing nothing. It does not have to go back and start a new game.

To see a short video demonstrating the operation of game, click here.

At the start of the game the program should do the following.

Once the above steps have been done the program should enter an infinite loop for the playing of the game. Each time through the loop the following should be done.


When your program is running you should be able to

Once you have the assignment working demonstrate it to one of the instructors. The answers to the review questions below should be edited into the Lab6_Answers.txt file. The Lab6_Answers.txt file and all source code (lab6.c, lcd.c, lcd.h, adc.c, adc.h and Makefile) must be uploaded to the Vocareum web site by the due date. See the Assignments page of the class web site for a link for uploading.

Please make sure to save all the parts used in this lab in your project box. These will be needed for labs throughout the rest of the semester. We suggest also saving all the pieces of wire you cut and stripped since those will be useful in later labs.

Review Questions

Answer the following questions and submit them in a separate text file ("Lab6_Answers.txt") along with your source code.

  1. Review the conceptual operation of an ADC and use the given parameters to find the desired value.
    1. Your 8-bit ADC has Lo and Hi reference voltages of 1V and 4V, what digital number would result from sampling a 2.0V?
    2. Your 5-bit ADC has Lo and Hi reference voltages of 0V and 5V, what input voltage would yield a digital number of 12?
    3. Your 6-bit ADC has a Lo reference voltages of 2V. A voltage is sampled at 2.4V and the digital result is 26. What was the Hi reference voltage used by the ADC?
  2. We want you to feel comfortable reading documentation to understand the operation of a device. To that end, open the ATmega328/P datasheet linked on our website from the Tools and Links Page and go to chapter 24 regarding the ADC. In our current lab, the ADC only takes samples when commanded through the ADSC bit in the ADCSRA register. However, the ADC can be configured to take continuous samples based on some other triggering source. Read over the register bit descriptions of the ADCSRA register (especially bit 5 = ADATE) and the ADCSRB register (especially bits ADTS[2:0]) described in sections 24.9.2 and 24.9.4, respectively. In addition, in section 24.4, directly above Figure 24-4 is the text:

    "In Free Running mode, a new conversion will be started immediately after the conversion completes, while ADSC remains high."

    Now consider what effect setting the ADATE bit of ADCSRA to a 1 will have, assuming you don't modify ADCSRB from its default reset value. Briefly describe what the ADC module will do.