Main Page   Data Structures   File List   Data Fields   Globals  

/pulse.c

Go to the documentation of this file.
00001 /*! \file pulse.c \brief Pulse/frequency generation function library. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'pulse.c'
00005 // Title        : Pulse/frequency generation function library
00006 // Author       : Pascal Stang - Copyright (C) 2000-2002
00007 // Created      : 2002-08-19
00008 // Revised      : 2003-05-29
00009 // Version      : 0.7
00010 // Target MCU   : Atmel AVR Series
00011 // Editor Tabs  : 4
00012 //
00013 // This code is distributed under the GNU Public License
00014 //      which can be found at http://www.gnu.org/licenses/gpl.txt
00015 //
00016 //*****************************************************************************
00017 
00018 #ifndef WIN32
00019     #include <avr/io.h>
00020     #include <avr/signal.h>
00021     #include <avr/interrupt.h>
00022     #include <avr/pgmspace.h>
00023 #endif
00024 
00025 #include "global.h"
00026 #include "timer.h"
00027 #include "pulse.h"
00028 
00029 // Global variables
00030 extern short __attribute__ ((progmem)) TimerPrescaleFactor[];
00031 // pulse generation registers
00032 volatile static unsigned char  PulseT1AMode;
00033 volatile static unsigned short PulseT1ACount;
00034 volatile static unsigned short PulseT1APeriodTics;
00035 volatile static unsigned char  PulseT1BMode;
00036 volatile static unsigned short PulseT1BCount;
00037 volatile static unsigned short PulseT1BPeriodTics;
00038 
00039 // pulse mode bit definitions
00040 // PULSE_MODE_COUNTED
00041 //      if true, the requested number of pulses are output, then output is turned off
00042 //      if false, pulses are output continuously
00043 #define PULSE_MODE_COUNTED      0x01
00044 
00045 // functions
00046 
00047 void pulseInit(void)
00048 {
00049     // initialize timer1 for pulse operation
00050     pulseT1Init();
00051 }
00052 
00053 void pulseT1Init(void)
00054 {
00055     // try to make sure that timer1 is in "normal" mode
00056     // most importantly, turn off PWM mode
00057     timer1PWMOff();
00058 
00059     // set some reasonable initial values
00060     // in case the user forgets to
00061     PulseT1AMode = 0;
00062     PulseT1BMode = 0;
00063     PulseT1ACount = 0;
00064     PulseT1BCount = 0;
00065     PulseT1APeriodTics = 0x8000;
00066     PulseT1BPeriodTics = 0x8000;
00067 
00068     // attach the pulse service routines to
00069     // the timer 1 output compare A and B interrupts
00070     timerAttach(TIMER1OUTCOMPAREA_INT,pulseT1AService);
00071     timerAttach(TIMER1OUTCOMPAREB_INT,pulseT1BService);
00072 }
00073 
00074 void pulseT1Off(void)
00075 {
00076     // turns pulse outputs off immediately
00077     
00078     // set pulse counters to zero (finished)
00079     PulseT1ACount = 0;
00080     PulseT1BCount = 0;
00081     // disconnect OutputCompare action from OC1A pin
00082     cbi(TCCR1A,COM1A1);
00083     cbi(TCCR1A,COM1A0);
00084     // disconnect OutputCompare action from OC1B pin
00085     cbi(TCCR1A,COM1B1);
00086     cbi(TCCR1A,COM1B0);
00087     // detach the pulse service routines
00088     timerDetach(TIMER1OUTCOMPAREA_INT);
00089     timerDetach(TIMER1OUTCOMPAREB_INT);
00090 }
00091 
00092 void pulseT1ASetFreq(u16 freqHz)
00093 {
00094     // set the frequency of the pulse output
00095     // we need to find the requested period/2 (in timer tics)
00096     // from the frequency (in hertz)
00097 
00098     // get the current prescaler setting
00099     u16 prescaleDiv = 1<<(PRG_RDB(TimerPrescaleFactor+(inp(TCCR1B) & TIMER_PRESCALE_MASK)));
00100     // calculate how many tics in period/2
00101     // this is the (timer tic rate)/(2*requested freq)
00102     PulseT1APeriodTics = ((u32)F_CPU/((u32)prescaleDiv*2*freqHz));
00103 }
00104 
00105 void pulseT1BSetFreq(u16 freqHz)
00106 {
00107     // set the frequency of the pulse output
00108     // we need to find the requested period/2 (in timer tics)
00109     // from the frequency (in hertz)
00110 
00111     // get the current prescaler setting
00112     u16 prescaleDiv = 1<<(PRG_RDB(TimerPrescaleFactor+(inp(TCCR1B) & TIMER_PRESCALE_MASK)));
00113     // calculate how many tics in period/2
00114     // this is the (timer tic rate)/(2*requested freq)
00115     PulseT1BPeriodTics = ((u32)F_CPU/((u32)prescaleDiv*2*freqHz));
00116 }
00117 
00118 void pulseT1ARun(u16 nPulses)
00119 {
00120     // set the number of pulses we want and the mode
00121     if(nPulses)
00122     {
00123         // if the nPulses is non-zero, use "counted" mode
00124         PulseT1AMode |= PULSE_MODE_COUNTED;
00125         PulseT1ACount = nPulses<<1;
00126     }
00127     else
00128     {
00129         // if nPulses is zero, run forever
00130         PulseT1AMode &= ~PULSE_MODE_COUNTED;
00131         PulseT1ACount = 1<<1;
00132     }
00133     // set OutputCompare action to toggle OC1A pin
00134     cbi(TCCR1A,COM1A1);
00135     sbi(TCCR1A,COM1A0);
00136 
00137     // now the "enabling" stuff
00138 
00139     // set the output compare one pulse cycle ahead of current timer position 
00140     // to make sure we don't have to wait until the timer overflows and comes
00141     // back to the current value
00142     // set future output compare time to TCNT1 + PulseT1APeriodTics
00143     outw(OCR1A, inw(TCNT1) + PulseT1APeriodTics);
00144 
00145     // enable OutputCompare interrupt
00146     sbi(TIMSK, OCIE1A);
00147 }
00148 
00149 void pulseT1BRun(u16 nPulses)
00150 {
00151     // set the number of pulses we want and the mode
00152     if(nPulses)
00153     {
00154         // if the nPulses is non-zero, use "counted" mode
00155         PulseT1BMode |= PULSE_MODE_COUNTED;
00156         PulseT1BCount = nPulses<<1;
00157     }
00158     else
00159     {
00160         // if nPulses is zero, run forever
00161         PulseT1BMode &= ~PULSE_MODE_COUNTED;
00162         PulseT1BCount = 1<<1;
00163     }
00164     // set OutputCompare action to toggle OC1B pin
00165     // (note: with all the A's and B's flying around, TCCR1A is not a bug)
00166     cbi(TCCR1A,COM1B1);
00167     sbi(TCCR1A,COM1B0);
00168 
00169     // now the "enabling" stuff
00170 
00171     // set the output compare one pulse cycle ahead of current timer position 
00172     // to make sure we don't have to wait until the timer overflows and comes
00173     // back to the current value
00174     // set future output compare time to TCNT1 + PulseT1APeriodTics
00175     outw(OCR1B, inw(TCNT1) + PulseT1BPeriodTics);
00176 
00177     // enable OutputCompare interrupt
00178     sbi(TIMSK, OCIE1B);
00179 }
00180 
00181 void pulseT1AStop(void)
00182 {
00183     // stop output regardless of remaining pulses or mode
00184     // go to "counted" mode
00185     PulseT1AMode |= PULSE_MODE_COUNTED;
00186     // set pulses to zero
00187     PulseT1ACount = 0;
00188 }
00189 
00190 void pulseT1BStop(void)
00191 {
00192     // stop output regardless of remaining pulses or mode
00193     // go to "counted" mode
00194     PulseT1BMode |= PULSE_MODE_COUNTED;
00195     // set pulses to zero
00196     PulseT1BCount = 0;
00197 }
00198 
00199 u16 pulseT1ARemaining(void)
00200 {
00201     // return the number of pulses remaining for channel A
00202     // add 1 to make sure we round up, >>1 equivalent to /2
00203     return (PulseT1ACount+1)>>1;
00204 }
00205 
00206 u16 pulseT1BRemaining(void)
00207 {
00208     // return the number of pulses remaining for channel A
00209     // add 1 to make sure we round up, >>1 equivalent to /2
00210     return (PulseT1BCount+1)>>1;
00211 }
00212 
00213 void pulseT1AService(void)
00214 {
00215     // check if TimerPulseACount is non-zero
00216     //      (i.e. pulses are still requested)
00217     if(PulseT1ACount)
00218     {
00219         //u16 OCValue;
00220         // read in current value of output compare register OCR1A
00221         //OCValue =  inp(OCR1AL);       // read low byte of OCR1A
00222         //OCValue += inp(OCR1AH)<<8;    // read high byte of OCR1A
00223         // increment OCR1A value by PulseT1APeriodTics
00224         //OCValue += PulseT1APeriodTics;
00225         // set future output compare time to this new value
00226         //outp((OCValue>>8),        OCR1AH);    // write high byte
00227         //outp((OCValue & 0x00FF),OCR1AL);  // write low byte
00228 
00229         // the following line should be identical in operation
00230         // to the lines above, but for the moment, I'm not convinced
00231         // this method is bug-free.  At least it's simpler!
00232         outw(OCR1A, inw(OCR1A) + PulseT1APeriodTics);
00233                 
00234         // decrement the number of pulses executed
00235         if(PulseT1AMode & PULSE_MODE_COUNTED)
00236             PulseT1ACount--;
00237     }
00238     else
00239     {
00240         // pulse count has reached zero
00241         // disable the output compare's action on OC1A pin
00242         cbi(TCCR1A,COM1A1);
00243         cbi(TCCR1A,COM1A0);
00244         // and disable the output compare's interrupt to stop pulsing
00245         cbi(TIMSK, OCIE1A);
00246     }
00247 }
00248 
00249 void pulseT1BService(void)
00250 {
00251     // check if TimerPulseACount is non-zero
00252     //      (i.e. pulses are still requested)
00253     if(PulseT1BCount)
00254     {
00255         //u16 OCValue;
00256         // read in current value of output compare register OCR1B
00257         //OCValue =  inp(OCR1BL);       // read low byte of OCR1B
00258         //OCValue += inp(OCR1BH)<<8;    // read high byte of OCR1B
00259         // increment OCR1B value by PulseT1BPeriodTics
00260         //OCValue += PulseT1BPeriodTics; 
00261         // set future output compare time to this new value
00262         //outp((OCValue>>8),        OCR1BH);    // write high byte
00263         //outp((OCValue & 0x00FF),OCR1BL);  // write low byte
00264 
00265         // the following line should be identical in operation
00266         // to the lines above, but for the moment, I'm not convinced
00267         // this method is bug-free.  At least it's simpler!
00268         outw(OCR1B, inw(OCR1B) + PulseT1BPeriodTics);
00269         
00270         // decrement the number of pulses executed
00271         if(PulseT1BMode & PULSE_MODE_COUNTED)
00272             PulseT1BCount--;
00273     }
00274     else
00275     {
00276         // pulse count has reached zero
00277         // disable the output compare's action on OC1B pin
00278         cbi(TCCR1A,COM1B1);
00279         cbi(TCCR1A,COM1B0);
00280         // and disable the output compare's interrupt to stop pulsing
00281         cbi(TIMSK, OCIE1B);
00282     }
00283 }

Generated on Fri Aug 1 10:42:42 2003 for Procyon AVRlib by doxygen1.2.18