0% found this document useful (0 votes)
23 views71 pages

Atmegea Intruppts

The document discusses Analog to Digital Conversion (ADC) methods, including Flash ADC, Ramp ADC, and Successive Approximation ADC, highlighting their advantages and disadvantages. It also covers the ADC implementation on the ATMega328P microcontroller, detailing the conversion process, accuracy considerations, and relevant registers. Additionally, it introduces Pulse Width Modulation (PWM) using Timer1 for various applications, including LED brightness control and generating an ambulance siren.

Uploaded by

s.kawish
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views71 pages

Atmegea Intruppts

The document discusses Analog to Digital Conversion (ADC) methods, including Flash ADC, Ramp ADC, and Successive Approximation ADC, highlighting their advantages and disadvantages. It also covers the ADC implementation on the ATMega328P microcontroller, detailing the conversion process, accuracy considerations, and relevant registers. Additionally, it introduces Pulse Width Modulation (PWM) using Timer1 for various applications, including LED brightness control and generating an ambulance siren.

Uploaded by

s.kawish
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 71

10/18/2017

ECE3411 – Fall 2017


Lec 4a.

ADC: Analog to Digital Conversion

Marten van Dijk


Department of Electrical & Computer Engineering
University of Connecticut
Email: [email protected]

Copied from Lecture 5a, ECE3411 – Fall 2015, by


Marten van Dijk and Syed Kamran Haider

Introduction
 Why do we need Analog-Digital Conversion?
 Real world is Analog
 Digital computers process Digital signals
 ADC/DAC serve as interface between Computers and
Real world!

 Analog Signals are “Continuous”


 A “Discrete” version of the analog signal is created by
“Sampling” the analog signal
 ADC then maps each sample onto a quantized range of
voltages which can be represented by binary values.

1
10/18/2017

ADC Types: Flash ADC


 Parallel Design
 A resistor divider network generates discrete voltage levels
 Input voltage is compared against all the voltage levels at once
 Priority Encoder considers the first “HIGH” input from the top as
valid, and converts it to binary form.

 Advantage: Fast
 Conversion takes just one cycle

 Disadvantage: A lot of components needed.


 2 − 1 comparators needed for 𝑛 bit ADC

Picture Source: www.hardwaresecrets.com

ADC Types: Ramp ADC


 Sequential Design
 A Counter counts from 0 ⋯ 2
 A DAC generates discrete voltage levels corresponding to the
digital values 0 ⋯ 2 (i.e. a voltage Ramp)
 In each cycle, input voltage is compared against the current
voltage level generated by DAC
 The comparator generates a “HIGH” value as soon as the ramp
crosses the input value. The corresponding counter value
becomes the output.

 Advantage: Only a few components needed.


Picture Source: www.hardwaresecrets.com
 Disadvantage: Very slow.
 2 − 1 cycles (in worst case) for 𝑛 bit ADC conversion

2
10/18/2017

ADC Types: Successive Approximation ADC


 Sequential Design
 Closest digital value is approximated by “Binary Search”
 First, the MSB of SAR is set to 1, and the comparator decides
whether the input voltage is higher or lower than DAC voltage.
The bit value is adjusted accordingly.
 The process is repeated for each bit from MSB down to LSB
 The final SAR value becomes the output.

 Most widely used ADC type.


 Advantages:
Picture Source: www.hardwaresecrets.com
 Only a few components needed.
 Conversion takes just 𝑛 cycles.

ATMega328P ADC Diagram


ADMUX To sample, switch connects a capacitor to the output of a buffer amplifier,
which charges or discharges the capacitor. This makes voltage across the
capacitor proportional to the input voltage. To hold, the switch disconnects.
ADC0
ADC1
Analog
… S&H + Conversion logic implements a
Mux Clocked
ADC7 -- successive approximation
off Mux algorithm (a binary search;
Bandgap
gnd one bit per search):
- DAC takes as input the
Voltage reference Vref: Aref DAC output of the conversion
- By default: Aref pin supplies Vref if a fixed voltage source logic and converts it to an
is connected to the Aref pin analog voltage where Aref
- The internal 1.1V reference is generated from the internal sets the full range
bandgap reference through an internal amplifier Conversion Logic - Analog comparator
- AVCC is connected to the ADC through a passive switch and decides whether the DAC
can be made Vref = Vcc +/- 0.3V output or input voltage is
Prescalar
- To reduce noise for Vref equal to 1.1V or AVCC the Aref the largest
pin can be externally decoupled by a capacitor to ground 6

3
10/18/2017

Pin Assignment

4
10/18/2017

Normal Conversion
 Takes 13 cycles

Accuracy
 Capacitor in S&H leaks and can therefore not hold a value for too long
 There exists a minimum sample speed/frequency

 Conversion logic takes time, so we cannot sample too fast


 There exists a maximum sample speed/frequency
 The faster you sample, you get a smaller number of accurate output bits (since the binary search
cannot completely finish)

 Noise: MCU produces up to 150mV line noise, there are other sources such as
electrical field, etc.
 Use capacitances close to the CPU to eliminate most of the inductance

10

5
10/18/2017

Prescalar

 E.g., a prescalar of 128 gives 16MHz/128 = 125000 (between 50 and 200 kHz)
 To complete the binary search takes 13 cycles = 13/125000 = 104 micro seconds
 Gives 10 bits uncalibrated accuracy at a linear scale to Vref

 CPU clock is at least twice as fast as the ADC’s acceptable frequency; therefore the smallest
prescalar must be >=2
11

ADMUX Register

12

6
10/18/2017

ADMUX Register

0..7 indicate input pins ADC0 .. ADC7

13

ADCH/ADCL: ADC Data Registers

ADLAR = Analog Data Left Adjust Register

If ADLAR is set to 0,
- read ADCL for low order bits, and
- until ADCH is read the ADC is
locked out

For 8-bit conversion, set


ADLAR to 1 and read ADCH

14

7
10/18/2017

ADCSRA: ADC Status Register A

 Bit 7: ADEN – analog converter enable bit; set this bit to 1 if you want to do a
conversion
 Bit 6 ADSC – AD start conversion; if it is set to 1, then a conversion is started for you
and it is auto set back to 0 when done
 You can poll this bit and as soon as it is 0, you know the conversion is done
 Or you can poll the interrupt flag (or use the corresponding ISR if enabled):

 Bit 4: ADIF – AD interrupt flag; will be set when a conversion is done and will
trigger an interrupt if ADIE is set
 Warning: do not mess with this flag, e.g., use ADCSRA |= (1<<ADSC);
15

ADCSRA: ADC Status Register A

 Bit 3: ADIE – AD interrupt enable; if turned on, write the ISR to handle what
