Link Search Menu Expand Document

Sensors, Actuators, and I/O

Prelab due 9/18/22 at 11:00 am

Writeup due 9/25/22 at 11:00 am

About

In this lab, you will continue to get experience wiring circuits and writing Arduino code. This lab introduces the analogWrite and analogRead functions and has you explore how to use them with multiple different input and output devices in your kit. By the end of this lab, you should have a deeper understanding of how to manipulate and read voltages in embedded circuits, by use of pulse-width modulation (PWM), Analog to Digital Converters (ADCs), Digital to Analog Converters (DACs), and voltage divider circuits.

Lab 2 Rubric

Resources

Materials

Included in your kits:

  • Arduino MKR 1000 and USB cable
  • Breadboard
  • 2 LEDs (recommended red)
  • 3 resistors (3: 1kΩ)
  • 1 capacitor (100 μF)
  • 1 RBG LED
  • 1 potentiometer
  • Jumpers/wires

Provided:

  • None necessary

Steps

Note: during the course of this lab, you will make one graph that you will be asked to discuss in your lab document. We suggest making and saving this graph in a Google sheet, shared with you and your partner (if you have one), so that you can reference it later.

For these and the following labs, we do not show ground explicitly connected to the GND pin of the Arduino, to make the diagrams less cluttered. You should ALWAYS connected the GND pin of the Arduino to the ground rails of the breadboard, as described in Lab 1.

  1. Build a circuit to explore a visual representation of PWM:

    1. Recall from class that PWM is a way to simulate analog (continuous) output using a digital signal. The duty cycle of a PWM signal can vary from 0% (always off) to 100% (always on):

      PWM duty cycle

      (image from Wikipedia)

      Discuss with your partner (or think to yourself) about what you expect to happen to an LED driven by a 50% duty cycle signal.

    2. On your breadboard, build the following circuit. We recommend using a red LED for brightness/visibility:

      Lab02Circuit01

    3. In the pre-lab, you read about analogWrite(…). Read the following code and make sure you understand what it does by discussing it with your partner:

      /*
      * Opens serial communication between the MKR1000 and the computer
      * Takes in a number 0-255 from the serial monitor and sets the output PWM duty cycle on LED_PIN to that number
      */
      
      int LED_PIN = 4;
      
      void setup() {
         Serial.begin(9600);
         while (!Serial); // Wait for Serial to initialize
         Serial.println("Ready!");
         analogWrite(LED_PIN, 0);
      }
      
      void loop() {
         if (Serial.available() > 0) {
            int input_pwm = Serial.parseInt();
            Serial.parseInt(); // Ignore null character
            if (input_pwm < 0 or input_pwm > 255) {
               Serial.println("Input out of range; ignoring");
            } else {
               Serial.print("Received input of ");
               Serial.println(input_pwm);
               analogWrite(LED_PIN, input_pwm);
            }
         }
      }
      
    4. Copy the code into a new Arduino sketch. Open the Serial Monitor and then upload the sketch to the Arduino.

    5. Play around sending different values through the serial monitor. What happens to the LED? Does it match your intuition? Can you give a concrete explanation, based on the Arduino PWM frequency listed in the documentation you read, and on the frequency at which the human eye perceives?

  2. To see numerical evidence to back up your intuition, and to explore analogRead(...), we will use a capacitor to smooth a PWM signal.

    1. Think about how you would measure the average voltage output by a PWM pin. One way is to use digitalRead(...) and average a sample of the results. This might lead to different or even incorrect results based on the sampling frequency, which depends on multiple factors, including how long the digitalRead(...) takes and how long any computation takes between samples. Imagine if the sampling frequency happened to be the same as the PWM frequency. Then, we would sample the same point of the PWM curve every time, and always measure the same voltage, which would not give us the correct average:

      Sampling

      Instead, we will use a circuit component to do some averaging for us.

    2. Construct the following circuit:

      Lab02Circuit02

      Make sure you use the correct capacitor (helpfully, it has the capacitance printed right on the body), and pay attention to its polarity! The anode (positive side) has a longer leg.

    3. A capacitor stores electric energy – a little like a rechargeable battery. When it receives a voltage, it gradually charges up, and when the voltage source is gone, it gradually discharges. For a PWM circuit, that charging and discharging lead to a voltage across the capacitor that resembles the red line here:

      Capacitor

      Hence, given enough PWM cycles, the voltage across the capacitor will settle to a small error around the average voltage of the PWM signal. No matter at which point in the cycle you happen to sample the voltage, across the capacitor, it will be close enough to the average voltage of the PWM cycle (for our measurement purposes).

    4. Write some Arduino code to measure the voltage across the capacitor, by calling analogRead(…) on pin A1. Your code should set the output of pin 4 to a variable representing a PWM duty cycle from 0-255, wait a fraction of a second, and read the voltage on pin A1.

      Note that the analogRead(...) outputs a number from 0 to 1023 (resolution of 10 bits for the MKR1000), so your code will have to use the formula you came up with in the prelab to convert this value to a voltage between 0 and 3.3V.

      Your code should change the PWM duty cycle on pin 4 from 0 to 255 by increments of 5, and use Serial.print(...) and Serial.println(...) to print comma-separated values of duty cycle and capacitor voltage (see the code in step 1c for an example of how to set up serial and how to print multiple strings to the same line). For example, the first line will likely read 0, 0.0.

    5. Run this program on the Arduino and copy the serial output to a spreadsheet. On Google sheets, you can paste comma-separated lists into a single column and then click the clipboard at the bottom-right of the pasted selection and select “Split text to columns.” Graph the curve of PWM duty cycle vs. voltage across the capacitor. Is this the result you expect? Why or why not?

      Get your graph checked off by a TA.

  3. While, in some ways, PWM approximates a continuous (analog) output signal, it is important to understand the difference between a PWM output and an analog output. Construct some circuits to see the difference between the two in practice:

    1. First, construct the circuit below. We suggest red LEDs for brightness/visibility:

      Lab02Circuit03

    2. Using analogWriteResolution(…), set the analog write resolution of the Arduino to 8 bits. This will make things consistent with the DAC pin we will use in the next step. Write some Arduino code to drive each of the LEDs with a PWM with 50% duty cycle (input of 127 to analogWrite(...))

    3. Upload your code to the Arduino. You should observe both LEDs glowing at the same, half-dim brightness. If this doesn’t happen, your LEDs might be deficient, or you are calling pinMode(...) before calling analogWrite(...), which you shouldn’t do.

    4. Unplug the Arduino and change the pin driving one of the LEDs to the DAC/A0 pin:

      Lab02Circuit04

      This pin has a Digital to Analog Converter, which means that analogWrite(...) outputs a desired voltage between 0V and 3.3V, instead of a PWM signal.

    5. Update your code from step 3b to drive the LED with the A0 pin, at half-voltage (input of 127 to analogWrite(...)). Except for changing the pin number, nothing else about your code should change.

    6. Upload your code to the Arduino. What do you observe? Why do you think this happened? Discuss it with your partner or ask a TA for a hint. You will be asked to answer this question in your own words for the lab writeup.

  4. One of the powerful things about microcontrollers is that you can write code that makes the output of some components respond to the input of other components. This provides more flexibility and functionality than hooking up the components directly in a circuit. You’ve already done a basic version of this in Lab 1, where you read a button input and controlled some LEDs. Now, you will use a potentiometer to controll an RBG LED, which will involve some slightly more complicated code.

    1. You will be using a potentiometer for this step. To understand how a potentiometer works, first recall this voltage divider circuit from the prelab (you do not have to connect this circuit):

      Lab02Circuit05

      In the prelab, you defined a formula for the voltage at the point ?? V in terms of R1 and R2. Hence, by choosing values of R1 and R2, this circuit can be used to divide the supply voltage to whatever lower value you want. Because R1 and R2 are fixed for any specific circuit, however, this divided voltage will also be fixed.

      A potentiometer works on the same principle. While different potentiometers work in different ways, conceptually, you can imagine it internally changing the values of R1 and R2 as its dial is turned. This means that, a potentiometer can be set to output any voltages in between 0 and its supply voltage while the circuit is on.

    2. Armed with this knowledge, you can work with the following circuit. Construct it on your breadboard:

      Lab02Circuit06

      The potentiometer symbol, fittingly, looks like a resistor with an arrow pointing to it, to symbolize the variable internal resistance ratios. Your potentiometer looks like a blue square with two legs on one side and one leg on the other. If you are using the old kit, some assembly may be required – the knobs for those potentiometers are in a separate bag in the kit, and look like small black or white plastic rods. Firmly insert one of them into the body of the potentiometer to assemble it. The potentiometers are not polarized, meaning that, for the two legs on the same side, you can choose one to connect to ground and then connect the other to VCC. Be sure to use VCC, not 5V!! The leg on the side by itself should get connected to the analog pin of the Arduino.

      Instead of using three separate LEDs in this circuit, use your RBG LED. It looks like a white LED with four legs. Yours are common cathode, which means that the cathode (longest leg) should be connected to ground. The other four legs control the red, blue, and green outputs of the LED and should each be connected to a different resistor and Arduino pin.

    3. Write some code that changes your LED from blue, to purple, to red, to yellow, to green, to teal, back to blue as you turn the potentiometer (where you start and end this cycle doesn’t matter, as long as the whole progression is there in order). Use analogRead(...) to read in the values of the potentiometer, and use analogWrite(...) to send a PWM signal to each channel on the LED.

      Lab02RGBgraph

      The graph above is an approximation of what the pin output for each leg of the LED should look like as the potentiometer changes in value. One channel of the LED should be off at all times, and the duty cycles of the other two should sum to 255 to maintain a constant brightness. For example, when changing from blue to red, the green LED will be off, and the duty cycles of blue and red will change from B=255, R=0 for completely blue, to B=127, R=128 for purple, to B=0, R=255 for completely red, with intermediate values computed to make a smooth transition. Talk through how you will write this code with your partner, and ask your TA for a hint if needed. Hint: you read about the map function in the prelab. Since you’re reading and writing integers, it may be useful to use this function to cut down on the amount of math you have to do.

    4. Upload and run your code on the Arduino. Debug your circuit and code. Hint: if one or more colors of the RBG LED don’t seem to be working, verify that your LED is functional by writing code that turns each one on individually (writing a PWM duty cycle of 255 to one pin and 0 to the other two). When you’re confident that it works, get it checked off by a TA. You now know how to use analogRead(...) and analogWrite(...) to interact with input and output components using code!

  5. Turn in your work:

    1. Save your code from steps 2d and 4c and name them 2d.ino and 4c.ino. Upload this to the “Lab 2 Code” assignment on Gradescope (include all partner(s) on the submission).

    2. INDIVIDUALLY, complete the Lab 2 writeup assignment on Gradescope.