Today, you will learn how to read analog voltages so that you can do more advanced operations other than just reading a “yes” or a “no”, you will be able to gather information from temperature sensors, photo diodes, flex sensors, and a multitude of other sensors or input sources. We will then display the voltage as a binary number on three LED’s.
Goals
- Advanced usage of registers
- micro-controller configuration
- function creation in AVR studio
- reading analog voltages using the ATtiny85 micro-controller
- understanding a voltage divider
Required Materials
- Programmer
- Attiny85
- 3 LED’s and 3 current limiting resistors
- two photo diodes, flex sensors, or two resistors
- digital multimeter
Getting Started
- There is a reference voltage that may be selected “by writing to the REFS[2:0] bits in ADMUX”
- You select the analog channel “by writing to the MUX[3:0] bits in ADMUX”
- you need to make sure you choose the single ended value instead of differential value (for simplicity) simple explanations can be found here and here
- You need to decide if you wish to get an 8 bit value (256 different levels) or a 10bit value (1024 different levels) and read the proper registers ADCL and ADCH, set using ADLAR bit in ADMUX register.
- when getting a 10bit value make sure you read the ADCL register before the ADCH register
- Using single conversion mode, you start a conversion by writing a 1 to the ADSC bit in the ADSCRA register.
- this is the equation we need to use to calculate the voltage on the analog pin. Voltage = collected_value*Vref/2^(resolution 8 or 10) or Voltage = collected_value*5/1024 for our example
- collected_value = (ADCH << 8)|ADCL
- that shows how the data should be interpreted/combined when getting a 10bit reading.
Putting it all together:
Now that you have read and pulled out some of the information in the datasheet about how you collect analog readings, it is time to decide what you wish to do. Lets define a goal, collect a 10bit single ended analog reading with a range of 0-5V (Vref = Vcc and Vcc = 5V) and collect the reading from PB4 or ADC2. That way we can use PB0-PB2 to display our collected value in binary on three LED’s. The best place to look for information about each register regarding analog reading’s is starting on page 138 section 17.13.
1. Setting up a circuit
In order to test the ADC, you can try to measure the resistance of any of the resistive sensors in your kit, for example the light-resistor, the flex-sensor or the potentiometer. All of these “sensors” (the potentiometer really is a knob) change their resistance as a function of the quantity they measure. In order to measure a resistance, you can use it as part of a voltage divider. A voltage divider consists of two resistors, one the one you want to measure and the other one with known resistance. Its function, and how to wire it to your ADC input is explained in the following screencast:
http://www.youtube.com/watch?
2. Configuring the ADMUX register
The easiest to read way of setting register’s is by following the following format:
(register being set)= (tab ->) (stuff)| (tab ->) (more stuff)| (tab ->) (last bit of stuff);
From reading the datasheet, we know we want to fill the ADMUX register with the following information:
ADMUX = (0 << ADLAR)| //10bit precision (1 << MUX1)| //use PB4 as input pin (0 << REFS0)| //set refs0 and refs1 to 0 to use Vcc as Vref (0 << REFS1);
which can be simplified to:
ADMUX = (1 << MUX1);
3. Configure the ADCSRA register
The only bit we need to set in this register is the bit required to enable the ADC, we don’t want to start a conversion yet so don’t set the ADSC bit or any of the interrupt related pins.
ADSCRA = (1 << ADEN); //enable the ADC
4. Time to play around
Now that you have figured out how an ADC works and the basic configurations for the ATtiny85’s internal ADC lets upload some code that uses it and outputs a 0-5 number in binary that you can determine by setting a voltage on pin PB4 of the ATtiny chip. Before plugging in your micro controller connect three LED’s in series with resistors to PB0-PB2.
#include <avr/io.h> #include <stdint.h>
//configure ADC in this function void initADC (){
//Configure ADMUX register ADMUX = (1 << ADLAR)| //shift in a 1 and follow 8bit procedure (1 << MUX1)| //Use ADC2 or PB4 pin for Vin (0 << REFS0)| //set refs0 and 1 to 0 to use Vcc as Vref (0 << REFS1);
//Configure ADCSRA register ADCSRA = (1 << ADEN)| //set ADEN bit to 1 to enable the ADC (0 << ADSC); //set ADSC to 0 to make sure no conversions are happening }
//configure digital output pins void initDO () { //enable pin 4-6 or PB0-PB2 for debugging/output DDRB = (1 << 0)|(1 << 1)|(1 << 2); }
//function that returns an analog reading double getAIN() { //make sure we define result as a double so we can mult/divide w/o error double result = 0; int temp = 0;
//set ADSC pin to 1 in order to start reading the AIN value ADCSRA |= (1 << ADSC);
//do nothing until the ADSC pin returns back to 0; while (((ADCSRA >> ADSC) & 1)){}
//for 10bit precision we must read ADCL first (lower bits) //temp = ADCL;
//then read the most significant bits, shift them over, and //or that number with the least significant bits //result = ((ADCH << 0x8) | temp);
//for 8 bit precision we can just read ADCH: result = ADCH;
//to properly interpret the results as a voltage we need to //divide the result by the maximum range: 2^(#bits precision)-1 //and multiply the result by the Vref value, Vcc or 5V result = result * 5/255; for 8bit, below for 10bit resolution
// result = result * 5/1023; return result; }
int main () {
int reading = 0;
//place all configuration code at the begining of this function initADC(); initDO();
//place any repetitive code inside the infinite for loop below for (;;) {
//gets an analog reading reading = (int)getAIN();
//saves the reading in binary to the LED's PORTB = reading; } }
Check to make sure this code works by connecting a wire from PB4 to GND and then switching it to VCC, the LED display should change. Be aware that it will output 0 and 4 because it won’t display 5 until the ADC senses a voltage slightly higher than 5V.
[…] The first goal is to dim/brighten an LED based on the reading of any analog sensor. […]
[…] am following a tutorial which spells out how to read an analog voltage on an AVR. However the tutorial uses a […]