Lab4_JoseOchoa


 

Assignment

  1. Resistance Varying Sensors:

  2. Voltage Varying Sensors:

  3. Count-based Sensors

  4. Create a data logger

  5. Upload your report as a wiki page to your student folder, and when you are ready to turn it in, only move the report wiki page to the 'Inbox' folder. Your images will remain embedded in the page.

 

In The Report

 

Part A. Resistance Varying Sensors

1. Potentiometer

Set up the LED output and potentiometer input circuits from the following schematic on your breadboard. Don't forget that there's a big difference between "analog pin 0" and "pin 0." This setup is much like lab 2's LED fade, except now we're using analogRead to control the fade.

 

 

 

                    

 

Try the code in File->Examples->Analog->AnalogInput.

Change the code so that the LED fades and brightens with the analog value of the potentiometer, like a dimmer.

Post a copy of your new code in your lab writeup.

 

int sensorPin = A0; // select the input pin for the potentiometer

int ledPin = 9; // select the pin for the LED

int sensorValue = 0; // variable to store the value coming from the sensor

 

void setup() {

// declare the ledPin as an OUTPUT:

     pinMode(ledPin, OUTPUT);

}

 

void loop() {

// read the value from the sensor (0 - 1024)):

// divide because we need range from 0 - 255

sensorValue = analogRead(sensorPin)/4;

 

// turn the ledPin on

analogWrite(ledPin, sensorValue)

}

 

 

 

 

2. Writing to the Serial Monitor

Use the code from File->Examples->Communication->Graph as a template to print data from your potentiometer to the serial monitor.

a. Based on the readings from the serial monitor, what is the range of the analog values being read?

According to the serial monitor, the digital values being read back span from 0 to 1023. Since that is the case, this potentiometer's output goes from 0 to +5V.

 

 

b. How many bits of resolution does the analog to digital converter (ADC) on the Atmega32U4 have [hint: where might you look to find this sort of thing]? How many are you using with the range of values you're seeing?

According to the AVR atmega32U4 datasheet, the ADC provides 10 bits of resolution. That is precisely what the serial monitor readings show.

  Great that you read the datasheet :)

 

3. Flex Sensor

The Flex sensor changes resistance between 8k-10k Ohms (straight) and 20k-50k Ohms (bent). The datasheet is here -- note that the datasheet states they should be 10k Ohms straight and 60-110k Ohms while bent ±30%. We'll build a voltage divider circuit with a 22k resistor, using the Flex sensor with the fading LED/potentiometer code from the last exercise:

 

 

a. What resistance do you see with a Multimeter when the sensor is flat? When it is bent?

When he sensor is flat, it measures at 14k. When the sensor is extremely bent, it measured as much as 82k.

 

b. What kind of voltages should we expect for the Teensy analog pin based on the sensor resistance?

At 14k, the voltage at A0 will be about 3V. At the other end of the extreme (82k), the voltage at A0 will be about 1V.

 

c. How does the range of the LED's brightness change compared to the potentiometer?

Compared to the potentiometer, the LED will not glow as bright and it won't dim as much either.

 

Change the LED fading code values so that you get the full range of output voltages from using your Flex sensor.

d. Include a copy of your Lowly Multimeter code in your lab write-up.

/*

Lowly Multimeter

Demonstrates analog input by reading a flex sensor on Analog Pin 0,

and displayig the digital value representations on a 16x2 LCD

 

The circuit:

* Flex Sensor attached to analog input 0 on one end,

* and one side pin (either one) to ground

* LCD RS pin to digital pin 12

* LCD Enable pin to digital pin 11

* LCD D4 pin to digital pin 5

* LCD D5 pin to digital pin 4

* LCD D6 pin to digital pin 3

* LCD D7 pin to digital pin 2

* LCD R/W pin to ground

* 10K resistor:

* ends to +5V and ground

* wiper to LCD VO pin (pin 3)

 

* Code adapted from efforts by:

* David A. MEllis, Tom Igoe, Limor Fried

 

*/

 

#include <LiquidCrystal.h>

 

// initialize the library with the numbers of the interface pins

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

 

 

int sensorPin = A0; // select the input pin for the flex sensor

int ledPin = 9; // select the pin for the LED

int sensorValue = 0; // variable to store the value coming from the sensor

 