happens when conversion finishes
 Bit 5: ADATE – allows one out of 8 selected events to trigger the ADC converter
when coupled with the ADCSRB register
 Bits 0,1,2: prescalar (see previous slide)

16

8
10/18/2017

ADCSRB

17

Example code ADC, no interrupt


// Borrowed from Bruce Land - Cornell University

// Performs single, left adjusted conversions and prints to UART

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>
#include <util/delay.h>
#include <math.h>
#include "uart.h"

volatile int Ain, AinLow;


volatile float Voltage;
char VoltageBuffer[6];

FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);

18

9
10/18/2017

Example code ADC, no interrupt


void main(void)
{
DDRC &= 0x00; // PC1 = ADC1 is set as input

uart_init();
stdout = stdin = stderr = &uart_str;

// ADLAR set to 1  left adjusted result in ADCH


// MUX3:0 set to 0001  input voltage at ADC1 Takes more than 1ms, hence conversion
ADMUX = (1<<MUX0) | (1<<ADLAR); will finish which takes 104us

// ADEN set to 1  enables the ADC circuitry


// ADPS2:0 set to 111  prescalar set to 128 (104us per conversion)
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);

// Start A to D conversion
ADCSRA |= (1<<ADSC);
fprintf(stdout,"\n\rStarting ADC demo...\n\r");

19

Example code ADC, no interrupt


while (1)
{
// Read from ADCH to get the 8 MSBs of the 10 bit conversion
Ain = ADCH;

// Typecast the volatile integer into floating type data, divide by maximum 8-bit value, and
// multiply by 5V for normalization
Voltage = (float)Ain/256.00 * 5.00;

//ADSC is cleared to 0 when a conversion completes. Set ADSC to 1 to begin a conversion.


ADCSRA |= (1<<ADSC);

// Write Voltage to string format and print (3 char string + “.” + 2 decimal places)
dtostrf(Voltage, 3, 2, VoltageBuffer);
fprintf(stdout,"%s\n\r",VoltageBuffer);
}
Takes more than 1ms, hence conversion
return 0; will finish which takes 104us
} 20

10
10/18/2017

Conversion needs to finish


 Conversion needs to finish before the next conversion is called

 Use a print statement


 Delay functionality (of at least 104us)
 while (!(ADCSRA & (1<<ADSC) == 0)) { }
 The most efficient solution

21

11
10/23/2017

ECE3411 – Fall 2017


Lab 4a.

PWM: Pulse Width Modulation

Marten van Dijk


Department of Electrical & Computer Engineering
University of Connecticut
Email: [email protected]

Copied from Lab 5a, ECE3411 – Fall 2015, by


Marten van Dijk and Syed Kamran Haider

Using Timer1 for PWM


 We’ll be using Timer1 in Fast PWM Mode with OCR1A as TOP
 I.e. (WGM13, WGM12, WGM11, WGM10) = (1,1,1,1)

 PWM signal is output at pin OC1B which is PB2 on ATmega328P


 OCR1A controls the frequency of the resulting PWM signal
 Every compare match A starts a new cycle of PWM waveform, i.e. PWM pin is ‘set’.

 OCR1B controls the duty cycle of the resulting PWM signal


 At every compare match B, the PWM signal is ‘cleared’ (non-inverting mode).

 Compare Match A ISR can be used to update OCR1A and OCR1B registers
 OCR1A changes frequency and OCR1B changes duty cycle.

 If PWM signal is needed at additional pin(s):


 Compare Match A ISR can be used to ‘set’ that pin(s).
 Compare Match B ISR can be used to ‘clear’ that pin(s).

1
10/23/2017

Connecting the Buzzer


 In this lab, we’ll be using a buzzer that’ll be driven by a PWM signal.
 Connect the buzzer according to the following schematic.

Task1: Low Frequency PWM Signal


Use Timer1 to generate a PWM signal on PB2 and PORTD such that:
 The PWM signal has a frequency of 1Hz
 While Switch 1 is pressed, the duty cycle of the PWM signal is gradually increased
(say in steps of 5%) up to 100%
 While Switch 2 is pressed, the duty cycle of the PWM signal is gradually decreased
(say in steps of 5%) down to 0
 Print the current duty cycle on LCD.
You don’t need to debounce the switches.
Hint: Use Compare Match A and B ISRs to generate PWM on PORTD in software.
Connect a pair of a LED and a current limiting resister (330 Ohm) to PB2.
Now you should be able to observe the LEDs’ blinking behavior with different duty
cycles.
4

2
10/23/2017

Task2: LED Brightness Control


Use Timer1 to generate a PWM signal on PB2 and PORTD such that:
 The PWM signal has a frequency of 1000Hz
 While Switch 1 is pressed, the duty cycle of the PWM signal is gradually increased
(say in steps of 1%) up to 100%
 While Switch 2 is pressed, the duty cycle of the PWM signal is gradually decreased
(say in steps of 1%) down to 0
You don’t need to debounce the switches.
Hint: Use Compare Match A and B ISRs to generate PWM on PORTD in software.
Connect a pair of a LED and a current limiting resister (330 Ohm) to PB2.
Now you should be able to observe the LEDs’ brightness behavior with different duty
cycles.

Task3: The Ambulance Siren


Using Timer1 PWM generation, implement an Ambulance Siren.
In particular, implement the following:
 Using Timer1, generate a PWM signal at PB2 with 25% duty cycle.
 Using Timer0, gradually vary the frequency of the PWM signal from 1kHz to 4kHz,
and then from 4kHz back to 1kHz and so on.
 I.e. Timer 0 overflows every ~16ms  ~120 overflows in 2 seconds.
 Each overflow changes the OCR1A value by 100 ticks.

 Notice that the duty cycle remains 25% for each frequency.
 Connect a Buzzer to the PWM signal as shown in earlier slides.
Now you should hear an ambulance siren.
Play with the frequency ranges and frequency update rates to transform the ambulance
siren into a Cop Car Siren 

3
10/18/2017

ECE3411 – Fall 2017


Lec 4b.

ADC: Analog to Digital Conversion

Marten van Dijk


Department of Electrical & Computer Engineering
University of Connecticut
Email: [email protected]

Copied from Lecture 5b, ECE3411 – Fall 2015, by


Marten van Dijk and Syed Kamran Haider

ADC Noise Canceler

1
10/18/2017

ADC Noise Reduction Mode = ADC Sleep Mode


 Enable sleep mode;
 Start conversion by calling sleep_cpu();
 MCU will be sleeping except for the conversion

 Set ADC interrupt and write ISR


 All timers stop when you use ADC sleep; only ADC, timer 2, and interrupts stay running

 Do something wrong here and it may sleep forever


 Always double check register settings and ISRs ..

