D:/DRISSI/arduino-0022/arduino-0022/libraries/TimerOne/TimerOne.cpp
00001 /*
00002  *  Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
00003  *  Original code by Jesse Tane for http://labs.ideo.com August 2008
00004  *  Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
00005  *  Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
00006  *
00007  *  This is free software. You can redistribute it and/or modify it under
00008  *  the terms of Creative Commons Attribution 3.0 United States License. 
00009  *  To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/ 
00010  *  or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
00011  *
00012  */
00013 
00014 #include "TimerOne.h"
00015 
00016 TimerOne Timer1;              // preinstatiate
00017 
00018 ISR(TIMER1_OVF_vect)          // interrupt service routine that wraps a user defined function supplied by attachInterrupt
00019 {
00020   Timer1.isrCallback();
00021 }
00022 
00023 void TimerOne::initialize(long microseconds)
00024 {
00025   TCCR1A = 0;                 // clear control register A 
00026   TCCR1B = _BV(WGM13);        // set mode as phase and frequency correct pwm, stop the timer
00027   setPeriod(microseconds);
00028 }
00029 
00030 void TimerOne::setPeriod(long microseconds)
00031 {
00032   long cycles = (F_CPU * (long long)microseconds) / 2000000;                                // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
00033   if(cycles < RESOLUTION)              clockSelectBits = _BV(CS10);              // no prescale, full xtal
00034   else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11);              // prescale by /8
00035   else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10);  // prescale by /64
00036   else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12);              // prescale by /256
00037   else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10);  // prescale by /1024
00038   else        cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10);  // request was out of bounds, set as maximum
00039   ICR1 = pwmPeriod = cycles;                                                     // ICR1 is TOP in p & f correct pwm mode
00040   TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
00041   TCCR1B |= clockSelectBits;                                                     // reset clock select register
00042 }
00043 
00044 void TimerOne::setPwmDuty(char pin, int duty)
00045 {
00046   unsigned long dutyCycle = pwmPeriod;
00047   dutyCycle *= duty;
00048   dutyCycle >>= 10;
00049   if(pin == 1 || pin == 9)       OCR1A = dutyCycle;
00050   else if(pin == 2 || pin == 10) OCR1B = dutyCycle;
00051 }
00052 
00053 void TimerOne::pwm(char pin, int duty, long microseconds)  // expects duty cycle to be 10 bit (1024)
00054 {
00055   if(microseconds > 0) setPeriod(microseconds);
00056   if(pin == 1 || pin == 9) {
00057     DDRB |= _BV(PORTB1);                                   // sets data direction register for pwm output pin
00058     TCCR1A |= _BV(COM1A1);                                 // activates the output pin
00059   }
00060   else if(pin == 2 || pin == 10) {
00061     DDRB |= _BV(PORTB2);
00062     TCCR1A |= _BV(COM1B1);
00063   }
00064   setPwmDuty(pin, duty);
00065   start();
00066 }
00067 
00068 void TimerOne::disablePwm(char pin)
00069 {
00070   if(pin == 1 || pin == 9)       TCCR1A &= ~_BV(COM1A1);   // clear the bit that enables pwm on PB1
00071   else if(pin == 2 || pin == 10) TCCR1A &= ~_BV(COM1B1);   // clear the bit that enables pwm on PB2
00072 }
00073 
00074 void TimerOne::attachInterrupt(void (*isr)(), long microseconds)
00075 {
00076   if(microseconds > 0) setPeriod(microseconds);
00077   isrCallback = isr;                                       // register the user's callback with the real ISR
00078   TIMSK1 = _BV(TOIE1);                                     // sets the timer overflow interrupt enable bit
00079   sei();                                                   // ensures that interrupts are globally enabled
00080   start();
00081 }
00082 
00083 void TimerOne::detachInterrupt()
00084 {
00085   TIMSK1 &= ~_BV(TOIE1);                                   // clears the timer overflow interrupt enable bit 
00086 }
00087 
00088 void TimerOne::start()
00089 {
00090   TCCR1B |= clockSelectBits;
00091 }
00092 
00093 void TimerOne::stop()
00094 {
00095   TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));          // clears all clock selects bits
00096 }
00097 
00098 void TimerOne::restart()
00099 {
00100   TCNT1 = 0;
00101 }