void lcdprintSensorValue(int sensorValue) {

// go to (0,0):

lcd.clear();

// Print a header message to the LCD.

lcd.print("Sensor Value:");

 

// set the cursor to column 0, line 1

// (note: line 1 is the second row, since counting begins with 0):

lcd.setCursor(0, 1);

 

// Print the sensor value to the LCD

lcd.print(sensorValue);

}

 

 

void setup() {

// declare the ledPin as an OUTPUT:

pinMode(ledPin, OUTPUT);

 

// set up the LCD's number of columns and rows:

lcd.begin(16, 2);

}

 

void loop() {

// read the value from the sensor (0 - 1024)):

// divide because we need range from 0 - 255

// re-normalize to zero for the flex sensor by subtracting 50

// expand the measurement range by multiplying by 2.5

sensorValue = analogRead(sensorPin)/4;

sensorValue -= 50;

sensorValue *= 2.5;

 

// turn the ledPin on

analogWrite(ledPin, sensorValue);

 

// Print the sensor value to the LCD

lcdprintSensorValue(sensorValue);

 

// allow the changing sensor values to be visible

// instead of changing so quickly.

delay(100);

}

 

 Great commenting

 

4. Force Sensitive Resistor

Just like the Flex sensor, the FSR changes resistance - in this case, when pressure is applied to the FSR (Wikipedia page). Here's the datasheet. We can reuse the same circuit as before without LED circuit.

 

 

Build two FSR circuits to enable a game of thumb wrestling.

a. What resistance values do you see from your force sensor?

The sensor range changes very quickly from 1 megOhm, all the way down to almost 0 ohms.

 

b. What kind of relationship does the resistance have as a function of force applied? (eg, linear?)

It appears as if there is a power relationship between force and resistance.

 

c. Include a copy of your FSR thumb wrestling code in your lab write-up.

/*

Thumb Wrestling

Demonstrates analog input by reading analog sensors on analog pins 4 and 5, and

summing the analog sensor values for each sensor and displaying each on an LCD.

The higher value "wins" the thumb wrestling match.

 

The circuit:

* Voltage divider circuit with FSR sensor on the "high side"

* one FSR pin attached to analog input 0

* other FSR pin attached to Vcc

* a 22K resistor on the "low side"

* one 22K end attached to FSR pin and analog input 0

* other 22K end attached to ground

 

* This code is based on the AnalogInput code example:

Created by David Cuartielles

Modified 4 Sep 2010

By Tom Igoe

http://arduino.cc/en/Tutorial/AnalogInput

*/

 

#include <LiquidCrystal.h>

 

// initialize the library with the numbers of the interface pins

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

 

 

int sensorPinA = A4; // select the input pin for force sensor 1

int sensorPinB = A5; // select the input pin for force sensor 2

int ledPin = 9; // select the pin for the LED

int sensorValueA = 0; // variable to store the value coming from the sensor

int sensorValueB = 0; // variable to store the value coming from the sensor

int lcd_columnA = 2;

int lcd_columnB = 12;

 

void lcdprintSensorValue(int sensorValue, int lcd_column) {

// set the cursor to column 0, line 1

// (note: line 1 is the second row, since counting begins with 0):

lcd.setCursor(lcd_column, 1);

 

// Print the sensor value to the LCD

lcd.print(sensorValue);

}

 

 

void setup() {

// declare the ledPin as an OUTPUT:

pinMode(ledPin, OUTPUT);

 

// set up the LCD's number of columns and rows:

lcd.begin(16, 2);

}

 

void loop() {

for (int i=0; i < 30; i++) {

// read both sensors values (0 - 1024)):

// divide because we need range from 0 - 255

// and create a running total of each amount

sensorValueA += analogRead(sensorPinA)/4;

sensorValueB += analogRead(sensorPinB)/4;

 

// go to (0,0):

lcd.clear();

 

// print a header line to lcd

lcd.print("TOTAL_A - TOTAL_B");

 

// Print the sensor value to the LCD

lcdprintSensorValue(sensorValueA, lcd_columnA);

 

// Print the sensor value to the LCD

lcdprintSensorValue(sensorValueB, lcd_columnB);

 

// allow the changing sensor values to be visible

// instead of changing so quickly.

delay(100);

}

}

 

Part B. Voltage Varying Sensors

Some more sophisticated sensors have ICs that measure physical phenomena and then output an analog voltage level, varying voltage much as a voltage divider circuit would.

 

1. IR Distance Sensor

