mirror of
https://github.com/arduino/Arduino.git
synced 2025-02-20 14:54:31 +01:00
Got timer and pwm functions working with the ATmega168 (including pwm on pin 3); no longer relying on timer.c or timer.h from avrlib.
This commit is contained in:
parent
8b6864f3b8
commit
2f97a4b146
@ -30,6 +30,7 @@ UPDATES
|
||||
|
||||
0005
|
||||
|
||||
ATmega168 support on the way (currently timers and pwm working).
|
||||
New Wiring-compatible randomSeed(), random(max) and random(min, max) functions
|
||||
(except operating on longs instead of floats).
|
||||
Fixed bug that sometimes caused uploading of old versions of a sketch.
|
||||
@ -115,4 +116,4 @@ Yaniv Steiner and Giorgio Olivero have been supporting the project and are
|
||||
working at using it with the Instant Soup platform.
|
||||
|
||||
Arduino uses the GNU avr-gcc toolchain, uisp, avr-libc, avrlib, and code
|
||||
from Processing and Wiring.
|
||||
from Processing and Wiring.
|
||||
|
@ -105,6 +105,35 @@ pin_t digital_pin_to_port_array[NUM_DIGITAL_PINS] = {
|
||||
|
||||
pin_t *digital_pin_to_port = digital_pin_to_port_array;
|
||||
|
||||
int analog_out_pin_to_timer_array[NUM_DIGITAL_PINS] = {
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
// on the ATmega168, digital pin 3 has pwm
|
||||
#if defined(__AVR_ATmega168__)
|
||||
TIMER2B,
|
||||
#else
|
||||
NOT_ON_TIMER,
|
||||
#endif
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
TIMER1A,
|
||||
TIMER1B,
|
||||
#if defined(__AVR_ATmega168__)
|
||||
TIMER2A,
|
||||
#else
|
||||
TIMER2,
|
||||
#endif
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
};
|
||||
|
||||
int *analog_out_pin_to_timer = analog_out_pin_to_timer_array;
|
||||
|
||||
/*
|
||||
// Some of the digital pins also support hardware PWM (analog output).
|
||||
pin_t analog_out_pin_to_port_array[NUM_DIGITAL_PINS] = {
|
||||
{ NOT_A_PIN, NOT_A_PIN },
|
||||
@ -124,7 +153,7 @@ pin_t analog_out_pin_to_port_array[NUM_DIGITAL_PINS] = {
|
||||
};
|
||||
|
||||
pin_t *analog_out_pin_to_port = analog_out_pin_to_port_array;
|
||||
|
||||
*/
|
||||
pin_t analog_in_pin_to_port_array[NUM_ANALOG_IN_PINS] = {
|
||||
{ PC, 0 },
|
||||
{ PC, 1 },
|
||||
|
@ -1,483 +0,0 @@
|
||||
/*! \file timer.c \brief System Timer function library. */
|
||||
//*****************************************************************************
|
||||
//
|
||||
// File Name : 'timer.c'
|
||||
// Title : System Timer function library
|
||||
// Author : Pascal Stang - Copyright (C) 2000-2002
|
||||
// Created : 11/22/2000
|
||||
// Revised : 07/09/2003
|
||||
// Version : 1.1
|
||||
// Target MCU : Atmel AVR Series
|
||||
// Editor Tabs : 4
|
||||
//
|
||||
// This code is distributed under the GNU Public License
|
||||
// which can be found at http://www.gnu.org/licenses/gpl.txt
|
||||
//
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Modified by David A. Mellis, 9 July 2006.
|
||||
|
||||
#ifndef WIN32
|
||||
#include <avr/io.h>
|
||||
#include <avr/signal.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/sleep.h>
|
||||
#endif
|
||||
|
||||
#include "global.h"
|
||||
#include "timer.h"
|
||||
|
||||
#include "rprintf.h"
|
||||
|
||||
// Program ROM constants
|
||||
// the prescale division values stored in order of timer control register index
|
||||
// STOP, CLK, CLK/8, CLK/64, CLK/256, CLK/1024
|
||||
unsigned short __attribute__ ((progmem)) TimerPrescaleFactor[] = {0,1,8,64,256,1024};
|
||||
// the prescale division values stored in order of timer control register index
|
||||
// STOP, CLK, CLK/8, CLK/32, CLK/64, CLK/128, CLK/256, CLK/1024
|
||||
unsigned short __attribute__ ((progmem)) TimerRTCPrescaleFactor[] = {0,1,8,32,64,128,256,1024};
|
||||
|
||||
// Global variables
|
||||
// time registers
|
||||
volatile unsigned long TimerPauseReg;
|
||||
volatile unsigned long Timer0Reg0;
|
||||
volatile unsigned long Timer2Reg0;
|
||||
|
||||
typedef void (*voidFuncPtr)(void);
|
||||
volatile static voidFuncPtr TimerIntFunc[TIMER_NUM_INTERRUPTS];
|
||||
/*
|
||||
// delay for a minimum of <us> microseconds
|
||||
// the time resolution is dependent on the time the loop takes
|
||||
// e.g. with 4Mhz and 5 cycles per loop, the resolution is 1.25 us
|
||||
void delay_us(unsigned short time_us)
|
||||
{
|
||||
unsigned short delay_loops;
|
||||
register unsigned short i;
|
||||
|
||||
delay_loops = (time_us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty)
|
||||
|
||||
// one loop takes 5 cpu cycles
|
||||
for (i=0; i < delay_loops; i++) {};
|
||||
}
|
||||
*/
|
||||
/*
|
||||
void delay_ms(unsigned char time_ms)
|
||||
{
|
||||
unsigned short delay_count = F_CPU / 4000;
|
||||
|
||||
unsigned short cnt;
|
||||
asm volatile ("\n"
|
||||
"L_dl1%=:\n\t"
|
||||
"mov %A0, %A2\n\t"
|
||||
"mov %B0, %B2\n"
|
||||
"L_dl2%=:\n\t"
|
||||
"sbiw %A0, 1\n\t"
|
||||
"brne L_dl2%=\n\t"
|
||||
"dec %1\n\t" "brne L_dl1%=\n\t":"=&w" (cnt)
|
||||
:"r"(time_ms), "r"((unsigned short) (delay_count))
|
||||
);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
void timerInit(void)
|
||||
{
|
||||
u08 intNum;
|
||||
// detach all user functions from interrupts
|
||||
for(intNum=0; intNum<TIMER_NUM_INTERRUPTS; intNum++)
|
||||
timerDetach(intNum);
|
||||
|
||||
// initialize all timers
|
||||
timer0Init();
|
||||
timer1Init();
|
||||
#ifdef TCNT2 // support timer2 only if it exists
|
||||
timer2Init();
|
||||
#endif
|
||||
// enable interrupts
|
||||
sei();
|
||||
}
|
||||
|
||||
void timer0Init()
|
||||
{
|
||||
// initialize timer 0
|
||||
timer0SetPrescaler( TIMER0PRESCALE ); // set prescaler
|
||||
outb(TCNT0, 0); // reset TCNT0
|
||||
sbi(TIMSK, TOIE0); // enable TCNT0 overflow interrupt
|
||||
|
||||
timer0ClearOverflowCount(); // initialize time registers
|
||||
}
|
||||
*/
|
||||
void timer1Init(void)
|
||||
{
|
||||
// initialize timer 1
|
||||
timer1SetPrescaler( TIMER1PRESCALE ); // set prescaler
|
||||
outb(TCNT1H, 0); // reset TCNT1
|
||||
outb(TCNT1L, 0);
|
||||
sbi(TIMSK, TOIE1); // enable TCNT1 overflow
|
||||
}
|
||||
|
||||
#ifdef TCNT2 // support timer2 only if it exists
|
||||
void timer2Init(void)
|
||||
{
|
||||
// initialize timer 2
|
||||
timer2SetPrescaler( TIMER2PRESCALE ); // set prescaler
|
||||
outb(TCNT2, 0); // reset TCNT2
|
||||
sbi(TIMSK, TOIE2); // enable TCNT2 overflow
|
||||
|
||||
timer2ClearOverflowCount(); // initialize time registers
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
void timer0SetPrescaler(u08 prescale)
|
||||
{
|
||||
// set prescaler on timer 0
|
||||
outb(TCCR0, (inb(TCCR0) & ~TIMER_PRESCALE_MASK) | prescale);
|
||||
}
|
||||
*/
|
||||
void timer1SetPrescaler(u08 prescale)
|
||||
{
|
||||
// set prescaler on timer 1
|
||||
outb(TCCR1B, (inb(TCCR1B) & ~TIMER_PRESCALE_MASK) | prescale);
|
||||
}
|
||||
|
||||
#ifdef TCNT2 // support timer2 only if it exists
|
||||
void timer2SetPrescaler(u08 prescale)
|
||||
{
|
||||
// set prescaler on timer 2
|
||||
outb(TCCR2, (inb(TCCR2) & ~TIMER_PRESCALE_MASK) | prescale);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
u16 timer0GetPrescaler(void)
|
||||
{
|
||||
// get the current prescaler setting
|
||||
return (pgm_read_word(TimerPrescaleFactor+(inb(TCCR0) & TIMER_PRESCALE_MASK)));
|
||||
}
|
||||
|
||||
u16 timer1GetPrescaler(void)
|
||||
{
|
||||
// get the current prescaler setting
|
||||
return (pgm_read_word(TimerPrescaleFactor+(inb(TCCR1B) & TIMER_PRESCALE_MASK)));
|
||||
}
|
||||
|
||||
#ifdef TCNT2 // support timer2 only if it exists
|
||||
u16 timer2GetPrescaler(void)
|
||||
{
|
||||
//TODO: can we assume for all 3-timer AVR processors,
|
||||
// that timer2 is the RTC timer?
|
||||
|
||||
// get the current prescaler setting
|
||||
return (pgm_read_word(TimerRTCPrescaleFactor+(inb(TCCR2) & TIMER_PRESCALE_MASK)));
|
||||
}
|
||||
#endif
|
||||
|
||||
void timerAttach(u08 interruptNum, void (*userFunc)(void) )
|
||||
{
|
||||
// make sure the interrupt number is within bounds
|
||||
if(interruptNum < TIMER_NUM_INTERRUPTS)
|
||||
{
|
||||
// set the interrupt function to run
|
||||
// the supplied user's function
|
||||
TimerIntFunc[interruptNum] = userFunc;
|
||||
}
|
||||
}
|
||||
|
||||
void timerDetach(u08 interruptNum)
|
||||
{
|
||||
// make sure the interrupt number is within bounds
|
||||
if(interruptNum < TIMER_NUM_INTERRUPTS)
|
||||
{
|
||||
// set the interrupt function to run nothing
|
||||
TimerIntFunc[interruptNum] = 0;
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
u32 timerMsToTics(u16 ms)
|
||||
{
|
||||
// calculate the prescaler division rate
|
||||
u16 prescaleDiv = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0)));
|
||||
// calculate the number of timer tics in x milliseconds
|
||||
return (ms*(F_CPU/(prescaleDiv*256)))/1000;
|
||||
}
|
||||
|
||||
u16 timerTicsToMs(u32 tics)
|
||||
{
|
||||
// calculate the prescaler division rate
|
||||
u16 prescaleDiv = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0)));
|
||||
// calculate the number of milliseconds in x timer tics
|
||||
return (tics*1000*(prescaleDiv*256))/F_CPU;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
void timerPause(unsigned short pause_ms)
|
||||
{
|
||||
// pauses for exactly <pause_ms> number of milliseconds
|
||||
u08 timerThres;
|
||||
u32 ticRateHz;
|
||||
u32 pause;
|
||||
|
||||
// capture current pause timer value
|
||||
timerThres = inb(TCNT0);
|
||||
// reset pause timer overflow count
|
||||
TimerPauseReg = 0;
|
||||
// calculate delay for [pause_ms] milliseconds
|
||||
// prescaler division = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0)))
|
||||
ticRateHz = F_CPU/timer0GetPrescaler();
|
||||
// precision management
|
||||
// prevent overflow and precision underflow
|
||||
// -could add more conditions to improve accuracy
|
||||
if( ((ticRateHz < 429497) && (pause_ms <= 10000)) )
|
||||
pause = (pause_ms*ticRateHz)/1000;
|
||||
else
|
||||
pause = pause_ms*(ticRateHz/1000);
|
||||
|
||||
// loop until time expires
|
||||
while( ((TimerPauseReg<<8) | inb(TCNT0)) < (pause+timerThres) )
|
||||
{
|
||||
// DAM: these lines (in particular, the call to set_sleep_mode)
|
||||
// caused avr-gcc to give an error about a misplaced } in linux,
|
||||
// presumambly caused by a macro somewhere. Since they're not
|
||||
// vital (and are causing problems), I'm commenting them out.
|
||||
//if( TimerPauseReg < (pause>>8));
|
||||
//{
|
||||
// save power by idling the processor
|
||||
//set_sleep_mode(SLEEP_MODE_IDLE);
|
||||
//sleep_mode();
|
||||
//}
|
||||
}
|
||||
|
||||
// old inaccurate code, for reference
|
||||
|
||||
// calculate delay for [pause_ms] milliseconds
|
||||
//u16 prescaleDiv = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0)));
|
||||
//u32 pause = (pause_ms*(F_CPU/(prescaleDiv*256)))/1000;
|
||||
|
||||
//TimerPauseReg = 0;
|
||||
//while(TimerPauseReg < pause);
|
||||
}
|
||||
|
||||
void timer0ClearOverflowCount(void)
|
||||
{
|
||||
// clear the timer overflow counter registers
|
||||
Timer0Reg0 = 0; // initialize time registers
|
||||
}
|
||||
|
||||
long timer0GetOverflowCount(void)
|
||||
{
|
||||
// return the current timer overflow count
|
||||
// (this is since the last timer0ClearOverflowCount() command was called)
|
||||
return Timer0Reg0;
|
||||
}
|
||||
*/
|
||||
#ifdef TCNT2 // support timer2 only if it exists
|
||||
void timer2ClearOverflowCount(void)
|
||||
{
|
||||
// clear the timer overflow counter registers
|
||||
Timer2Reg0 = 0; // initialize time registers
|
||||
}
|
||||
/*
|
||||
long timer2GetOverflowCount(void)
|
||||
{
|
||||
// return the current timer overflow count
|
||||
// (this is since the last timer2ClearOverflowCount() command was called)
|
||||
return Timer2Reg0;
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
void timer1PWMInit(u08 bitRes)
|
||||
{
|
||||
// configures timer1 for use with PWM output
|
||||
// on OC1A and OC1B pins
|
||||
|
||||
// enable timer1 as 8,9,10bit PWM
|
||||
if(bitRes == 9)
|
||||
{ // 9bit mode
|
||||
sbi(TCCR1A,PWM11);
|
||||
cbi(TCCR1A,PWM10);
|
||||
}
|
||||
else if( bitRes == 10 )
|
||||
{ // 10bit mode
|
||||
sbi(TCCR1A,PWM11);
|
||||
sbi(TCCR1A,PWM10);
|
||||
}
|
||||
else
|
||||
{ // default 8bit mode
|
||||
cbi(TCCR1A,PWM11);
|
||||
sbi(TCCR1A,PWM10);
|
||||
}
|
||||
|
||||
// clear output compare value A
|
||||
outb(OCR1AH, 0);
|
||||
outb(OCR1AL, 0);
|
||||
// clear output compare value B
|
||||
outb(OCR1BH, 0);
|
||||
outb(OCR1BL, 0);
|
||||
}
|
||||
|
||||
#ifdef WGM10
|
||||
// include support for arbitrary top-count PWM
|
||||
// on new AVR processors that support it
|
||||
void timer1PWMInitICR(u16 topcount)
|
||||
{
|
||||
// set PWM mode with ICR top-count
|
||||
cbi(TCCR1A,WGM10);
|
||||
sbi(TCCR1A,WGM11);
|
||||
sbi(TCCR1B,WGM12);
|
||||
sbi(TCCR1B,WGM13);
|
||||
|
||||
// set top count value
|
||||
ICR1 = topcount;
|
||||
|
||||
// clear output compare value A
|
||||
OCR1A = 0;
|
||||
// clear output compare value B
|
||||
OCR1B = 0;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void timer1PWMOff(void)
|
||||
{
|
||||
// turn off timer1 PWM mode
|
||||
cbi(TCCR1A,PWM11);
|
||||
cbi(TCCR1A,PWM10);
|
||||
// set PWM1A/B (OutputCompare action) to none
|
||||
timer1PWMAOff();
|
||||
timer1PWMBOff();
|
||||
}
|
||||
|
||||
void timer1PWMAOn(void)
|
||||
{
|
||||
// turn on channel A (OC1A) PWM output
|
||||
// set OC1A as non-inverted PWM
|
||||
sbi(TCCR1A,COM1A1);
|
||||
cbi(TCCR1A,COM1A0);
|
||||
}
|
||||
|
||||
void timer1PWMBOn(void)
|
||||
{
|
||||
// turn on channel B (OC1B) PWM output
|
||||
// set OC1B as non-inverted PWM
|
||||
sbi(TCCR1A,COM1B1);
|
||||
cbi(TCCR1A,COM1B0);
|
||||
}
|
||||
|
||||
void timer1PWMAOff(void)
|
||||
{
|
||||
// turn off channel A (OC1A) PWM output
|
||||
// set OC1A (OutputCompare action) to none
|
||||
cbi(TCCR1A,COM1A1);
|
||||
cbi(TCCR1A,COM1A0);
|
||||
}
|
||||
|
||||
void timer1PWMBOff(void)
|
||||
{
|
||||
// turn off channel B (OC1B) PWM output
|
||||
// set OC1B (OutputCompare action) to none
|
||||
cbi(TCCR1A,COM1B1);
|
||||
cbi(TCCR1A,COM1B0);
|
||||
}
|
||||
|
||||
void timer1PWMASet(u16 pwmDuty)
|
||||
{
|
||||
// set PWM (output compare) duty for channel A
|
||||
// this PWM output is generated on OC1A pin
|
||||
// NOTE: pwmDuty should be in the range 0-255 for 8bit PWM
|
||||
// pwmDuty should be in the range 0-511 for 9bit PWM
|
||||
// pwmDuty should be in the range 0-1023 for 10bit PWM
|
||||
//outp( (pwmDuty>>8), OCR1AH); // set the high 8bits of OCR1A
|
||||
//outp( (pwmDuty&0x00FF), OCR1AL); // set the low 8bits of OCR1A
|
||||
OCR1A = pwmDuty;
|
||||
}
|
||||
|
||||
void timer1PWMBSet(u16 pwmDuty)
|
||||
{
|
||||
// set PWM (output compare) duty for channel B
|
||||
// this PWM output is generated on OC1B pin
|
||||
// NOTE: pwmDuty should be in the range 0-255 for 8bit PWM
|
||||
// pwmDuty should be in the range 0-511 for 9bit PWM
|
||||
// pwmDuty should be in the range 0-1023 for 10bit PWM
|
||||
//outp( (pwmDuty>>8), OCR1BH); // set the high 8bits of OCR1B
|
||||
//outp( (pwmDuty&0x00FF), OCR1BL); // set the low 8bits of OCR1B
|
||||
OCR1B = pwmDuty;
|
||||
}
|
||||
/*
|
||||
//! Interrupt handler for tcnt0 overflow interrupt
|
||||
TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW0)
|
||||
{
|
||||
Timer0Reg0++; // increment low-order counter
|
||||
|
||||
// increment pause counter
|
||||
TimerPauseReg++;
|
||||
|
||||
// if a user function is defined, execute it too
|
||||
if(TimerIntFunc[TIMER0OVERFLOW_INT])
|
||||
TimerIntFunc[TIMER0OVERFLOW_INT]();
|
||||
}
|
||||
*/
|
||||
//! Interrupt handler for tcnt1 overflow interrupt
|
||||
TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW1)
|
||||
{
|
||||
// if a user function is defined, execute it
|
||||
if(TimerIntFunc[TIMER1OVERFLOW_INT])
|
||||
TimerIntFunc[TIMER1OVERFLOW_INT]();
|
||||
}
|
||||
|
||||
#ifdef TCNT2 // support timer2 only if it exists
|
||||
//! Interrupt handler for tcnt2 overflow interrupt
|
||||
TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW2)
|
||||
{
|
||||
Timer2Reg0++; // increment low-order counter
|
||||
|
||||
// if a user function is defined, execute it
|
||||
if(TimerIntFunc[TIMER2OVERFLOW_INT])
|
||||
TimerIntFunc[TIMER2OVERFLOW_INT]();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OCR0
|
||||
/*
|
||||
// include support for Output Compare 0 for new AVR processors that support it
|
||||
//! Interrupt handler for OutputCompare0 match (OC0) interrupt
|
||||
TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE0)
|
||||
{
|
||||
// if a user function is defined, execute it
|
||||
if(TimerIntFunc[TIMER0OUTCOMPARE_INT])
|
||||
TimerIntFunc[TIMER0OUTCOMPARE_INT]();
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
//! Interrupt handler for CutputCompare1A match (OC1A) interrupt
|
||||
TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE1A)
|
||||
{
|
||||
// if a user function is defined, execute it
|
||||
if(TimerIntFunc[TIMER1OUTCOMPAREA_INT])
|
||||
TimerIntFunc[TIMER1OUTCOMPAREA_INT]();
|
||||
}
|
||||
|
||||
//! Interrupt handler for OutputCompare1B match (OC1B) interrupt
|
||||
TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE1B)
|
||||
{
|
||||
// if a user function is defined, execute it
|
||||
if(TimerIntFunc[TIMER1OUTCOMPAREB_INT])
|
||||
TimerIntFunc[TIMER1OUTCOMPAREB_INT]();
|
||||
}
|
||||
|
||||
//! Interrupt handler for InputCapture1 (IC1) interrupt
|
||||
TIMER_INTERRUPT_HANDLER(SIG_INPUT_CAPTURE1)
|
||||
{
|
||||
// if a user function is defined, execute it
|
||||
if(TimerIntFunc[TIMER1INPUTCAPTURE_INT])
|
||||
TimerIntFunc[TIMER1INPUTCAPTURE_INT]();
|
||||
}
|
||||
|
||||
//! Interrupt handler for OutputCompare2 match (OC2) interrupt
|
||||
TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE2)
|
||||
{
|
||||
// if a user function is defined, execute it
|
||||
if(TimerIntFunc[TIMER2OUTCOMPARE_INT])
|
||||
TimerIntFunc[TIMER2OUTCOMPARE_INT]();
|
||||
}
|
@ -1,278 +0,0 @@
|
||||
/*! \file timer.h \brief System Timer function library. */
|
||||
//*****************************************************************************
|
||||
//
|
||||
// File Name : 'timer.h'
|
||||
// Title : System Timer function library
|
||||
// Author : Pascal Stang - Copyright (C) 2000-2002
|
||||
// Created : 11/22/2000
|
||||
// Revised : 02/10/2003
|
||||
// Version : 1.1
|
||||
// Target MCU : Atmel AVR Series
|
||||
// Editor Tabs : 4
|
||||
//
|
||||
// This code is distributed under the GNU Public License
|
||||
// which can be found at http://www.gnu.org/licenses/gpl.txt
|
||||
//
|
||||
//
|
||||
// Notes: The Atmel AVR Series Processors each contain at least one
|
||||
// hardware timer/counter. Many of the processors contain 2 or 3
|
||||
// timers. Generally speaking, a timer is a hardware counter inside
|
||||
// the processor which counts at a rate related to the main CPU clock
|
||||
// frequency. Because the counter value increasing (counting up) at
|
||||
// a precise rate, we can use it as a timer to create or measure
|
||||
// precise delays, schedule events, or generate signals of a certain
|
||||
// frequency or pulse-width.
|
||||
// As an example, the ATmega163 processor has 3 timer/counters.
|
||||
// Timer0, Timer1, and Timer2 are 8, 16, and 8 bits wide respectively.
|
||||
// This means that they overflow, or roll over back to zero, at a
|
||||
// count value of 256 for 8bits or 65536 for 16bits. A prescaler is
|
||||
// avaiable for each timer, and the prescaler allows you to pre-divide
|
||||
// the main CPU clock rate down to a slower speed before feeding it to
|
||||
// the counting input of a timer. For example, if the CPU clock
|
||||
// frequency is 3.69MHz, and Timer0's prescaler is set to divide-by-8,
|
||||
// then Timer0 will "tic" at 3690000/8 = 461250Hz. Because Timer0 is
|
||||
// an 8bit timer, it will count to 256 in just 256/461250Hz = 0.555ms.
|
||||
// In fact, when it hits 255, it will overflow and start again at
|
||||
// zero. In this case, Timer0 will overflow 461250/256 = 1801.76
|
||||
// times per second.
|
||||
// Timer0 can be used a number of ways simultaneously. First, the
|
||||
// value of the timer can be read by accessing the CPU register TCNT0.
|
||||
// We could, for example, figure out how long it takes to execute a
|
||||
// C command by recording the value of TCNT0 before and after
|
||||
// execution, then subtract (after-before) = time elapsed. Or we can
|
||||
// enable the overflow interrupt which goes off every time T0
|
||||
// overflows and count out longer delays (multiple overflows), or
|
||||
// execute a special periodic function at every overflow.
|
||||
// The other timers (Timer1 and Timer2) offer all the abilities of
|
||||
// Timer0 and many more features. Both T1 and T2 can operate as
|
||||
// general-purpose timers, but T1 has special hardware allowing it to
|
||||
// generate PWM signals, while T2 is specially designed to help count
|
||||
// out real time (like hours, minutes, seconds). See the
|
||||
// Timer/Counter section of the processor datasheet for more info.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
#include "global.h"
|
||||
|
||||
// constants/macros/typdefs
|
||||
|
||||
// processor compatibility fixes
|
||||
#ifdef __AVR_ATmega323__
|
||||
// redefinition for the Mega323
|
||||
#define CTC1 CTC10
|
||||
#endif
|
||||
#ifndef PWM10
|
||||
// mega128 PWM bits
|
||||
#define PWM10 WGM10
|
||||
#define PWM11 WGM11
|
||||
#endif
|
||||
|
||||
// Timer/clock prescaler values and timer overflow rates
|
||||
// tics = rate at which the timer counts up
|
||||
// 8bitoverflow = rate at which the timer overflows 8bits (or reaches 256)
|
||||
// 16bit [overflow] = rate at which the timer overflows 16bits (65536)
|
||||
//
|
||||
// overflows can be used to generate periodic interrupts
|
||||
//
|
||||
// for 8MHz crystal
|
||||
// 0 = STOP (Timer not counting)
|
||||
// 1 = CLOCK tics= 8MHz 8bitoverflow= 31250Hz 16bit= 122.070Hz
|
||||
// 2 = CLOCK/8 tics= 1MHz 8bitoverflow= 3906.25Hz 16bit= 15.259Hz
|
||||
// 3 = CLOCK/64 tics= 125kHz 8bitoverflow= 488.28Hz 16bit= 1.907Hz
|
||||
// 4 = CLOCK/256 tics= 31250Hz 8bitoverflow= 122.07Hz 16bit= 0.477Hz
|
||||
// 5 = CLOCK/1024 tics= 7812.5Hz 8bitoverflow= 30.52Hz 16bit= 0.119Hz
|
||||
// 6 = External Clock on T(x) pin (falling edge)
|
||||
// 7 = External Clock on T(x) pin (rising edge)
|
||||
|
||||
// for 4MHz crystal
|
||||
// 0 = STOP (Timer not counting)
|
||||
// 1 = CLOCK tics= 4MHz 8bitoverflow= 15625Hz 16bit= 61.035Hz
|
||||
// 2 = CLOCK/8 tics= 500kHz 8bitoverflow= 1953.125Hz 16bit= 7.629Hz
|
||||
// 3 = CLOCK/64 tics= 62500Hz 8bitoverflow= 244.141Hz 16bit= 0.954Hz
|
||||
// 4 = CLOCK/256 tics= 15625Hz 8bitoverflow= 61.035Hz 16bit= 0.238Hz
|
||||
// 5 = CLOCK/1024 tics= 3906.25Hz 8bitoverflow= 15.259Hz 16bit= 0.060Hz
|
||||
// 6 = External Clock on T(x) pin (falling edge)
|
||||
// 7 = External Clock on T(x) pin (rising edge)
|
||||
|
||||
// for 3.69MHz crystal
|
||||
// 0 = STOP (Timer not counting)
|
||||
// 1 = CLOCK tics= 3.69MHz 8bitoverflow= 14414Hz 16bit= 56.304Hz
|
||||
// 2 = CLOCK/8 tics= 461250Hz 8bitoverflow= 1801.758Hz 16bit= 7.038Hz
|
||||
// 3 = CLOCK/64 tics= 57625.25Hz 8bitoverflow= 225.220Hz 16bit= 0.880Hz
|
||||
// 4 = CLOCK/256 tics= 14414.063Hz 8bitoverflow= 56.305Hz 16bit= 0.220Hz
|
||||
// 5 = CLOCK/1024 tics= 3603.516Hz 8bitoverflow= 14.076Hz 16bit= 0.055Hz
|
||||
// 6 = External Clock on T(x) pin (falling edge)
|
||||
// 7 = External Clock on T(x) pin (rising edge)
|
||||
|
||||
// for 32.768KHz crystal on timer 2 (use for real-time clock)
|
||||
// 0 = STOP
|
||||
// 1 = CLOCK tics= 32.768kHz 8bitoverflow= 128Hz
|
||||
// 2 = CLOCK/8 tics= 4096kHz 8bitoverflow= 16Hz
|
||||
// 3 = CLOCK/32 tics= 1024kHz 8bitoverflow= 4Hz
|
||||
// 4 = CLOCK/64 tics= 512Hz 8bitoverflow= 2Hz
|
||||
// 5 = CLOCK/128 tics= 256Hz 8bitoverflow= 1Hz
|
||||
// 6 = CLOCK/256 tics= 128Hz 8bitoverflow= 0.5Hz
|
||||
// 7 = CLOCK/1024 tics= 32Hz 8bitoverflow= 0.125Hz
|
||||
|
||||
#define TIMER_CLK_STOP 0x00 ///< Timer Stopped
|
||||
#define TIMER_CLK_DIV1 0x01 ///< Timer clocked at F_CPU
|
||||
#define TIMER_CLK_DIV8 0x02 ///< Timer clocked at F_CPU/8
|
||||
#define TIMER_CLK_DIV64 0x03 ///< Timer clocked at F_CPU/64
|
||||
#define TIMER_CLK_DIV256 0x04 ///< Timer clocked at F_CPU/256
|
||||
#define TIMER_CLK_DIV1024 0x05 ///< Timer clocked at F_CPU/1024
|
||||
#define TIMER_CLK_T_FALL 0x06 ///< Timer clocked at T falling edge
|
||||
#define TIMER_CLK_T_RISE 0x07 ///< Timer clocked at T rising edge
|
||||
#define TIMER_PRESCALE_MASK 0x07 ///< Timer Prescaler Bit-Mask
|
||||
|
||||
#define TIMERRTC_CLK_STOP 0x00 ///< RTC Timer Stopped
|
||||
#define TIMERRTC_CLK_DIV1 0x01 ///< RTC Timer clocked at F_CPU
|
||||
#define TIMERRTC_CLK_DIV8 0x02 ///< RTC Timer clocked at F_CPU/8
|
||||
#define TIMERRTC_CLK_DIV32 0x03 ///< RTC Timer clocked at F_CPU/32
|
||||
#define TIMERRTC_CLK_DIV64 0x04 ///< RTC Timer clocked at F_CPU/64
|
||||
#define TIMERRTC_CLK_DIV128 0x05 ///< RTC Timer clocked at F_CPU/128
|
||||
#define TIMERRTC_CLK_DIV256 0x06 ///< RTC Timer clocked at F_CPU/256
|
||||
#define TIMERRTC_CLK_DIV1024 0x07 ///< RTC Timer clocked at F_CPU/1024
|
||||
#define TIMERRTC_PRESCALE_MASK 0x07 ///< RTC Timer Prescaler Bit-Mask
|
||||
|
||||
// default prescale settings for the timers
|
||||
// these settings are applied when you call
|
||||
// timerInit or any of the timer<x>Init
|
||||
#define TIMER0PRESCALE TIMER_CLK_DIV8 ///< timer 0 prescaler default
|
||||
#define TIMER1PRESCALE TIMER_CLK_DIV64 ///< timer 1 prescaler default
|
||||
#define TIMER2PRESCALE TIMERRTC_CLK_DIV64 ///< timer 2 prescaler default
|
||||
|
||||
// interrupt macros for attaching user functions to timer interrupts
|
||||
// use these with timerAttach( intNum, function )
|
||||
#define TIMER0OVERFLOW_INT 0
|
||||
#define TIMER1OVERFLOW_INT 1
|
||||
#define TIMER1OUTCOMPAREA_INT 2
|
||||
#define TIMER1OUTCOMPAREB_INT 3
|
||||
#define TIMER1INPUTCAPTURE_INT 4
|
||||
#define TIMER2OVERFLOW_INT 5
|
||||
#define TIMER2OUTCOMPARE_INT 6
|
||||
#ifdef OCR0 // for processors that support output compare on Timer0
|
||||
#define TIMER0OUTCOMPARE_INT 7
|
||||
#define TIMER_NUM_INTERRUPTS 8
|
||||
#else
|
||||
#define TIMER_NUM_INTERRUPTS 7
|
||||
#endif
|
||||
|
||||
// default type of interrupt handler to use for timers
|
||||
// *do not change unless you know what you're doing
|
||||
// Value may be SIGNAL or INTERRUPT
|
||||
#ifndef TIMER_INTERRUPT_HANDLER
|
||||
#define TIMER_INTERRUPT_HANDLER SIGNAL
|
||||
#endif
|
||||
|
||||
// functions
|
||||
#define delay delay_us
|
||||
#define delay_ms timerPause
|
||||
void delay_us(unsigned short time_us);
|
||||
|
||||
//! initializes timing system (all timers)
|
||||
// runs all timer init functions
|
||||
// sets all timers to default prescale values #defined in systimer.c
|
||||
void timerInit(void);
|
||||
|
||||
// default initialization routines for each timer
|
||||
void timer0Init(void); ///< initialize timer0
|
||||
void timer1Init(void); ///< initialize timer1
|
||||
#ifdef TCNT2 // support timer2 only if it exists
|
||||
void timer2Init(void); ///< initialize timer2
|
||||
#endif
|
||||
|
||||
// Clock prescaler set/get commands for each timer/counter
|
||||
// For setting the prescaler, you should use one of the #defines
|
||||
// above like TIMER_CLK_DIVx, where [x] is the division rate
|
||||
// you want.
|
||||
// When getting the current prescaler setting, the return value
|
||||
// will be the [x] division value currently set.
|
||||
void timer0SetPrescaler(u08 prescale); ///< set timer0 prescaler
|
||||
u16 timer0GetPrescaler(void); ///< get timer0 prescaler
|
||||
void timer1SetPrescaler(u08 prescale); ///< set timer1 prescaler
|
||||
u16 timer1GetPrescaler(void); ///< get timer0 prescaler
|
||||
#ifdef TCNT2 // support timer2 only if it exists
|
||||
void timer2SetPrescaler(u08 prescale); ///< set timer2 prescaler
|
||||
u16 timer2GetPrescaler(void); ///< get timer2 prescaler
|
||||
#endif
|
||||
|
||||
|
||||
// TimerAttach and Detach commands
|
||||
// These functions allow the attachment (or detachment) of any user function
|
||||
// to a timer interrupt. "Attaching" one of your own functions to a timer
|
||||
// interrupt means that it will be called whenever that interrupt happens.
|
||||
// Using attach is better than rewriting the actual INTERRUPT() function
|
||||
// because your code will still work and be compatible if the timer library
|
||||
// is updated. Also, using Attach allows your code and any predefined timer
|
||||
// code to work together and at the same time. (ie. "attaching" your own
|
||||
// function to the timer0 overflow doesn't prevent timerPause from working,
|
||||
// but rather allows you to share the interrupt.)
|
||||
//
|
||||
// timerAttach(TIMER1OVERFLOW_INT, myOverflowFunction);
|
||||
// timerDetach(TIMER1OVERFLOW_INT)
|
||||
//
|
||||
// timerAttach causes the myOverflowFunction() to be attached, and therefore
|
||||
// execute, whenever an overflow on timer1 occurs. timerDetach removes the
|
||||
// association and executes no user function when the interrupt occurs.
|
||||
// myOverflowFunction must be defined with no return value and no arguments:
|
||||
//
|
||||
// void myOverflowFunction(void) { ... }
|
||||
|
||||
//! Attach a user function to a timer interrupt
|
||||
void timerAttach(u08 interruptNum, void (*userFunc)(void) );
|
||||
//! Detach a user function from a timer interrupt
|
||||
void timerDetach(u08 interruptNum);
|
||||
|
||||
|
||||
// timing commands
|
||||
//! timerPause pauses for the number of milliseconds specified in <pause_ms>
|
||||
void timerPause(unsigned short pause_ms);
|
||||
|
||||
// overflow counters
|
||||
void timer0ClearOverflowCount(void); ///< clear timer0's overflow counter
|
||||
long timer0GetOverflowCount(void); ///< read timer0's overflow counter
|
||||
#ifdef TCNT2 // support timer2 only if it exists
|
||||
void timer2ClearOverflowCount(void); ///< clear timer2's overflow counter
|
||||
long timer2GetOverflowCount(void); ///< read timer0's overflow counter
|
||||
#endif
|
||||
|
||||
// PWM initialization and set commands for timer1
|
||||
// timer1PWMInit()
|
||||
// configures the timer1 hardware for PWM mode on pins OC1A and OC1B.
|
||||
// bitRes should be 8,9,or 10 for 8,9,or 10bit PWM resolution
|
||||
//
|
||||
// timer1PWMOff()
|
||||
// turns off all timer1 PWM output and set timer mode to normal state
|
||||
//
|
||||
// timer1PWMAOn() and timer1PWMBOn()
|
||||
// turn on output of PWM signals to OC1A or OC1B pins
|
||||
// NOTE: Until you define the OC1A and OC1B pins as outputs, and run
|
||||
// this "on" command, no PWM output will be output
|
||||
//
|
||||
// timer1PWMAOff() and timer1PWMBOff()
|
||||
// turn off output of PWM signals to OC1A or OC1B pins
|
||||
//
|
||||
// timer1PWMASet() and timer1PWMBSet()
|
||||
// sets the PWM duty cycle for each channel
|
||||
// NOTE: <pwmDuty> should be in the range 0-255 for 8bit PWM
|
||||
// <pwmDuty> should be in the range 0-511 for 9bit PWM
|
||||
// <pwmDuty> should be in the range 0-1023 for 10bit PWM
|
||||
// NOTE: the PWM frequency can be controlled in increments by setting the
|
||||
// prescaler for timer1
|
||||
|
||||
void timer1PWMInit(u08 bitRes); ///< initialize and set timer1 mode to PWM
|
||||
void timer1PWMInitICR(u16 topcount);///< initialize and set timer1 mode to PWM with specific top count
|
||||
void timer1PWMOff(void); ///< turn off all timer1 PWM output and set timer mode to normal
|
||||
void timer1PWMAOn(void); ///< turn on timer1 Channel A (OC1A) PWM output
|
||||
void timer1PWMBOn(void); ///< turn on timer1 Channel B (OC1B) PWM output
|
||||
void timer1PWMAOff(void); ///< turn off timer1 Channel A (OC1A) PWM output
|
||||
void timer1PWMBOff(void); ///< turn off timer1 Channel B (OC1B) PWM output
|
||||
void timer1PWMASet(u16 pwmDuty); ///< set duty of timer1 Channel A (OC1A) PWM output
|
||||
void timer1PWMBSet(u16 pwmDuty); ///< set duty of timer1 Channel B (OC1B) PWM output
|
||||
|
||||
// Pulse generation commands have been moved to the pulse.c library
|
||||
|
||||
#endif
|
@ -37,15 +37,8 @@
|
||||
#endif
|
||||
|
||||
// from Pascal's avrlib
|
||||
#include "global.h"
|
||||
//#include "a2d.h"
|
||||
#include "timer.h"
|
||||
#include "uart.h"
|
||||
|
||||
// timer.h #defines delay to be delay_us, we need to undefine
|
||||
// it so our delay can be in milliseconds.
|
||||
#undef delay
|
||||
|
||||
#include "wiring.h"
|
||||
|
||||
// The number of times timer 0 has overflowed since the program started.
|
||||
@ -66,14 +59,9 @@ int digitalPinToBit(int pin)
|
||||
return digital_pin_to_port[pin].bit;
|
||||
}
|
||||
|
||||
int analogOutPinToPort(int pin)
|
||||
int analogOutPinToTimer(int pin)
|
||||
{
|
||||
return analog_out_pin_to_port[pin].port;
|
||||
}
|
||||
|
||||
int analogOutPinToBit(int pin)
|
||||
{
|
||||
return analog_out_pin_to_port[pin].bit;
|
||||
return analog_out_pin_to_timer[pin];
|
||||
}
|
||||
|
||||
int analogInPinToBit(int pin)
|
||||
@ -81,26 +69,6 @@ int analogInPinToBit(int pin)
|
||||
return analog_in_pin_to_port[pin].bit;
|
||||
}
|
||||
|
||||
void timer2PWMOn()
|
||||
{
|
||||
// configure timer 2 for normal (non-inverting) pwm operation
|
||||
// this attaches the timer to the pwm pin
|
||||
sbi(TCCR2, COM21);
|
||||
cbi(TCCR2, COM20);
|
||||
}
|
||||
|
||||
void timer2PWMOff()
|
||||
{
|
||||
// disconnect the timer from the pwm pin
|
||||
cbi(TCCR2, COM21);
|
||||
cbi(TCCR2, COM20);
|
||||
}
|
||||
|
||||
void timer2PWMSet(unsigned char val)
|
||||
{
|
||||
OCR2 = val;
|
||||
}
|
||||
|
||||
void pinMode(int pin, int mode)
|
||||
{
|
||||
if (digitalPinToPort(pin) != NOT_A_PIN) {
|
||||
@ -119,14 +87,22 @@ void digitalWrite(int pin, int val)
|
||||
// If the pin that support PWM output, we need to turn it off
|
||||
// before doing a digital write.
|
||||
|
||||
if (analogOutPinToBit(pin) == 1)
|
||||
timer1PWMAOff();
|
||||
if (analogOutPinToTimer(pin) == TIMER1A)
|
||||
cbi(TCCR1A, COM1A1);
|
||||
|
||||
if (analogOutPinToBit(pin) == 2)
|
||||
timer1PWMBOff();
|
||||
|
||||
if (analogOutPinToBit(pin) == 3)
|
||||
timer2PWMOff();
|
||||
if (analogOutPinToTimer(pin) == TIMER1B)
|
||||
cbi(TCCR1A, COM1B1);
|
||||
|
||||
#if defined(__AVR_ATmega168__)
|
||||
if (analogOutPinToTimer(pin) == TIMER2A)
|
||||
cbi(TCCR2A, COM2A1);
|
||||
|
||||
if (analogOutPinToTimer(pin) == TIMER2B)
|
||||
cbi(TCCR2A, COM2B1);
|
||||
#else
|
||||
if (analogOutPinToTimer(pin) == TIMER2)
|
||||
cbi(TCCR2, COM21);
|
||||
#endif
|
||||
|
||||
if (val == LOW)
|
||||
cbi(_SFR_IO8(port_to_output[digitalPinToPort(pin)]),
|
||||
@ -143,14 +119,22 @@ int digitalRead(int pin)
|
||||
// If the pin that support PWM output, we need to turn it off
|
||||
// before getting a digital reading.
|
||||
|
||||
if (analogOutPinToBit(pin) == 1)
|
||||
timer1PWMAOff();
|
||||
if (analogOutPinToTimer(pin) == TIMER1A)
|
||||
cbi(TCCR1A, COM1A1);
|
||||
|
||||
if (analogOutPinToBit(pin) == 2)
|
||||
timer1PWMBOff();
|
||||
|
||||
if (analogOutPinToBit(pin) == 3)
|
||||
timer2PWMOff();
|
||||
if (analogOutPinToTimer(pin) == TIMER1B)
|
||||
cbi(TCCR1A, COM1B1);
|
||||
|
||||
#if defined(__AVR_ATmega168__)
|
||||
if (analogOutPinToTimer(pin) == TIMER2A)
|
||||
cbi(TCCR2A, COM2A1);
|
||||
|
||||
if (analogOutPinToTimer(pin) == TIMER2B)
|
||||
cbi(TCCR2A, COM2B1);
|
||||
#else
|
||||
if (analogOutPinToTimer(pin) == TIMER2)
|
||||
cbi(TCCR2, COM21);
|
||||
#endif
|
||||
|
||||
return (_SFR_IO8(port_to_input[digitalPinToPort(pin)]) >>
|
||||
digitalPinToBit(pin)) & 0x01;
|
||||
@ -197,18 +181,36 @@ void analogWrite(int pin, int val)
|
||||
// writing with them. Also, make sure the pin is in output mode
|
||||
// for consistenty with Wiring, which doesn't require a pinMode
|
||||
// call for the analog output pins.
|
||||
if (analogOutPinToBit(pin) == 1) {
|
||||
pinMode(pin, OUTPUT);
|
||||
timer1PWMAOn();
|
||||
timer1PWMASet(val);
|
||||
} else if (analogOutPinToBit(pin) == 2) {
|
||||
pinMode(pin, OUTPUT);
|
||||
timer1PWMBOn();
|
||||
timer1PWMBSet(val);
|
||||
} else if (analogOutPinToBit(pin) == 3) {
|
||||
pinMode(pin, OUTPUT);
|
||||
timer2PWMOn();
|
||||
timer2PWMSet(val);
|
||||
pinMode(pin, OUTPUT);
|
||||
|
||||
if (analogOutPinToTimer(pin) == TIMER1A) {
|
||||
// connect pwm to pin on timer 1, channel A
|
||||
sbi(TCCR1A, COM1A1);
|
||||
// set pwm duty
|
||||
OCR1A = val;
|
||||
} else if (analogOutPinToTimer(pin) == TIMER1B) {
|
||||
// connect pwm to pin on timer 1, channel B
|
||||
sbi(TCCR1A, COM1B1);
|
||||
// set pwm duty
|
||||
OCR1B = val;
|
||||
#if defined(__AVR_ATmega168__)
|
||||
} else if (analogOutPinToTimer(pin) == TIMER2A) {
|
||||
// connect pwm to pin on timer 2, channel A
|
||||
sbi(TCCR2A, COM2A1);
|
||||
// set pwm duty
|
||||
OCR2A = val;
|
||||
} else if (analogOutPinToTimer(pin) == TIMER2B) {
|
||||
// connect pwm to pin on timer 2, channel B
|
||||
sbi(TCCR2A, COM2B1);
|
||||
// set pwm duty
|
||||
OCR2B = val;
|
||||
#else
|
||||
} else if (analogOutPinToTimer(pin) == TIMER2) {
|
||||
// connect pwm to pin on timer 2, channel B
|
||||
sbi(TCCR2, COM21);
|
||||
// set pwm duty
|
||||
OCR2 = val;
|
||||
#endif
|
||||
} else if (val < 128)
|
||||
digitalWrite(pin, LOW);
|
||||
else
|
||||
@ -319,7 +321,7 @@ void print(const char *format, ...)
|
||||
}
|
||||
*/
|
||||
|
||||
TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW0)
|
||||
SIGNAL(SIG_OVERFLOW0)
|
||||
{
|
||||
timer0_overflow_count++;
|
||||
}
|
||||
@ -434,30 +436,47 @@ unsigned long pulseIn(int pin, int state)
|
||||
int main(void)
|
||||
{
|
||||
// this needs to be called before setup() or some functions won't
|
||||
// work there
|
||||
// work there
|
||||
sei();
|
||||
|
||||
// timer 0 is used for millis() and delay()
|
||||
//timer0Init();
|
||||
timer0_overflow_count = 0;
|
||||
// set timer 0 prescale factor to 8
|
||||
#if defined(__AVR_ATmega168__)
|
||||
sbi(TCCR0B, CS01);
|
||||
#else
|
||||
sbi(TCCR0, CS01);
|
||||
#endif
|
||||
// enable timer 0 overflow interrupt
|
||||
#if defined(__AVR_ATmega168__)
|
||||
sbi(TIMSK0, TOIE0);
|
||||
#else
|
||||
sbi(TIMSK, TOIE0);
|
||||
#endif
|
||||
|
||||
// timers 1 & 2 are used for the hardware pwm
|
||||
timer1Init();
|
||||
//timer1SetPrescaler(TIMER_CLK_DIV1);
|
||||
timer1PWMInit(8);
|
||||
|
||||
timer2Init();
|
||||
|
||||
// configure timer 2 for phase correct pwm
|
||||
// timers 1 and 2 are used for phase-correct hardware pwm
|
||||
// this is better for motors as it ensures an even waveform
|
||||
// note, however, that fast pwm mode can achieve a frequency of up
|
||||
// 8 MHz (with a 16 MHz clock) at 50% duty cycle
|
||||
cbi(TCCR2, WGM21);
|
||||
|
||||
// set timer 1 prescale factor to 64
|
||||
sbi(TCCR1B, CS11);
|
||||
sbi(TCCR1B, CS10);
|
||||
// put timer 1 in 8-bit phase correct pwm mode
|
||||
sbi(TCCR1A, WGM10);
|
||||
|
||||
// set timer 2 prescale factor to 64
|
||||
#if defined(__AVR_ATmega168__)
|
||||
sbi(TCCR2B, CS22);
|
||||
#else
|
||||
sbi(TCCR2, CS22);
|
||||
#endif
|
||||
// configure timer 2 for phase correct pwm (8-bit)
|
||||
#if defined(__AVR_ATmega168__)
|
||||
sbi(TCCR2A, WGM20);
|
||||
#else
|
||||
sbi(TCCR2, WGM20);
|
||||
#endif
|
||||
|
||||
// set a2d reference to AVCC (5 volts)
|
||||
cbi(ADMUX, REFS1);
|
||||
|
@ -89,6 +89,15 @@ void loop(void);
|
||||
#define NOT_A_PIN 0
|
||||
#define NOT_A_PORT -1
|
||||
|
||||
#define NOT_ON_TIMER -1
|
||||
#define TIMER0A 0
|
||||
#define TIMER0B 1
|
||||
#define TIMER1A 2
|
||||
#define TIMER1B 3
|
||||
#define TIMER2 4
|
||||
#define TIMER2A 5
|
||||
#define TIMER2B 6
|
||||
|
||||
typedef struct {
|
||||
int port;
|
||||
int bit;
|
||||
@ -99,7 +108,7 @@ extern int port_to_input[];
|
||||
extern int port_to_output[];
|
||||
extern pin_t *digital_pin_to_port;
|
||||
extern pin_t *analog_in_pin_to_port;
|
||||
extern pin_t *analog_out_pin_to_port;
|
||||
extern int *analog_out_pin_to_timer;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
Loading…
x
Reference in New Issue
Block a user