Sleep Modes

2
10/18/2017

ADC Noise Reduction

Example code ADC with noise reduction


// Written by Bruce Land - Cornell University

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <stdio.h>
#include <stdlib.h>
#include <util/delay.h>
#include <math.h>
#include "uart.h"

#define Vref 5.00

volatile int Ain, AinLow;


volatile float Voltage;
char VoltageBuffer[10];

FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);

3
10/18/2017

Example code ADC with noise reduction

ISR (ADC_vect)
{
// Program ONLY gets here when ADC done flag is set
// When reading 10-bit values you MUST read the low byte first
AinLow = (int)ADCL;
Ain = (int)ADCH*256;
Ain = Ain + AinLow;
}

Example code ADC with noise reduction


int main(void)
{
//init the A to D converter
ADMUX = 0b00000001;
ADCSRA = (1<<ADEN) | (1<<ADIE) + 7 ;
SMCR = (1<<SM0) ; // sleep -- choose ADC mode

// init the UART -- uart_init() is in uart.c


uart_init();
stdout = stdin = stderr = &uart_str;
fprintf(stdout,"\n\rStarting ADC ISR demo...\n\r");

// Need the next two statements so that the USART finishes


// BEFORE the cpu goes to sleep.
while (!(UCSR0A & (1<<UDRE0))) ; // Is UART still doing stuff?
_delay_ms(1); // enough time to empty the transmit buffer

sleep_enable();
sei(); 8

4
10/18/2017

Example code ADC with noise reduction


while (1)
{
// Get the sample
//The sleep statement lowers digital noise and starts the A/D conversion
sleep_cpu();

//program ONLY gets here after ADC ISR is done


voltage = (float)Ain ;
voltage = (voltage/1024.0)*Vref ; //(fraction of full scale)*Vref
dtostrf(voltage, 6, 3, v_string);
printf("%s", v_string);

// Need the next two statements so that the USART finishes


// BEFORE the cpu goes to sleep the next time thru the loop.
while (!(UCSR0A & (1<<UDRE0))) ; // Is UART still doing stuff?
_delay_ms(1); // enough time to empty the transmit buffer
}
return 0;
} 9

Exercises
 Can you get rid of the _delay_ms(1) instruction in the while loop by using a task
based programming approach?
 This would be useful if other tasks would need to execute as well.

 Note that each char takes about 1ms to print:


 Is a 1ms delay in the main while loop enough? Why?
 How many ms does while (!(UCSR0A & (1<<UDRE0))); approximately wait in the main while loop?
 In a task based approach would it be better to avoid while (!(UCSR0A & (1<<UDRE0))); ?
 And how would you do this?

 Check the code in the slides (I changed an earlier version without double checking:
you may figure out a bug here and there )

10

5
10/18/2017

Example Problem: What is happening in the following code?


... inclusion of packages ...
... declaration of global variables ...
... we assume a 20MHz crystal ...

ISR (TIMER0_COMPA_vect)
{
//Update task timer
if (taskADC_timer >0 ) {--taskADC_timer;}
}

ISR (ADC_vect)
{
//Read a 10-bit conversion
AinLow = (int)ADCL;
Ain = (int)ADCH*256;
Ain = Ain + AinLow;
}

11

What is happening in the following code?


void taskADC(void)
{
//Reset task timer
taskADC_timer = 400;

//Convert Ain into a voltage


voltage = ((1.0*Ain)/1024.0)*5.0;

... Some more computation: sometimes taking more and sometimes taking less time ...
... However, no matter how long taskADC() takes, its execution is always <= 200 ms ...
}

12

6
10/18/2017

What is happening in the following code?


int main(void)
{
... initialization variables ...

| //set up timer 1 for 3.2 micro second counter increments


| TCCR1B = 3; //set prescalar to divide by 64

//set up timer 0 such that ISR(TIMER0_COMPA_vect) is called every 1 milli second


OCR0A = 77; //Set the compare reg to 78 time ticks
TIMSK0 = (1<<OCIE0A); //Turn on timer 0 cmp match ISR
TCCR0B = 4; //Set prescalar to divide by 256
TCCR0A = (1<<WGM01); //Turn on clear-on-match
//how accurate is this timer?

13

What is happening in the following code?


//initialize the A to D converter
DDRC &= 0xF0; //Set PORTC[3:0] as input for ADC
ADMUX = 0b00000001; //Indicate which pin should be measured
ADCSRA = (1<<ADEN) | (1<<ADIE) + 7 ; //Enable AD converter, enable its interrupt,
//set prescalar (notice that the ADSC bit is
//not set, so no ADC conversion is started)
SMCR = (1<<SM0) ; //Choose ADC sleep mode

sleep_enable();
sei();

14

7
10/18/2017

What is happening in the following code?


while (1)
{ The main body initializes timer 1, which is being polled
if (taskADC_timer == 0) before an ADC measurement in sleep mode and before the
{ execution of an "ADC task", and which is polled again as
soon as the measurement and task execution are finished.
| //Measure timer 1
| T1poll_before = TCNT1;

//Perform an ADC measurement in sleep mode, and execute taskADC:


sleep_cpu();
taskADC();

| //Measure timer 1 again and update busy with the amount of micro seconds that
| //have passed: every TCNT1 to TCNT1+1 increment takes 3.2 micro seconds.
| T1poll_after = TCNT1;
| if T1poll_after > T1poll_before {busy += (T1poll_after-T1poll_before)*3.2;}
| else {busy += ((T1poll_after-T1poll_before)+65536)*3.2;}
} The difference is converted to micro seconds and added to a variable busy. The goal of
} busy is to measure the time during which the MCU is doing "useful" work. The code that is
} related to busy is highlighted with vertical bars. 15

What is happening in the following code?


 Answer with "never", "sometimes", or "always", whether the execution times
(measured in micro seconds) of the following procedures are added into busy
(explain your answers):
 ISR(TIMER0_COMPA_vect)
 ?????

16

8
10/18/2017

What is happening in the following code?


 Answer with "never", "sometimes", or "always", whether the execution times
(measured in micro seconds) of the following procedures are added into busy
(explain your answers):
 ISR(ADC_vect)
 ?????

17

What is happening in the following code?


 Answer with "never", "sometimes", or "always", whether the execution times
(measured in micro seconds) of the following procedures are added into busy
(explain your answers):
 sleep_cpu()
 ?????

18

9
10/18/2017

What is happening in the following code?


 Answer with "never", "sometimes", or "always", whether the execution times
(measured in micro seconds) of the following procedures are added into busy
(explain your answers):
 taskADC()
 ?????

19

What is happening in the following code?


 The program assumes that taskADC() always takes <=200 ms. Use this assumption to
explain why the code
if T1poll_after > T1poll_before {busy += (T1poll_after-T1poll_before)*3.2;}
else {busy += ((T1poll_after-T1poll_before)+65536)*3.2;}
 correctly adds to busy the time in micro seconds that passed between the polling of
T1poll_before and the polling of T1poll_after.
 Solution: ??????

20

10
10/18/2017

Solutions
 Answer with "never", "sometimes", or "always", whether the execution times
(measured in micro seconds) of the following procedures are added into busy
(explain your answers):
 ISR(TIMER0_COMPA_vect)
 Sometimes:
 The ADC task is executed approximately every 400 ms and executes in less than 200 ms.
 So, there is always a significant number of ms during which the while loop does not execute the code
within the if statement.
 During this "idle" time the timer ISR is called every ms but its execution time is not added into busy.
 During the time that the ADC task is executed the timer ISR will also be called and executed. These
execution times do get added into busy.

21

Solutions
 Answer with "never", "sometimes", or "always", whether the execution times
(measured in micro seconds) of the following procedures are added into busy
(explain your answers):
 ISR(ADC_vect)
 Always:
 Right after sleep_cpu(), the ADC ISR is called.
 Since sleep_cpu() is part of a busy wrapper, the execution time of each ADC ISR is part of busy's
measurement.

22

11
10/18/2017

Solutions
 Answer with "never", "sometimes", or "always", whether the execution times
(measured in micro seconds) of the following procedures are added into busy
(explain your answers):
 sleep_cpu()
 The data sheet writes for the ADC Noise Reduction Mode that ”... the SLEEP
instruction makes the MCU enter ADC Noise Reduction mode, stopping the CPU but
allowing the ADC, the external interrupts, 2-wire Serial Interface address match,
Timer/Counter2 and the Watchdog to continue operating (if enabled) ...” This means
that all other HW modules stop working, in particular, the other timers/counters stop
incrementing.
 Never:
 During the execution of sleep_cpu() timer 1 does not increment.
 Hence, its execution time cannot be measured by polling TCNT1.

23

Solutions
 Answer with "never", "sometimes", or "always", whether the execution times
(measured in micro seconds) of the following procedures are added into busy
(explain your answers):
 taskADC()
 Always:
 the ADC task is part of a busy wrapper.

24

12
10/18/2017

Solutions
 The program assumes that taskADC() always takes <=200 ms. Use this assumption to
explain why the code
if T1poll_after > T1poll_before {busy += (T1poll_after-T1poll_before)*3.2;}
else {busy += ((T1poll_after-T1poll_before)+65536)*3.2;}
correctly adds to busy the time in micro seconds that passed between the polling of
T1poll_before and the polling of T1poll_after.
 Solution:
 Each task takes less than 200 ms, which is less than 2^{16} * 3.2 micro seconds (=209.7 ms),
 which is the time it takes to increment TCNT1 from 0 to its maximum value.
 So, TCNT1 may at most loop through once.
 If TCNT1 does not loop through, then T1poll_after > T1poll_before and (T1poll_after-T1poll_before)*3.2} measures the amount
of time that has lapsed in micro seconds.
 If TCNT1 loops though once, then T1poll_after <= T1poll_before and ((T1poll_after - 0) + (2^{16} - T1poll_before))*3.2
measures the amount of time that has lapsed.

25

Spring 2017: Advanced MCU Applications Lab


 What?
 Advanced course on Microcontrollers’ Applications.

 Instructor
 Marten van Dijk

 When?
 Next semester: Spring 2017

 Who can join?


 Everyone who has taken ECE3411

 What will be taught?


 Parallel Bus interfaces (for external SRAM/other devices)
 Controller Area Network (CAN Protocol)
 Wireless Protocols (E.g. Bluetooth)
 Analog Sensors Interfacing (E.g. Ultrasonic Sensors)
 Motor Control (DC motors, Servo motors)
 Real-time Operating Systems
 And more…
 Final Project: Collision Avoidance Robot

26

13
10/23/2017

ECE3411 – Fall 2017


Lab 4b.

ADC: Analog to Digital Conversion

Marten van Dijk


Department of Electrical & Computer Engineering
University of Connecticut
Email: [email protected]

Copied from Lab 5b, ECE3411 – Fall 2015, by


Marten van Dijk and Syed Kamran Haider

Hardware Changes for Task1


In this lab, we’ll be measuring analog voltages using ADC
 Connect the potentiometer to ADC6 pin as shown below.
 Connect AREF pin to VCC  Reference voltage becomes 5V.

1
10/23/2017

Task1: Simple Voltmeter


We are going to design a simple voltmeter that measures voltages between 0-5V with
~4mV resolution.
 Connect a potentiometer to produce variable voltage at ADC6 pin.
 Connect AREF pin to VCC
 Read the analog input voltage using ADC every 100ms
 Convert the ADC reading to voltage measurement and print the voltage on LCD.
Note: Use the full 10-bit resolution of the ACD
Now you should be able to observe different voltage readings as you twist the
potentiometer knob.

Task2: Light Sensor


We are going to control the brightness of LEDs based on the ambient light in the room.
 Replace the potentiometer with a resistor divider network with a photo cell (light
dependent resistor) and a 10kOhm resistor to produce variable voltage at ADC7 pin.
 Connect AREF pin to VCC
 Read the analog input voltage using ADC every 100ms
 Change the duty cycle of the PWM signal for LEDs to control their brightness.
 When the Photo cell detects dark, increase the brightness and vice versa.

2
10/23/2017

Task3: Voltage Measurement Statistics


Write a program with the following specifications:
 The program allows two modes for measuring voltages: Normal mode and ADC sleep
mode. The user can change mode through UART while the program is executing.
 The program measures with 10 bits accuracy the input voltage (against AREF with
VREF=5V) every 1ms.
 The program keeps track of the average and standard deviation of your
measurements over the last 50 ms.
 Every 150 ms display on the LCD screen on two separate lines the most recent
measured average voltage with its standard deviation (also use words/symbols to
make clear what is being displayed).

Open Questions in Task3


Task3 leaves some open questions:
 How often do you measure? And when do you measure? E.g., you may want to wait
say 1 ms after each print statement to the terminal and LCD screen such that the print
buffers are emptied before the next ADC conversion.
 How do you average if some of your ADC conversions are closer together in time than
others?
Pick your solution and explain its accuracy and what you could do in future versions to
improve the result.

3
10/23/2017