The circuit for the distance sensor is simple: just connect red to 5V, black to ground, and yellow to analog input 0.

Use your Lowly Multimeter program to look at the data the sensor returns.

 

Move your hand or a piece of paper over the sensor and see how the readings vary with distance.

a. Describe the voltage change over the sensing range of the sensor.

When the field of view is clear, the ADC readings range between 0 and 15 (out of 255). As a paper is brought closer to the sensor, the values begin increasing in a linear-like fashion until a maximum of about 160 is generated. The values then plateau for a short distance before they begin dropping again as the paper is brought all the way up to the sensor. The value at that end is about 50.

 

b. Does it match up with what you expect from the datasheet?

The shape of the curve would be identical as that on the datasheet, though the values would be relative.

 

 

2. Accelerometer

Start off with the example code that reads values from a 3-axis accelerometer out to a computer over the serial monitor. Use your mighty coding skills to indicate what your readings are on the X, Y and Z axes of the accelerometer on your LCD panel!

 

a. Include your accelerometer read-out code in your write-up.

/*

ADXL3xx

 

Reads an Analog Devices ADXL3xx accelerometer and communicates the

acceleration through a 16x2 LCD.

 

Accelerometer pinout:

1.G - Ground

2.Vin- Voltage, 5V

3.Xo- X axis output, 0 - 3.3V

4.Yo- Y axis output, 0 - 3.3V

5.Zo- Z axis output, 0 - 3.3V

6.G - Ground

7.3V0 - 3.3V output from the voltage regulator

8.GS - tie low for 1.5g sensing, high for 6g sensing

9.ST - self test pin (not needed for this assignment)

 

http://www.arduino.cc/en/Tutorial/ADXL3xx

 

The circuit:

analog 0: accelerometer self test

analog 1: z-axis

analog 2: y-axis

analog 3: x-axis

 

created 2 Jul 2008

by David A. Mellis

modified 4 Sep 2010

by Tom Igoe

 

This example code is in the public domain.

 

*/

 

#include <LiquidCrystal.h>

 

// initialize the library with the numbers of the interface pins

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

 

// these constants describe the pins. They won't change:

const int xpin = A1; // x-axis of the accelerometer

const int ypin = A2; // y-axis

const int zpin = A3; // z-axis (only on 3-axis models)

 

int xValue = 0;

int yValue = 0;

int zValue = 0;

 

 

void setup()

{

// set up the LCD's number of columns and rows:

lcd.begin(16, 2);

}

 

void loop()

{

// print the sensor values:

xValue = analogRead(xpin);

yValue = analogRead(ypin);

zValue = analogRead(zpin);

 

// go to (0,0):

lcd.clear();

// Print a header message to the LCD.

lcd.print("XXX - YYY - ZZZ");

 

// set the cursor to column 0, line 1

// (note: line 1 is the second row, since counting begins with 0):

lcd.setCursor(0, 1);

 

lcd.print(xValue);

lcd.print(" - ");

lcd.print(yValue);

lcd.print(" - ");

lcd.print(zValue);

 

// delay before next reading:

delay(100);

}

 

 

Part D. Logging values to the EEPROM and reading them back

 

1. Design your logger

Your data logger will have two main modes: one where it logs data and another where it plays the data back.

Create a state diagram sketch that indicates how you'd like to switch between one mode and the other, and also what you'd like the program to do in each state.

 

a. Turn in a copy of your final state diagram.

 

 Nice state diagram!

 

 

2. Reading and writing values to the EEPROM

The Atmega32U4 on the Teensy has 1K bytes of internal EEPROM.

a. How many byte-sized data samples can you store on the Atmega32U4?

1024 samples.

 

 

b. How would you get your analog data from the ADC to be byte-sized?

Cast the values as “char” prior to storing them into the EEPROM.

 

 

3. Create your data logger!

Your logger should be able to record a stream of analog data (at a sample rate of your desire) and then play it back at some later point in time. You are welcome to play back to either the 16x2 LCD or the serial monitor.

a. Use the lab camera or your own camera/cell phone to record and upload a short demo video of your logger in action.

 

b. Here is the datalogger code:

 

#include <EEPROM.h>

#include <LiquidCrystal.h>

 

// initialize the library with the numbers of the interface pins

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

 

#define PBUTTON_PRESS LOW

#define FLEX_THRESHOLD 100

#define IDLE 0x01

