Professional Documents
Culture Documents
HOME
AVR TUTORIALS
MSP430 TUTORIALS
CONTACT FORM
FORUM
SEARCH
OK
CATEGORIES
Electro-Labs.com
68HC Projects
Arduino
ARM Cortex
ARM Cortex Tutorial
AVR TUTORIAL
ARM7 Projects
ARM9 Projects
AVR Projects
AVR Tutorial
BASIC Stamp
ChipKIT Projects
Atmega328 has one 16 bit timer which is more powerful comparing to 8 bit timers. 16 bit timer is called
CPLD Projects
Timer/Counter1. Counter1 has twice more bits than 8 bit Counter0, so you get more counts leading to longer
DSP Projects
dsPIC
FPGA Projects
Handy Circuits
Linux board projects
16 bit timer has pretty same functionality as Timer0 plus more specific ones. We wont be discussing Normal,
Misc
CTC, fast PWM and correct phase PWM modes as these are equivalent to Timer0. But lets focus on fresh things.
There we have a new module called Input Capture Unit along with Input Capture Flag (ICF1) interrupt and new
waveform generating mode called Phase and Frequency Correct PWM.
MSC-51 Projects
MSP430 Projects
MSP430 Tutorial
Netduino
PIC32
Uncategorized
MOST POPULAR
OCR1A=0x2564;
Using Direct Memory Access (DMA)
Compiler will sort this out automatically. But if you need to write separate bytes of 16 register then you need to
write high byte first and then low:
1
2
OCR1AH=0x25;
http://www.embedds.com/programming-16-bit-timer-on-atmega328/[06-06-2014 20:26:49]
in STM32 projects
Programming 16 bit timer on Atmega328 - Embedded projects from around the web
OCR1AL=0x64;
This is because 16 bit registers share one special TEMP register allowing to write 16 bit value at once, but using
two clock cycles. If you need to read 16 bit register first has to be low byte and then high.
Nucleo-F401RE Arduino shape with
Cortex-M4 power
projects
ARCHIVES
Select
Month
Select
Month
RECENT COMMENTS
jolin on Want more out of Raspberry Pi? try
Banana Pi
admin on What is Arduino Zero?
Danilo Recchia on What is Arduino Zero?
Michael Langley on Who May Seek For Spy
Earpiece?
Input capture may be triggered by rising or falling edge and even noise canceler may be used to make sure signal is
real. Ok, its time for example. Lets measure the duty cycle of signal fed in to ICP1 pin.
WE RECOMMEND
So we are going to capture three time-stamps needed to calculate duty cycle. One pair for measuring signal at level
1 and second pair of times-tamps to measure signal period. Seams easy. But there are some hidden stones. First
one what if signal frequency is to big. In this case we cannot do much in software level just external frequency
dividers would help. Second problem is when signal is too slow and one full timer count-up may not be enough.
Here we can find a solution by introducing software counter to keep timer overflow counts. So we are going to deal
http://www.embedds.com/programming-16-bit-timer-on-atmega328/[06-06-2014 20:26:49]
Programming 16 bit timer on Atmega328 - Embedded projects from around the web
with two interrupts that may overlap. Lets see how it goes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <avr/io.h>
#include <avr/interrupt.h>
//Counts overflovs
volatile uint16_t T1Ovs1, T1Ovs2;
//Variables holding three timestamps
volatile uint16_t Capt1, Capt2, Capt3;
//capture Flag
volatile uint8_t Flag;
//Initialize timer
void InitTimer1(void)
{
//Set Initial Timer value
TCNT1=0;
//First capture on rising edge
TCCR1B|=(1<<ICES1);
//Enable input capture and overflow interrupts
TIMSK1|=(1<<ICIE1)|(1<<TOIE1);
}
void StartTimer1(void)
{
//Start timer without prescaller
TCCR1B|=(1<<CS10);
//Enable global interrutps
sei();
}
//capture ISR
ISR(TIMER1_CAPT_vect)
{
if (Flag==0)
{
//save captured timestamp
Capt1=ICR1;
//change capture on falling edge
TCCR1B&=~(1<<ICES1);
//reset overflows
T1Ovs2=0;
}
if (Flag==1)
{
Capt2=ICR1;
//change capture on rising edge
TCCR1B|=(1<<ICES1);
//save first overflow counter
T1Ovs1=T1Ovs2;
}
if (Flag==2)
{
Capt3=ICR1;
//stop input capture and overflow interrupts
TIMSK1&=~((1<<ICIE1)|(1<<TOIE1));
}
//increment Flag
Flag++;
}
//Overflow ISR
ISR(TIMER1_OVF_vect)
{
//increment overflow counter
T1Ovs2++;
}
int main(void)
{
//dutycycle result holder
volatile uint8_t DutyCycle;
InitTimer1();
StartTimer1();
while(1)
{
//calculate duty cycle if all timestamps captured
if (Flag==3)
{
DutyCycle=(uint8_t)((((uint32_t)(Capt2-Capt1)+((uint3
/((uint32_t)(Capt3-Capt1)+((uint32_t)T1Ovs2*0x100
http://www.embedds.com/programming-16-bit-timer-on-atmega328/[06-06-2014 20:26:49]
Programming 16 bit timer on Atmega328 - Embedded projects from around the web
75
76
77
78
79
80
81
82
83
84
85
86
87
You can see in example that measuring of DutyCycle practically doesnt depend on frequency well at some range.
If running an MCU at 16 MHz then measured waveform period can range from about 1s or less up to several
seconds considering that 16 bit interrupt counter can have max 65536 values. I dont say that this algorithm is
effective or good for any reasons. If you actually know the range of PWM frequency you can do way better
approach. This example is just to represent how input capture mode works.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <avr/io.h>
void InitPort(void)
{
//Init PB1/OC1A and PB2/OC1B pins as output
DDRB|=(1<<PB1)|(1<<PB2);
}
void InitTimer1(void)
{
//Set Initial Timer value
TCNT1=0;
//set non inverted PWM on OC1A pin
//and inverted on OC1B
TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<COM1B0);
//set top value to ICR1
ICR1=0x00FF;
//set corrcet phase and frequency PWM mode
TCCR1B|=(1<<WGM13);
//set compare values
OCR1A=0x0064;
OCR1B=0x0096;
}
void StartTimer1(void)
{
//Start timer with prescaller 64
TCCR1B|=(1<<CS11)|(1<<CS10);
}
int main(void)
{
InitPort();
InitTimer1();
StartTimer1();
while(1)
{
//do nothing
}
}
http://www.embedds.com/programming-16-bit-timer-on-atmega328/[06-06-2014 20:26:49]
Programming 16 bit timer on Atmega328 - Embedded projects from around the web
This is it with 16-bit timer. Its only a fraction of what timer can do. I bet you can run other modes by your own
now. So keep practicing. Codes to download are here[25KB].
Read
TAGGED 16 bit timer input capture, AVR 16 bit timer, AVR 16 timer interrupts, AVR correct phase correct frequency PWM, AVR
timer examples, AVR Tutorial.
18 COMMENTS
DT
December 11, 2010 at 2:57 pm
You cant disable interrupts within an ISR. The final RETI instruction will set the global I bit.
Would you like me to act as a reviewer for your material? Id be happy to help. I truly appreciate your efforts
with the tutorials.
ADMIN
December 11, 2010 at 6:59 pm
Yep somehow I missed that. Anyway I was thinking of doing DutyCycle calculations inside
ISR(TIMER1_CAPT_vect)interrupt so disabling and enabling wouldnt be an issue.
Reviewing would be great. Even a contributing one person job leads to more errors.
ADMIN
December 11, 2010 at 7:11 pm
Corrected the code. Instead disabling interrupts I stooped timer until Duty cycle is calculated. Then timer is
started again.
DT
December 11, 2010 at 8:16 pm
I dont think that will work. You are stopping the Timer1 clock but this does not stop CLKio, so the IC edge
detectors will still operate and generate interrupts. The conventional approach is to disable the IC interrupt
http://www.embedds.com/programming-16-bit-timer-on-atmega328/[06-06-2014 20:26:49]
Programming 16 bit timer on Atmega328 - Embedded projects from around the web
instead (ICIE1).
DT
December 11, 2010 at 9:08 pm
ADMIN
December 12, 2010 at 12:58 pm
(my last comment disappeared?) Could be captcha problem. Somehow it was disabled automatically as some
other comments.
Thank you for finding this error. It really keeps interrupting and capturing timestamps of stopped timer what
leads to wrong calculations. Just disabled TIMER1_CAPT interrupts to avoid this.
ADMIN
December 12, 2010 at 1:05 pm
Just curious. Are you finding these tutorials useful and clear enough? Feel free to add suggestions where to pay
more attention to: explanations, technical details, code examples.
DT
December 12, 2010 at 3:19 pm
Personally, I dont need your tutorials, but if someone else is going to the considerable effort to write them then
Im happy to lend my experience to the process. Im fortunate in having been into embedded software as a
career for many years, and have already fallen into all the usual pit-falls!
Incidentally, in your corrected code, you can remove the redundant Timer clock disables/enables (apart from the
initial one), but just before you re-enable the interrupt you should clear the ICF1 flag by writing to TIFR1. This
is because you will probably have an old interrupt pending that you want to ignore.
ADMIN
December 12, 2010 at 3:46 pm
These pit-falls is probably most important part when learning. Your experience is invaluable here. I hope you
will keep an eye in future.
Regarding corrections. I left Timer running but disabled the capture and overflow interrupts. After calculus
done cleared interrupt flags in case any presence of them and re-enabled interrupts. This should work. I
understand that program layout isnt the best but this intended to be only to show how input capture works.
DT
December 12, 2010 at 5:08 pm
You shouldnt use a read-modify-write for the timer interrupt flags register (for exactly the same reason as with
PIN registers). You may clear flags that you didnt intend to, and although it wont affect this example, its not
good to leave a trap set like this.
Sorry to be pedantic on things like this, but if people try to use this code for their own experiments, they will
have problems if they try to extend the functionality at all.
http://www.embedds.com/programming-16-bit-timer-on-atmega328/[06-06-2014 20:26:49]
Programming 16 bit timer on Atmega328 - Embedded projects from around the web
ADMIN
December 12, 2010 at 5:35 pm
Dont be sorry. This is very important to do it right at the very beginning. This is what a tutorial is for. Gladly
Im also pulling some bad habits out.
Fixed. Thanks.
DT
December 12, 2010 at 10:11 pm
The duty cycle calculation really doesnt need 64-bit integers. That one line causes the code to grow from ~500
bytes to ~5500 bytes!!! And I dont think it will work since the casts are performed too late, which will
therefore overflow the 16-bit multiply that will be implemented. Also, the overflows should be multiplied by
010000 instead of 0xFFFF.
Its still not pretty, but this works and saves about 4.5kB of program space:
DutyCycle = (uint8_t)((((uint32_t)(Capt2 Capt1) PLUS ((uint32_t)T1Ovs1 * 0x10000L)) * 100L) /
((uint32_t)(Capt3 Capt1) PLUS ((uint32_t)T1Ovs2 * 0x10000L)));
Ive used PLUS since they seem to get removed when posting.
Note: it is vital that the subtraction is performed in unsigned 16-bit math then cast to 32-bit this then gives
the right answer even when Capt1 is larger than Capt2.
ADMIN
December 12, 2010 at 11:46 pm
Im wandering why I casted to 64 bit values while keeping 32 bits in mind? Probably did this absently.
Tested your code with simulator -works OK. Thanks.
DT
December 13, 2010 at 12:59 am
ADMIN
December 13, 2010 at 1:09 am
ANAND
May 31, 2012 at 12:15 pm
am using this program to detect frequency and through GSM we are sending that frequency as message to
mobile..but this program is not working for us.pls help us.
LEAVE A REPLY
Connect with:
Poweredby OneAllSocialLogin
http://www.embedds.com/programming-16-bit-timer-on-atmega328/[06-06-2014 20:26:49]
Programming 16 bit timer on Atmega328 - Embedded projects from around the web
Your email address will not be published. Required fields are marked *
Name *
Email *
Website
Comment
You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym
title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite="">
<strike> <strong>
Post Comment
http://www.embedds.com/programming-16-bit-timer-on-atmega328/[06-06-2014 20:26:49]
Programming 16 bit timer on Atmega328 - Embedded projects from around the web
June 2014
CONNECT WITH:
M
LOGIN
Username
10
11
12
13
14
15
17
18
19
20
21
22
23
24
25
26
27
28
29
30
May
USERS ONLINE
Password
17 Users Online
Remember Me
Login
Register
Lost Password
Connect with:
Poweredby OneAllSocialLogin
http://www.embedds.com/programming-16-bit-timer-on-atmega328/[06-06-2014 20:26:49]
16