Further Observations
 Before entering the sleep mode, one needs to check bit RXC0=0 and bit TXC0=1,
i.e., everything is received and transmitted.
 One may still see the following artifact:
 Typing a character while in sleep mode only echoes part of the character or a corrupted character
over the UART.
 E.g. I typed two random strings while in sleep mode and the MCU echoed back this:
kadjflskadjflk³djflksdjflksdlkfs
skajsdhksajhdksjahdkjashdj³Øhkdjhkasjd

 Why does that happen?


 The backspace functionality helps the user to correct such an artifact.

4
10/18/2017

ECE3411 – Fall 2017


Lec 4c.

EEPROM
Watchdog Timer

Marten van Dijk


Department of Electrical & Computer Engineering
University of Connecticut
Email: [email protected]

Copied from Lecture 5c, ECE3411 – Fall 2015, by


Marten van Dijk and Syed Kamran Haider

EEPROM: Electrically Erasable Programmable ROM

You should not access EEPROM in main in a loop, otherwise, it will not exist any more !

EEPROM reads in 2 cycles and writes in about 100 cycles


Flash (program + optional read only data): read in 2 cycles
RAM: read+write in 1 cycle each

Data in EEPROM remains even if you pull the chip out of the board or turn power on and off
2

1
10/18/2017

EEPROM

EEPROM

2
10/18/2017

EEPROM

EEPROM
One can do sequential writes
before an erasure:
• During a write one can only
flip bits from 0 to 1
• If a bit needs to flip from a 1
to 0, an erasure is required
before doing a write
• Hence, sequential writes may
be possible if only 0 to 1 bit
flips need to be written
• The lifetime of an eeprom bit
is about 100.000 0 1 write
and 10 erasure cycles
• So, if sequential writes before
an erasure are possible, the
lifetime of eeprom is not
unnecessarily shortened

3
10/18/2017

EEPROM

EEPROM

4
10/18/2017

10

5
10/18/2017

EEPROM
#include <avr/eeprom.h>
#define eeprom_true 0 //Suppose you want to store a flag at position 0
#define eeprom_data 1 //Suppose you want to store data at position 1

// Code snippet in e.g. an initialization Use ‘T’ or something else from


if (eeprom_read_byte((uint8_t*)eeprom_true) == 'T') default 0 byte data values
{
time = eeprom_read_byte((uint8_t*)eeprom_data); (unint8_t*) is used to cast eeprom_data
} and eeprom_true into a byte pointer
else
{
time = 0; //Initialize time to 0 as this is the first time the code is running on the MCU
//before it has ever been reset
}

11

EEPROM
// Code snippet in some task:
if (SW1_Pressed)
{
if (eeprom_read_byte((uint8_t*)eeprom_true) != 'T')
{
eeprom_write_byte((uint8_t*)eeprom_true,'T');
}
eeprom_write_byte((uint8_t*)eeprom_data,time); //Write time to EEPROM
fprintf(stdout,"button push at %d \n\r", time); //Write time to UART
}

12

6
10/18/2017

Watchdog Timer

13

Watchdog Timer
 Suppose your application is heating a room
 Once the temperature is too high, the application should turn off
 Implement a watchdog timer:
 An independent heat sensor causes an ISR (e.g., external interrupt) when the measured temperature is
low enough
 This ISR resets the watchdog and disables itself
 The main program regularly enables the ISR
 The watchdog will turn off the system if
 The sensor breaks  no ISR will be called  the watchdog is not reset  the watchdog will count down to 0 and causes the
system to be reset (with or without executing a watchdog ISR before reset)
 The temperature is too high  no ISR will be called  etc.

 Safety: if sensor breaks or if temperature is to high, the system is reset


 In SW one can always reset the system if the temperature is too high, but how does it know whether
the sensor that measures the temperature is functioning correctly?

14

7
10/18/2017

Watchdog Timer

Watchdog reset restarts the counter


before the time-out value is reached:
• #include <avr/wdt.h>
• wdt_reset();

15

Watchdog Timer

16

8
10/18/2017

Watchdog Timer

 WDTCSR |= (1<<WDCE) | (1<<WDE);


 WDCE: Watchdog Change Enable allows to make changes during the next 4 cycles (= one operation)
 WDE: Watchdog Enable

 WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP3);
 This operation clears the WDCE bit as required by using = (not |=)
 WDIE: Watchdog Interrupt Enable  E.g., we want an interrupt after 4.0 seconds
 WDE: Watchdog Enable means a system reset is generated after 4.0 seconds
 (1<<WDP3) sets a prescalar

17

Watchdog Timer

18

9
10/18/2017

Watchdog Timer

Nothing can interrupt the timed sequence

Another example from the datasheet without interrupt enable

19

Watchdog Timer
 If we have enabled the interrupt, an interrupt is created before the system is reset
 E.g., ISR(WDT_vect) { Store state in eeprom }
 After system reset the initialization can read the last state from eeprom

 If a reset occurs, it is good practice to turn of the watchdog as soon as the MCU
starts
 The register contents survive after restart: this means the watchdog is enabled (and reset)
 If initialization takes too long, then the watchdog will time out and the MCU turns off: the MCU will
never get through the initialization
 So, turn off the watchdog at the start of your code, do the initialization, and turn on the watchdog
before entering the main while(1){ …} loop

20

10
10/18/2017

Watchdog Timer

21

Watchdog Timer
#include <avr/wdt.h>

#include <avr/eeprom.h>
#define eeprom_true 0 //Suppose you want to store a flag at position 0
#define eeprom_data 1 //Suppose you want to store data at position 1

ISR (WDT_vect)
{
eeprom_write_dword((uint32_t*)eeprom_data,mode); //Write our current mode to EEPROM
eeprom_write_byte((uint8_t*)eeprom_true, 'T'); //Set write flag TRUE
}

void Initialize(void)
{
… all other initialization …
WDTCSR |= (1<<WDCE) | (1<<WDE); // Set Watchdog Condition Edit for four cycles
WDTCSR = (1<<WDIE) | (1<<WDE) | (1<<WDP3); // Set WDT Int and Reset; Prescalar at 4.0s.
}
22

11
10/18/2017

Watchdog Timer
int main(void)
{
// WDOG Interrupt and Reset Disable, this only matters if reset occurs.
wdt_reset(); // Reset Watchdog timer
MCUSR &= ~(1<<WDRF); // Shut off Watchdog Reset Flag
WDTCSR |= (1<<WDCE) | (1<<WDE); // Set Watchdog Change Enable and WD Enable
WDTCSR = 0x00; // Disable Watchdog

Initialize();
// Read TimeOut from EEPROM
if (eeprom_read_byte((uint8_t*)eeprom_true) == 'T')
{
mode = eeprom_read_dword((uint32_t*)eeprom_data);
}
else
{
mode = 0; // Begin in normal mode
}
while (1) { ….. }
}
23