#define WAIT_CHANGE_STATE 0x02

#define RECORD_SITTING 0x04

#define RECORD_STANDING 0x08

#define PLAYBACK_STATE 0x10

#define CLEAR_EEPROM_STATE 0x20

#define SITTING 0

#define STANDING 1

#define MILLISECONDS_PER_SECOND 1000

#define EEPROM_ADDRESS_MAX 255

 

 

// set pin numbers - constants won't chang

const int PBUTTON_RECORD_PIN = 6; // the number of the pushbutton pin

const int PBUTTON_PLAY_PIN = 0; // the number of the pushbutton pin

const int FSR_SENSOR_PIN = A4; // select the input pin for the force sensor

const int LED_PIN = 15; // select the pin for the LED

 

// Initialize any sensor variables

int forceValue = 0; // variable to store the value coming from the sensor

int buttonState_play = 0; //

int buttonState_record = 0; //

 

// Initialize the state variables

int active_state = IDLE;

int next_state = IDLE;

int userPosition = STANDING;

int sitting_event = 0;

int standing_event = 0;

int writing_done_event = 0;

int playback_done_event = 0;

int clear_done_event = 0;

 

// Initialize other variables

int address = 0;

unsigned int timestamp_readvalue = 0x0000;

unsigned int timestamp_lsb = 0x0000;

unsigned int timestamp_msb = 0x0000;

unsigned char value = 0x00;

unsigned long initial_timestamp = 0;

unsigned long running_timestamp = 0;

char running_timestamp_lobyte = 0x00;

char running_timestamp_hibyte = 0x00;

 

void setup()

{

// set up the LCD's number of columns and rows:

lcd.begin(16, 2);

 

// initialize the serial communication:

Serial.begin(9600);

 

// initialize the pushbutton pin as an input:

pinMode(PBUTTON_RECORD_PIN, INPUT);

// initialize the pushbutton pin as an input:

pinMode(PBUTTON_PLAY_PIN, INPUT);

}

 

void loop()

