Atmegea Intruppts
Atmegea Intruppts
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!
1
10/18/2017
Advantage: Fast
Conversion takes just one cycle
2
10/18/2017
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
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
13
If ADLAR is set to 0,
- read ADCL for low order bits, and
- until ADCH is read the ADC is
locked out
14
7
10/18/2017
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
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
#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"
18
9
10/18/2017
uart_init();
stdout = stdin = stderr = &uart_str;
// Start A to D conversion
ADCSRA |= (1<<ADSC);
fprintf(stdout,"\n\rStarting ADC demo...\n\r");
19
// 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;
// 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
21
11
10/23/2017
Compare Match A ISR can be used to update OCR1A and OCR1B registers
OCR1A changes frequency and OCR1B changes duty cycle.
1
10/23/2017
2
10/23/2017
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
1
10/18/2017
Sleep Modes
2
10/18/2017
#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"
3
10/18/2017
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;
}
sleep_enable();
sei(); 8
4
10/18/2017
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.
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
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
... 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
13
sleep_enable();
sei();
14
7
10/18/2017
| //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
16
8
10/18/2017
17
18
9
10/18/2017
19
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
Instructor
Marten van Dijk
When?
Next semester: Spring 2017
26
13
10/23/2017
1
10/23/2017
2
10/23/2017
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
4
10/18/2017
EEPROM
Watchdog Timer
You should not access EEPROM in main in a loop, otherwise, it will not exist any more !
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 10 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
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.
14
7
10/18/2017
Watchdog Timer
15
Watchdog Timer
16
8
10/18/2017
Watchdog Timer
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
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
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
Notice that for this task, _delay_ms() / _delay_us() function calls are not allowed.
3
10/23/2017
4
10/23/2017
Notice that for this task, _delay_ms() / _delay_us() function calls are not allowed.
5
Department of Electrical and Computing Engineering
UNIVERSITY OF CONNECTICUT
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.
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;
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)
• 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();
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?
UNIVERSITY OF CONNECTICUT
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.
Name:
Student ID:
ECE 3411 Fall 2017, Problem Set A4 Page 2 of 11
/* 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 main() */
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
/* Initialization function */
void initialize_all(void)
{
/* Configure the LED pin and implement the functionality of step (a) */
} /* End of initialize_all() */
Initials:
ECE 3411 Fall 2017, Problem Set A4 Page 6 of 11
Initials:
ECE 3411 Fall 2017, Problem Set A4 Page 7 of 11
/* Main Function */
int main(void)
{
/* Cleanup any aftereffects of Watchdog timeout reset */
/* 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:
// 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)
{
UNIVERSITY OF CONNECTICUT
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
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:
// 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: