Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*****************************************************************************************************************************
* File: timer0.c
*
* Purpose: setup of timer0 and timer2
* and delay functions
*
* Functions: void Timer_Init(void);
* void TIMER2_Init(void);
* void Delay_ms(unsigned int);
* void Delay_ms_Mess(unsigned int);
*
*****************************************************************************************************************************/
//
#include "main.h"
volatile unsigned int CountMilliseconds = 0;
volatile static unsigned int tim_main;
volatile unsigned char UpdateMotor = 0;
volatile unsigned int cntKompass = 0;
volatile unsigned int beeptime = 0;
volatile unsigned char SendSPI = 0;
volatile unsigned char ServoActive = 0;
unsigned int BeepMuster = 0xFFFF;
volatile int16_t ServoNickValue = 0;
volatile int16_t ServoRollValue = 0;
//---------------------------
enum
{
STOP = 0,
CK = 1,
CK8 = 2,
CK64 = 3,
CK256 = 4,
CK1024 = 5,
T0_FALLING_EDGE = 6,
T0_RISING_EDGE = 7
};
//---------------------------
//********************************************************************************************************************
// Timer0 is running with "fast PWM" at OC0A=PORTB3 and OC0B=PORTB4
// setup of Offset P_OFF1 and P_OFF2 for the air pressure sensor
//--------------------------------------------------------------------------------------------------------------------
void Timer_Init(void)
{
tim_main = SetDelay(10);
// ----------------------------------------------------------------------------------------------------------------
// TCCR0B Timer/Counter Control Register B containing: FOC0A FOC0B WGM02 CS02 CS01 CS0
//
TCCR0B = CK8; // CK8 = 2 = clk/8 (From prescaler) one turnarround takes 0.1024ms
// ----------------------------------------------------------------------------------------------------------------
// TCCR0A Timer/Counter Control Register A containing: COM0A1 COM0A0 COM0B1 COM0B0 WGM01 WGM00
//
TCCR0A = (1<<COM0A1)|(1<<COM0B1)|3; // WGM02 WGM01 WGM00 = 011 = Fast PWM
OCR0A = 0; // output compare Register A for Counter 0
OCR0B = 120; // output compare Register B for Counter 0
TCNT0 = (unsigned char)-TIMER_RELOAD_VALUE; // reload // #define TIMER_RELOAD_VALUE 250
// ----------------------------------------------------------------------------------------------------------------
// TIMSK0 Timer/Counter Interrupt Mask Register containing: OCIE0B OCIE0A TOIE0
// TOIE0: Timer/Counter0 Overflow Interrupt Enable - When the TOIE0 bit is written to one, and the I-bit in the Status Register is set
//
TIMSK0 |= (1<<TOIE0);
}
// **************************** EOF: void Timer_Init(void) *******************************************************************
// *************************************************************************************************************************
// this funktions returns the variable "CountMilliseconds" as it will be after the waiting time hase been exipired
// -------------------------------------------------------------------------------------------------------------------------
unsigned int SetDelay(unsigned int t)
{
return(CountMilliseconds + t + 1);
}
// *************************************************************************************************************************
// *************************************************************************************************************************
// Hier wird also die Zeitdifferenz (t-CountsMilliseconds) mit der Maske 0x08000 maskiert.
// 0x8000 = 1000 0000 0000 0000 setzt also bis auf das höchste Bit der 16-bit Zeitdifferenz alle Bits auf 0.
// Bei einer Integerzahl codiert das höchst bit das Vorzeichen. Ist also t < CountMillisconds wird,
// so flippt das Vorzeichen-Bit auf 1 sonst ist es 0. Diese Eigenschaft wird hier genutzt.
// Das Ganze wird dann noch um 9 Bits nach rechts geshiftet, damit die Information im unteren Byte liegt,
// um beim Typecast des Rückgabewertes auf 8-Bit die Ändeurng im oberen Byte nicht abgeschnitten wird.
//
// Man könnte den Code auch so aufschreiben:
/*
char CheckDelay(unsigned int t)
{
int diff;
diff = int(t-CountMilliseconds);
if (diff < 0) return 255;
else return 0;
}
*/
//
char CheckDelay(unsigned int t)
{
return(((t - CountMilliseconds) & 0x8000) >> 9); // 0x8000 = 0b 1000 0000 0000 0000
}
// *************************************************************************************************************************
// *************************************************************************************************************************
void Delay_ms(unsigned int w)
{
unsigned int akt;
akt = SetDelay(w);
while (!CheckDelay(akt));
}
// *************************************************************************************************************************
// *************************************************************************************************************************
void Delay_ms_Mess(unsigned int w)
{
unsigned int akt;
akt = SetDelay(w);
while (!CheckDelay(akt)) if(AdReady) {AdReady = 0; ANALOG_ON;} // #define ANALOG_ON ADCSRA=(1<<ADEN)|(1<<ADSC)|(0<<ADATE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADIE)
}
// *************************************************************************************************************************
// *************************************************************************************************************************
// Interrupt due to overflow of Timer0
// --------------------------------------
ISR(TIMER0_OVF_vect)
{
static unsigned char cnt_1ms=1, cnt=0; // one turnarround of Timer0 takes 0.1024ms at 256 steps
unsigned char pieper_ein = 0;
if(SendSPI) SendSPI--; //
if(!cnt--)
{
cnt=9; // 10 steps * 0.1024ms -> 1ms
cnt_1ms++;
cnt_1ms %= 2; // modulo division
if(!cnt_1ms) UpdateMotor = 1; // all 2 ms the motor is updated
CountMilliseconds++;
}
if(beeptime >= 1)
{
beeptime--;
if(beeptime & BeepMuster)
{
pieper_ein = 1;
}
else pieper_ein = 0;
}
else
{
pieper_ein = 0;
BeepMuster = 0xFFFF;
}
if(pieper_ein)
{
PORTC |= (1<<7); // beeper is connected to PORTC.7
}
else
{
PORTC &= ~(1<<7);
}
//------------------------------------------------------------------------------------------------------------------------
// Compass works per PWM at PORTC4
//------------------------------------------------------------------------------------------------------------------------
if(EE_Parameter.GlobalConfig & CFG_KOMPASS_AKTIV)
{
if(PINC & 0x10) // PORTC4 is up
{
cntKompass++;
}
else // PORTC4 is doing down now -> check lenght of PWM pulse
{
if((cntKompass) && (cntKompass < 362)) // if value is positiv and less then 362
{
cntKompass += cntKompass / 41;
if(cntKompass > 10) KompassValue = cntKompass - 10; else KompassValue = 0; // indicated value of compass
}
KompassRichtung = ((540 + KompassValue - KompassStartwert) % 360) - 180; // differential direction
cntKompass = 0; // reset PWM counter
}
}
}
// *************************************************************************************************************************
// *************************************************************************************************************************
// Purpose: Initialize Timer 2
//
// Timer 2 is used to generate the PWM at PD7 (J7) to control a camera servo for nick compensation.
//
//---------------------------------------------------------------------------------------------------------------------------------------
void TIMER2_Init(void)
{
unsigned char sreg = SREG; // copy SREG Status Register
cli(); // disable all interrupts before reconfiguration
PORTD &= ~(1<<PORTD7); // set PD7 = OC2A to low = Servo PPM
//------------------------------------------------------------------------------------------
// DDRC Port C Data Direction Register containing: DDC7 DDC6 DDC5 DDC4 DDC3 DDC2 DDC1 DDC0
DDRC |= (1<<DDC6); // set PC6 as output (Reset for HEF4017)
HEF4017R_ON; // #define HEF4017R_ON PORTC |= (1<<PORTC6)
//------------------------------------------------------------------------------------------
// TCCR2A = Timer/Counter 2 Control Register A containing: COM2A1 COM2A0 COM2B1 COM2B0 WGM21 WGM20
// COM2A1:0: Compare Match Output A Mode. These bits control the Output Compare pin (OC2A) behavior
// COM2B1:0: Compare Match Output B Mode. These bits control the Output Compare pin (OC2B) behavior
TCCR2A &= ~((1<<COM2A1)|(1<<COM2A0)|(1<<COM2B1)|(1<<COM2B0)); // Normal port operation
//
// The counter counts from BOTTOM to TOP then restarts from BOTTOM.
// TOP is defined as OCR2A asxxx, MGM22:0 = 111.
TCCR2A |= (1<<WGM21)|(1<<WGM20);
//------------------------------------------------------------------------------------------
// TCCR2B = Timer/Counter 2 Control Register B containing: FOC2A FOC2B WGM22 CS22 CS21 CS20
// FOC2A: Force Output Compare A. The FOC2A bit is only active when the WGM bits specify a non-PWM mode
// FOC2B: Force Output Compare B. The FOC2B bit is only active when the WGM bits specify a non-PWM mode.
// CS22:0: Clock Select. The three Clock Select bits select the clock source to be used by the Timer/Counter
// Clock Select = 011 = SYSKLOCK/32 at 20MHz / 32 = 625 kHz
// The timer increments from 0x00 to OCR2A with an update rate of 625 kHz or 0.0016 ms
//
TCCR2B &= ~((1<<FOC2A)|(1<<FOC2B)|(1<<CS22));
TCCR2B |= (1<<CS21)|(1<<CS20)|(1<<WGM22);
//------------------------------------------------------------------------------------------
// Reset the Timer/Counter 2
TCNT2 = 0;
OCR2A = 255; // Initialize the Output Compare Register A used for PWM generation on port PD7.
TCCR2A |= (1<<COM2A1); // Clear OC2A on Compare Match when up-counting. Set OC2A on Compare Match when down-counting
//------------------------------------------------------------------------------------------
// TIMSK2 Timer/Counter2 Interrupt Mask Register containing: OCIE2B OCIE2A TOIE2
// OCIE2B: Timer/Counter2 Output Compare Match B Interrupt Enable
// TOIE2: Timer/Counter2 Overflow Interrupt Enable
//
TIMSK2 &= ~((1<<OCIE2B)|(1<<TOIE2)); // Output Compare Match B Interrupt is dissabled as Overflow Interrupt
TIMSK2 |= (1<<OCIE2A); // Timer/Counter2 Output Compare Match A Interrupt is enabled
SREG = sreg; // recopy SREG Status Register
}
// *************************************************************************************************************************
// *************************************************************************************************************************
// Timer2 controlls the Position of Control Servos at
// OC2A=PORTD7
//---------------------------------------------------------------------------------------------------------------------------------------------
ISR(TIMER2_COMPA_vect)
{
// frame len 22.5 ms = 14063 * 1.6 us
// stop pulse: 0.3 ms = 188 * 1.6 us
// min servo pulse: 0.6 ms = 375 * 1.6 us
// max servo pulse: 2.4 ms = 1500 * 1.6 us
// resolution: 1500 - 375 = 1125 steps
#define IRS_RUNTIME 127
#define PPM_STOPPULSE 188
#define PPM_FRAMELEN (1757 * EE_Parameter.ServoNickRefresh)
#define MINSERVOPULSE 375
#define MAXSERVOPULSE 1500
#define SERVORANGE (MAXSERVOPULSE - MINSERVOPULSE)
static uint8_t PulseOutput = 0;
static uint16_t RemainingPulse = 0;
static uint16_t ServoFrameTime = 0;
//static uint8_t ServoIndex = 0;
#define MULTIPLYER 4
static int16_t ServoNickOffset = (255 / 2) * MULTIPLYER; // initial value near center positon
//static int16_t ServoRollOffset = (255 / 2) * MULTIPLYER; // initial value near center positon
//------------------------------------------------------------------------------------------------------------------------
// Nick servo state machine
//------------------------------------------------------------------------------------------------------------------------
if(!PulseOutput) // pulse output complete
{
if(TCCR2A & (1<<COM2A0)) // we had a low pulse
{
TCCR2A &= ~(1<<COM2A0); // make a high pulse
RemainingPulse = MINSERVOPULSE + SERVORANGE/2; // center position ~ 1.5ms
ServoNickOffset = (ServoNickOffset * 3 + (int16_t)Parameter_ServoNickControl * MULTIPLYER) / 4; // lowpass offset
ServoNickValue = ServoNickOffset; // offset (Range from 0 to 255 * 3 = 765)
if(EE_Parameter.ServoCompInvert & 0x01)
{ // inverting movement of servo
ServoNickValue += (int16_t)( ( (int32_t)EE_Parameter.ServoNickComp * MULTIPLYER * (IntegralNick / 128L ) ) / (256L) );
}
else
{ // non inverting movement of servo
ServoNickValue -= (int16_t)( ( (int32_t)EE_Parameter.ServoNickComp * MULTIPLYER * (IntegralNick / 128L ) ) / (256L) );
}
// limit servo value to its parameter range definition
if(ServoNickValue < ((int16_t)EE_Parameter.ServoNickMin * MULTIPLYER) )
{
ServoNickValue = (int16_t)EE_Parameter.ServoNickMin * MULTIPLYER;
}
else if(ServoNickValue > ((int16_t)EE_Parameter.ServoNickMax * MULTIPLYER) )
{
ServoNickValue = (int16_t)EE_Parameter.ServoNickMax * MULTIPLYER;
}
RemainingPulse += ServoNickValue - (256 / 2) * MULTIPLYER; // shift ServoNickValue to center position
ServoNickValue /= MULTIPLYER;
// range servo pulse width
if(RemainingPulse > MAXSERVOPULSE ) RemainingPulse = MAXSERVOPULSE; // upper servo pulse limit
else if(RemainingPulse < MINSERVOPULSE ) RemainingPulse = MINSERVOPULSE; // lower servo pulse limit
ServoFrameTime = RemainingPulse; // accumulate time for correct update rate
}
else // we had a high pulse
{
TCCR2A |= (1<<COM2A0); // make a low pulse
RemainingPulse = PPM_FRAMELEN - ServoFrameTime;
}
PulseOutput = 1; // set pulse output active
}
if(RemainingPulse > (255 + IRS_RUNTIME)) // General pulse output generator
{
OCR2A = 255;
RemainingPulse -= 255;
}
else
{
if(RemainingPulse > 255) // this is the 2nd last part
{
if((RemainingPulse - 255) < IRS_RUNTIME)
{
OCR2A = 255 - IRS_RUNTIME;
RemainingPulse -= 255 - IRS_RUNTIME;
}
else // last part > ISR_RUNTIME
{
OCR2A = 255;
RemainingPulse -= 255;
}
}
else // this is the last part
{
OCR2A = RemainingPulse;
RemainingPulse = 0;
PulseOutput = 0; // trigger to stop pulse
}
} // EOF: general pulse output generator
}
// *** EOF: ISR(TIMER2_COMPA_vect) ***************************************************************************************