{

// read the state of the pushbutton value:

buttonState_play = digitalRead(PBUTTON_PLAY_PIN);

// read the state of the pushbutton value:

buttonState_record = digitalRead(PBUTTON_RECORD_PIN);

// read the flex sensor value (0 - 1024)

// divide because we need range from 0 - 255

forceValue = analogRead(FSR_SENSOR_PIN)/4;

// Print the forceValue

Serial.print("ForceValue:");

Serial.print("\t");

Serial.print(forceValue);

Serial.println();

// Print the userPosition

Serial.print("userPosition:");

Serial.print("\t");

Serial.print(userPosition);

Serial.println();

 

// determine if there has been a change in user position

if (userPosition == SITTING && forceValue > FLEX_THRESHOLD)

standing_event = 1;

if (userPosition == STANDING && forceValue < FLEX_THRESHOLD)

sitting_event = 1;

 

 

// check if the pushbutton is pressed.

// if it is, the buttonState is PRESSED:

if (buttonState_record == PBUTTON_PRESS) {

if(active_state == IDLE) {

initial_timestamp = millis();

next_state = WAIT_CHANGE_STATE;

}

 

if(active_state == WAIT_CHANGE_STATE)

next_state = IDLE;

}

 

 

if (buttonState_play == PBUTTON_PRESS) {

if(active_state == IDLE)

next_state = PLAYBACK_STATE;

}

 

 

if (sitting_event == 1 ) {

sitting_event = 0;

running_timestamp = (millis() - initial_timestamp)/MILLISECONDS_PER_SECOND;

if(active_state == WAIT_CHANGE_STATE)

next_state = RECORD_SITTING;

}

 

if (standing_event == 1 ) {

standing_event = 0;

running_timestamp = (millis() - initial_timestamp)/MILLISECONDS_PER_SECOND;

if(active_state == WAIT_CHANGE_STATE)

next_state = RECORD_STANDING;

}

 

if (writing_done_event == 1) {

writing_done_event = 0;

if(active_state == RECORD_SITTING)

next_state = WAIT_CHANGE_STATE;

 

if(active_state == RECORD_STANDING)

next_state = WAIT_CHANGE_STATE;

}

 

 

if (playback_done_event == 1) {

playback_done_event = 0;

if(active_state == PLAYBACK_STATE)

next_state = CLEAR_EEPROM_STATE;

}

 

 

if (clear_done_event == 1) {

clear_done_event = 0;

if(active_state == CLEAR_EEPROM_STATE)

next_state = IDLE;

}

 

 

 

active_state = next_state;

 

// print active state

Serial.println(active_state);

delay(250);

 

switch ( active_state )

{

case IDLE:

// turn the ledPin off

analogWrite(LED_PIN, 0x00);

break;

 

case WAIT_CHANGE_STATE:

// turn the ledPin on

analogWrite(LED_PIN, 0x80);

break;

 

case RECORD_SITTING:

// Set the new user position

userPosition = SITTING;

// create the two-byte timestamp. the msb of hibyte specifies

// sitting (0) or standing (1)

running_timestamp_lobyte = (char)running_timestamp >> 8;

running_timestamp_hibyte = (char)running_timestamp;

running_timestamp_hibyte &= 0x7F;

 

// write the two parts of the 16-bit timestamp to the EEPROM

EEPROM.write(address, running_timestamp_lobyte);

EEPROM.write(address+1, running_timestamp_hibyte);

 

// print timestamp to LCD

lcd.clear();

lcd.print("Timestamp:"); // print header on first row

lcd.setCursor(0, 1);

lcd.print(running_timestamp); // print timestamp on second row

 

// advance to the next address of the EEPROM.

address += 2;

writing_done_event = 1;

break;

 

case RECORD_STANDING:

// Set the new user position

userPosition = STANDING;

// create the two-byte timestamp. the msb of hibyte specifies

// sitting (0) or standing (1)

running_timestamp_lobyte = running_timestamp >> 8;

running_timestamp_hibyte = (char)running_timestamp;

running_timestamp_hibyte |= 0x80;

 

EEPROM.write(address, running_timestamp_lobyte);

EEPROM.write(address+1, running_timestamp_hibyte);

 

// print timestamp to LCD

lcd.clear();

lcd.print("Timestamp:"); // print header on first row

lcd.setCursor(0, 1);

lcd.print(running_timestamp); // print timestamp on second row

 

// advance to the next address of the EEPROM.

address += 2;

writing_done_event = 1;

break;

 

case PLAYBACK_STATE:

// reset the address to begin reading from the first sensor reading

address = 0;

 

// read back all 30 samples and print them to the serial monitor

for (int i=0; i < EEPROM_ADDRESS_MAX; i+=2)

{

// read a byte from the current address of the EEPROM

value = EEPROM.read(address);

timestamp_lsb += value;

value = EEPROM.read(address + 1);

timestamp_msb += value;

timestamp_msb <<= 8;

timestamp_readvalue = timestamp_msb + timestamp_lsb;

 

 

if(timestamp_readvalue == 0)

i = EEPROM_ADDRESS_MAX;

 

 

Serial.print(address);

Serial.print("\t");

if (timestamp_readvalue > 0x7FFF) {

timestamp_readvalue &= 0x7FFF;

Serial.print(timestamp_readvalue, DEC);

Serial.print(" - STANDING");

} else {

Serial.print(timestamp_readvalue, DEC);

Serial.print(" - SITTING");

}

 

Serial.println();

 

 

// advance to the next address of the EEPROM

address += 2;

 

delay(100);

timestamp_readvalue = 0x0000;

timestamp_lsb = 0x0000;

timestamp_msb = 0x0000;

}

 

playback_done_event = 1;

delay(10000);

break;

 

case CLEAR_EEPROM_STATE:

address = 0;

 

// clear all samples from EEPROM

for (int i=0; i < EEPROM_ADDRESS_MAX; i++)

{

// read a byte from the current address of the EEPROM

EEPROM.write(address, 0x00);

 

Serial.print(address);

Serial.print("\t");

Serial.print("- clear");

Serial.println();

 

// advance to the next address of the EEPROM

address++;

 

delay(100);

}

 

 

clear_done_event = 1;

break;     

 

default:

active_state = IDLE;

next_state = IDLE;

userPosition = STANDING;

sitting_event = 0;

standing_event = 0;

writing_done_event = 0;

playback_done_event = 0;

initial_timestamp = 0;

running_timestamp = 0;

 

 

lcd.clear();

lcd.print("** STATE_ERROR ** "); // print header on first row

lcd.setCursor(0, 1);

lcd.print("Default state entered!"); // print timestamp on second row

 

delay(10000);

break;

}

}

 Nicely done.