12
10/23/2017

ECE3411 – Fall 2017


Lab 4c.

PWM: Signal Generation & Rectification

Marten van Dijk


Department of Electrical & Computer Engineering
University of Connecticut
Email: [email protected]

Copied from Lab 6a, ECE3411 – Fall 2015, by


Marten van Dijk and Syed Kamran Haider

Task1: PWM – Rectified Sine Waveform


 In this task, you need to generate a `rectified' 62.5Hz sine waveform using PWM.
 Generate a 64kHz PWM signal at PB2 using Timer1 such that the duty cycle of the
PWM is a function of a 62.5Hz sine wave i.e. for f=62.5, duty_cycle ~ sin2πft
 An example of such a PWM signal is shown below, where the duty cycle follows a
sine function.

1
10/23/2017

Connections
 Connect the PWM signal to a RC low pass filter as shown below.

Connections
 Connect the output of the low pass filter to an oscilloscope and observe the resulting
waveform.
 This waveform should look like the one shown below, where the negative half cycles
are also transformed into positive half cycles.

2
10/23/2017

Task1a: Frequency Correction


 Correct frequency of the resulting sine wave.
 Hint 1: Include math.h library and use sin() function to compute the sine value.
 Hint 2: Use Timer0 to generate the argument to sin() function.

Task1b: Improving Signal Quality


 You are required to improve the quality of the resulting signal.
 Hint: Signal quality depends upon the number of steps taken from 0 to 2π to update
duty cycle.

 Notice that for this task, _delay_ms() / _delay_us() function calls are not allowed.

3
10/23/2017

Task2: PWM – Rectified Sawtooth Waveform


 In this task, you need to generate a saw tooth waveform using PWM.
 Generate a 64kHz PWM signal at PB2 using Timer1 such that the duty cycle of the
PWM is such that it results in a 10Hz saw tooth waveform.
 An example of such a PWM signal is shown below, where the duty cycle results in a
saw tooth wave form.

Task2a: Frequency Correction


 Similar to Task1a; Correct the frequency of the resulting saw tooth waveform.

4
10/23/2017

Task2b: Improving Signal Quality


 You are required to improve the quality of the resulting signal.
 Hint: Signal quality depends upon the number of steps taken in one sawtooth
waveform cycle to update the PWM duty cycle.

 Notice that for this task, _delay_ms() / _delay_us() function calls are not allowed.

5
Department of Electrical and Computing Engineering

UNIVERSITY OF CONNECTICUT

ECE 3411 Microprocessor Application Lab: Fall 2017

Problem Set P4
There are 5 questions in this problem set. Answer each question according to the instructions
given in at least 3 sentences on own words.
If you find a question ambiguous, be sure to write down any assumptions you make.
Be neat and legible. If we can’t understand your answer, we can’t give you credit!
Any form of communication with other students is considered cheating and will merit an F as final
grade in the course.

SUBMIT YOUR ANSWERS IN A HARDCOPY FORMAT.

Do not write in the box below

1 (x/24) 2 (x/20) 3 (x/30) 4 (x/16) 5 (x/10) Total (xx/100)

Name:
Student ID:
ECE 3411 Fall 2017, Problem Set P4 Page 2 of 7

1. [24 points]: Assume a clock frequency of fclk = 20MHz and the following initialization:

DDRD = 0x10;
OCR1A = 39062;
OCR1B = 13020;
TCCR1A = 0b00110011;
TCCR1B = 0b00011101;

Answer the following questions:

a. In which mode is Timer1 running?

b. What is the numerical value of ‘TOP’ for Timer1 in this mode?

c. How much time (in seconds) does it take for Timer1 to complete one full cycle, i.e. going from
BOTTOM → TOP → BOTTOM? Be as accurate as possible in your calculations.

Initials:
ECE 3411 Fall 2017, Problem Set P4 Page 3 of 7

d. Starting from the moment of Timer1’s initialization, draw the waveforms of the TCNT1 register
value and the pin PB2 value w.r.t. time. Please draw the waveform strictly according to the timing
scale shown on X-axis, otherwise no credit will be given.

TOP
TCNT1

BOTTOM
1 2 3 4 5 6 7 8 9 Time (s)

5V
PB2

0V
1 2 3 4 5 6 7 8 9
Time (s)

e. In each full cycle of Timer1:


• For how much time (in seconds) is PB2 low? Be as accurate as possible in your calculations.

• For how much time (in seconds) is PB2 high? Be as accurate as possible in your calculations.

Initials:
ECE 3411 Fall 2017, Problem Set P4 Page 4 of 7

2. [20 points]:The code given below generates PWM signal using Timer 1.

int main(void)
{
DDRB = 0xFF; // Setting Port B as output

// Setting up Timer1
OCR1A = 100;
OCR1B = 30;
TCCR1B |= (1<<WGM13) | (1<<WGM12); // Turn on Fast PWM mode
TCCR1A |= (1<<WGM11) | (1<<WGM10); // Fast PWM mode with OCR1A as TOP
TCCR1A |= (1<<COM1B1)|(1<<COM1B0); // OC1B sets on compare match, clears at BOTTOM
TCCR1B |= (1<<CS12); // Set pre-scalar to divide by 256

while(1); // Nothing to do
}

a. At which pin of the microcontroller does this code produce the PWM signal? You may write
the logical name of the pin if you don’t remember the corresponding physical pin.

b. The figure below shows the TCNT1 register behavior over time. Draw the resulting PWM
signal in the space provided below.

100
TCNT1

30

0
Time

5V
PWM

0V
Time

Initials:
ECE 3411 Fall 2017, Problem Set P4 Page 5 of 7

3. [30 points]: You have designed a digital thermometer using the ATmega328P ADC and the temper-
ature sensor. The ADC is running on full resolution and its reference voltage is set to 1.1V .
If the temperature sensor produces 314mV at 25◦ C and its voltage sensitivity is 1mV /◦ C then answer
the following questions:

a. Theoretically, what is the maximum and minimum value of temperature that you can mea-
sure using this thermometer?

b. What is the smallest change in temperature (in ◦ C) that can be detected by this thermometer?
Be as accurate as possible in your calculations.

c. If the ADC reference voltage is changed to 512mV , then what would be the smallest change
in temperature (in ◦ C) that can be detected by this thermometer?

Initials:
ECE 3411 Fall 2017, Problem Set P4 Page 6 of 7

4. [16 points]:The code measures voltage every 1ms through ADC in sleep mode. The user can also
send characters to the MCU over UART. The program keeps track of the average and standard deviation
of the measurements over the last 50ms using a circular buffer for storing voltage values.

void Task_ADCMeasure(void)
{
int8_t flag = 1;
while (flag !=0) { flag = (UCSR0A ˆ (1<<TXC0)) & ((1<<RXC0) | (1<<TXC0)); }
sleep_cpu();

//statistics over last window samples


volt_index = ((1.0*Ain)/1024.00)*5.00; // 10 bit accuracy, AREF=5V
volt = v_buffer[v_index];
v_buffer[v_index] = volt_index;
v_index++;
v_index = (v_index % window);
Sum1 = Sum1 - volt + volt_index;
Sum2 = Sum2 - (volt*volt) + (volt_index * volt_index);

// Computes Moving Average and Standard Deviation


}

a. Does the circular buffer approach shown in the code above produce accurate results for ADC
noise measurement statistics? Explain your answer.

b. Can UART characters’ reception be corrupted during the ADC operation shown above? Ex-
plain your answer.

Initials:
ECE 3411 Fall 2017, Problem Set P4 Page 7 of 7

5. [10 points]: Can you shortly describe what you have learned and feel confident about using in the
future?

End of Problem Set


Initials:
Department of Electrical and Computing Engineering

UNIVERSITY OF CONNECTICUT

ECE 3411 Microprocessor Application Lab: Fall 2017

Problem Set A4
There are 4 questions in this problem set. Answer each question according to the instructions
given in at least 3 sentences on own words.
If you find a question ambiguous, be sure to write down any assumptions you make.
Be neat and legible. If we can’t understand your answer, we can’t give you credit!
Any form of communication with other students is considered cheating and will merit an F as final
grade in the course.

SUBMIT YOUR ANSWERS IN A HARDCOPY FORMAT.

Do not write in the box below

1 (x/28) 2 (x/30) 3 (x/20) 4 (x/22) Total (xx/100)

Name:
Student ID:
ECE 3411 Fall 2017, Problem Set A4 Page 2 of 11

1. [28 points]: Given that clock frequency (clkI/O ) of ATmega328P is 8MHz.


Assume the following about the code snippet given below:

• Each one of instruction 1, instruction 2, . . . , instruction 52 takes 4 CPU cycles.


• Evaluating while(1) statement takes zero CPU cycles.
• Evaluating if( !(ADCSRA & (1<<ADSC)) ) statement and executing its body take zero CPU
cycles.

#define F_CPU 8000000UL


#include <avr/io.h>

/* Main Function */
int main(void)
{
/* Configuring ADC Control and Status Register A */
ADCSRA = 0x86;

while(1)
{
instruction_1;
instruction_2;
instruction_3;
...
...
instruction_52;
if( !(ADCSRA & (1<<ADSC)) )
{
ADCSRA |= (1<<ADSC); // Start A to D Conversion
}

} /* End of while(1) Loop */

} /* End of main() */

Answer the following questions about the code snippet.

Initials:
ECE 3411 Fall 2017, Problem Set A4 Page 3 of 11

a. Given that it takes 13 ADC cycles, how much time (in microseconds) does it take to complete
one ADC conversion?

b. What prevents the condition “if( !(ADCSRA & (1<<ADSC)) )” from being satisfied?

c. How much time (in microseconds) does it take to complete one iteration of “while(1)” loop?

d. What is the percentage of while(1) loop iterations for which the body of “if( !(ADCSRA &
(1<<ADSC)) )” condition is executed?

Initials:
ECE 3411 Fall 2017, Problem Set A4 Page 4 of 11

2. [30 points]: Given that the clock frequency (clkI/O ) of ATmega328P is 16MHz, write a program
that uses watchdog timer in interrupt and reset modes simultaneously. The detailed functionality of the
program is as follows:

(a) Upon the system startup/reset, a LED connected to PB5 lights up for 0.5s and then turns off.
(b) After this, the main function starts blinking the LED at approximately 2Hz.
(c) After 2 seconds, the watchdog interrupt occurs and it keeps blinking the LED at 8Hz until the
system reset occurs.

To simplify the implementation, use delay ms() or delay us() routines inside while(1) loops to
implement the LED blinking function.
The following figure shows the detailed timing of the LED for the desired system. Notice that, after the
watchdog interrupt, it takes another watchdog timeout period for the system reset to occur.

0.5s Blinking at 2Hz Blinking at 8Hz 0.5s Blinking at 2Hz Blinking at 8Hz

ON

LED
OFF

0 1 2 3 4 5 6 7 8 9 10 Time(s)

Implement this system by filling the gaps in the provided code layouts of the subsections A, B and C.
You may use the provided data sheet for your reference.

Initials:
ECE 3411 Fall 2017, Problem Set A4 Page 5 of 11

A. Initialization: (10 points)


Complete the function initialize all(void) as instructed below:

// Define any variables here if needed

/* Initialization function */
void initialize_all(void)
{
/* Configure the LED pin and implement the functionality of step (a) */

/* Configure the Watchdog timer in Reset & Interrupt mode */


/* Set a prescaler such that watchdog times out after 2 seconds */

/* Any other initializations here if needed */

} /* End of initialize_all() */

Initials:
ECE 3411 Fall 2017, Problem Set A4 Page 6 of 11

B. Watchdog timeout ISR Implementation: (10 points)


Write the ISR ISR(WDT vect) to achieve the desired functionality.

/* Watchdog timeout ISR */


ISR(WDT_vect)
{
/* Blink the LED at 8Hz using _delay_ms() or _delay_us() function */

} /* end of Watchdog timeout ISR */

Initials:
ECE 3411 Fall 2017, Problem Set A4 Page 7 of 11

C. Main Function Implementation: (10 points)


Write the function main() to complete the system functionality.

/* Main Function */
int main(void)
{
/* Cleanup any aftereffects of Watchdog timeout reset */

initialize_all(); // Initialize everything


sei(); // Enable Global Interrupts

/* Event loop */
while(1)
{
/* Blink the LED at 2Hz using _delay_ms() */

} /* End of main() */
Initials:
ECE 3411 Fall 2017, Problem Set A4 Page 8 of 11

3. [20 points]: Assume a clock frequency of fclk = 16MHz. Read the following initialization and
ISRs:

#define MIN_TICKS 15624


#define MAX_TICKS 62499

// PWM variables
volatile uint16_t duty_cycle;
volatile uint16_t time_period;
volatile uint8_t toggle_flag;
int percentage_duty_cycle;

void initialization ()
{

DDRB |= (1<<DDB2);
time_period = MAX_TICKS;
duty_cycle = time_period/4;
toggle_flag = 0;

// Setup Timer1
OCR1A = time_period;
OCR1B = duty_cycle;
TCCR1A |= (1<<WGM11) | (1<<WGM10);
TCCR1B |= (1<<WGM13) | (1<<WGM12);
TCCR1A |= (1<<COM1B1);
TIMSK1 |= (1<<OCIE1A);
TCCR1B |= (1<<CS12);
}
// Timer 1 Compare Match A ISR (TCNT1 = OCR1A)
ISR (TIMER1_COMPA_vect)
{
if(toggle_flag)
{
if( time_period > MIN_TICKS)
{
time_period = time_period/2;
duty_cycle = time_period/4;
}
else
{
toggle_flag ˆ= 1;
}
}

else
{
if( time_period < MAX_TICKS)
Initials:
ECE 3411 Fall 2017, Problem Set A4 Page 9 of 11

{
time_period = (time_period * 2) +1;
duty_cycle = time_period/4;
}
else
{
toggle_flag ˆ= 1;
}
}

OCR1A = time_period;
OCR1B = duty_cycle;
}

Starting from the moment of Timer1’s initialization, draw the waveforms of the TCNT1 register value
and the pin PB2 value w.r.t. time. Please draw the waveform strictly according to the timing scale
shown on X-axis, otherwise no credit will be given.

TOP
TCNT1

BOTTOM
0.25 0.5 0.75 1 1.25 1.5 1.75 2 2.25 Time (s)

5V
PB2

0V
0.25 0.5 0.75 1 1.25 1.5 1.75 2 2.25 Time (s)

Initials:
ECE 3411 Fall 2017, Problem Set A4 Page 10 of 11

4. [22 points]: Given that the clock frequency (clkI/O ) of ATmega328P is 16MHz, you want to
implement two pins (A and B) that output PWM signals.

a. The frequency of each PWM signal is 1MHz, and the initial duty cycle of these two PWM signals is
50%. Please write the initialization function for timer0 (signal A) and timer1 (signal B).

void initialization ()
{

Initials:
ECE 3411 Fall 2017, Problem Set A4 Page 11 of 11

b. The duty cycle of A and B (duty cycle A and duty cycle B) should be updated in the ISRs according
to the following rules:
(a) For A: If duty cycle B > 90%, then duty cycle A = (1+duty cycle A)/2. If duty cycle B
< 10%, then duty cycle A = duty cycle A /2. In other cases, duty cycle A does not change.
(b) For B: If duty cycle A < 50%, then duty cycle B = (1+duty cycle B)/2. If duty cycle A
≥ 50%, then duty cycle B = duty cycle B /2.
Please write the ISRs for these two timers.

ISR (TIMER0_COMPA_vect)
{

ISR (TIMER1_COMPA_vect)
{

End of Problem Set


Initials:
Department of Electrical and Computing Engineering

UNIVERSITY OF CONNECTICUT

ECE 3411 Microprocessor Application Lab: Fall 2017

Independent LAB4
There are 2 independent lab questions in LAB4.

You may not discuss independent labs in any way, shape, or form with anyone else and you are
not allowed to lookup solutions from other sources.

Any form of communication with other students or looking up solutions is considered cheating
and will merit an F as final grade in the course.

Name:
Student ID:
ECE 3411 Fall 2017, LAB4 Page 2 of 5

1. [Pass/Fail points]: In this task, you need to design a digital thermometer using the ADC and an
external temperature sensor. The thermometer should display the room temperature in both Celsius and
Fahrenheits down to 1/10th of a degree.
You may refer to the provided data sheet of the temperature sensor (MCP9701A).

a. First, connect a potentiometer to the ADC channel and sample the analog input voltage after every
second.
• The potentiometer should generate a variable voltage between 0V and 5V.
• Print the current voltage (in millivolts) on LCD.

b. Now replace the potentiometer with a temperature sensor (MCP9701A) to read the temperature
every second.
• Convert the input voltage from the temperature sensor to the equivalent temperature.
• Print the temperature reading on LCD in both Celsius and Fahrenheits down to 1/10th of a
degree.
• Play with different resolutions of the ADC and different internal and external voltage refer-
ence values. What observations do you make?
Hint: The temperature sensor produces 400mV at 0 degree Celsius.

Initials:
ECE 3411 Fall 2017, LAB4 Page 3 of 5

2. [Pass/Fail points]: Complete the following tasks.

a. Your task is to extend the simple ADC voltage measurement code from Lab4b:Task1 with a watch-
dog timer:
• The watch dog timer should be set up such that if ADC reads ≥ 4V continuously for a period
of 4 seconds, only then a system reset must occur. Note that if ADC reads < 4V at anytime
after reading ≥ 4V but before the 4 seconds widnow has elapsed, then the system reset should
not occur.
• Before entering the main loop print Starting . to the terminal (this allows you to see when a
system reset actually occurs).
• Print a counter value on LCD where the counter is incremented every second.
• Before the system resets, the watch dog timer ISR should store in EEPROM the current value
of the counter. This value should be loaded from EEPROM before entering the main loop
and the counter should continue from this value onwards.

Initials:
ECE 3411 Fall 2017, LAB4 Page 4 of 5

b. Analyzing Assembly Code: Analyze the assembly of the provided C code that programs T imer0
in CTC mode to trigger Compare Match A ISR after every 1ms:

#define F_CPU 16000000UL


#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>

// variables
volatile uint16_t compare_matches;

//-------------------------------------------------------------------------------
// All initializations
void initialize_all(void)
{
// Setup Timer0
TIMSK0 |= (1<<OCIE0A); // Enable Compare Match A Interrupt
OCR0A = 249; // 250 ticks
TCCR0A |= (1<<WGM01); // CTC Mode
TCCR0B |= (1<<CS01) | (1<<CS00); // Prescaler = 64 ==> Overflow every 1ms
}

//-------------------------------------------------------------------------------
// Timer 0 Compare Match A ISR
ISR (TIMER0_COMPA_vect)
{
compare_matches++;
}

//------------------------------------------------------------------------------
int main(void)
{
initialize_all();
sei(); // Enable global interrupts

while (1);
}
• Increment a global counter inside the Compare Match A ISR.
• Use Atmel Studio debugger to see the Assembly code of your program.
• By stepping through the Assembly instructions one by one in the debugger, explain the
sequence of branch and jump instructions executed to call the Initialization function and
TIMER0 COMPA vect ISR.
• In particular, how does Interrupt Vector Table help in this regard?

Initials:
ECE 3411 Fall 2017, LAB4 Page 5 of 5

End of LAB4

Initials:

You might also like