Rev 64 | Blame | Compare with Previous | Last modification | View Log | RSS feed
//############################################################################
// - PWM CTRL
// - Main
// - ATMEGA8 mit 8MHz
// - Nur für den privaten Gebrauch
// - Keine Garantie auf Fehlerfreiheit
// - Kommerzielle Nutzung nur mit meiner Zustimmung
// - walter Meyer @ www.freakware.de
// - 11.12.2007
// - Make sure Fuses are programmed for internal 8 MHz RC Oscilator
//############################################################################*/
#include "main.h"
#include "uart.h"
#include "twislave.h"
volatile unsigned int PPM_SIGNAL = 1520;
volatile unsigned char PPM_NEW = 0;
volatile unsigned char TMR1OvF = 0;
volatile unsigned int TMR1MS;
volatile unsigned char CH0;
volatile unsigned char CH1;
volatile unsigned char CH2;
volatile unsigned char CH3;
volatile unsigned char CH4;
volatile unsigned char CH5;
uint16_t EEMEM EEPMIN=0x0000;
uint16_t EEMEM EEPMAX=0xffff;
uint16_t EEMEM EEPSIG=0xffff;
//led kennlinie, (noch nicht implementiert, nur vorbereitet)
unsigned char kl[256]={
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
};
/*##############################################################################*/
SIGNAL(SIG_OVERFLOW1)
{
TMR1OvF++;
}
SIGNAL(SIG_INPUT_CAPTURE1)
{
static unsigned int pos_ICR;
static unsigned int ppm;
if ((TCCR1B & (1<<ICES1)) != 0) //rising edge
{
TCCR1B &= ~(1<<ICES1); //set falling egde
TMR1OvF = 0;
pos_ICR = ICR1;
}
else //falling edge
{
TCCR1B |= (1<<ICES1); //set rising egde
ppm = (ICR1 - pos_ICR + (int) TMR1OvF * 65536);
if ((ppm > 600) && (ppm < 2400))
{
if (ppm > 2100) ppm = 2100;
if (ppm < 900) ppm = 900;
ppm = (PPM_SIGNAL * 3 + ppm) / 4;
PPM_SIGNAL = ppm;
if (PPM_NEW < 50) PPM_NEW++;
}
}
}
/*##############################################################################*/
SIGNAL(SIG_OVERFLOW0)
{
// this function is called every 32us,
// it is very important that it's execution time is as short as possible
// currently it's about 20us
static unsigned char counter = 254;
static unsigned char ms1 = 0;
static unsigned char ch0_tmp = 0;
static unsigned char ch1_tmp = 0;
static unsigned char ch2_tmp = 0;
static unsigned char ch3_tmp = 0;
static unsigned char ch4_tmp = 0;
static unsigned char ch5_tmp = 0;
unsigned char PORTB_BAK;
unsigned char PORTD_BAK;
PORTB_BAK = PORTB;
PORTD_BAK = PORTD;
if (counter++ == 254)
{
PORTB_BAK LEDON (CH0_B | CH1_B | CH2_B); //new cycle, output on
PORTD_BAK LEDON (CH3_D | CH4_D | CH5_D); //
ch0_tmp = CH0;
ch1_tmp = CH1;
ch2_tmp = CH2;
ch3_tmp = CH3;
ch4_tmp = CH4;
ch5_tmp = CH5;
counter = 0;
}
if (ch0_tmp == counter) PORTB_BAK LEDOFF CH0_B; //channel value reached, output off
if (ch1_tmp == counter) PORTB_BAK LEDOFF CH1_B; //
if (ch2_tmp == counter) PORTB_BAK LEDOFF CH2_B; //
if (ch3_tmp == counter) PORTD_BAK LEDOFF CH3_D; //
if (ch4_tmp == counter) PORTD_BAK LEDOFF CH4_D; //
if (ch5_tmp == counter) PORTD_BAK LEDOFF CH5_D; //
PORTB = PORTB_BAK;
PORTD = PORTD_BAK;
if (ms1++ == 32)
{
ms1=0;
TMR1MS++;
}
}
/*##############################################################################*/
unsigned int SetDelay (unsigned int t)
{
unsigned char hi_byte;
unsigned char lo_byte;
hi_byte = (TMR1MS >> 8);
lo_byte = (TMR1MS & 0xff);
if (hi_byte != (TMR1MS >> 8)) hi_byte = (TMR1MS >> 8);
return(((hi_byte << 8) | lo_byte) + t + 1);
}
/*##############################################################################*/
char CheckDelay(unsigned int t)
{
unsigned char hi_byte;
unsigned char lo_byte;
hi_byte = (TMR1MS >> 8);
lo_byte = (TMR1MS & 0xff);
if (hi_byte != (TMR1MS >> 8)) hi_byte = (TMR1MS >> 8);
return(((t - ((hi_byte << 8) | lo_byte)) & 0x8000) >> 9);
}
/*##############################################################################*/
void StartPWM(void)
{
//Timer 0 Config
TCCR0 = (0<<CS02)|(0<<CS01)|(1<<CS00); // (@8MHz) = 1/8us Clk = 256/8 = 32us overflow
TIMSK setbit (1<<TOIE0); // enable Int
}
/*##############################################################################*/
void StartPPM(void)
{
//Timer1 Config
TCCR1A = (0<<COM1A1)|(0<<COM1A0)|(0<<COM1B1)|(0<<COM1B0)|
(0<<FOC1A) |(0<<FOC1B) |(0<<WGM10) |(0<<WGM11);
TCCR1B = (1<<ICNC1)|(1<<ICES1)|(0<<WGM13)|
(0<<WGM12)|(0<<CS12)|(1<<CS11)|(0<<CS10); //ICP_POS_FLANKE
// interrupts
TIMSK |= (1<<TICIE1)|(1<<TOIE1); //ICP_INT_ENABLE and TIMER1_INT_ENABLE
}
/*##############################################################################*/
unsigned int GetPPM(void)
{
//this routines seems to be nesseccary, as reading a 16 bit value
//on a 8 bit machine is not atomic, so if an interrupt apears between reading
//low and high byte of the 16 bit value a wrong result is possible
unsigned char temp_hi;
unsigned char temp_lo;
temp_hi = (PPM_SIGNAL >> 8);
temp_lo = (PPM_SIGNAL & 0xff);
if (temp_hi != (PPM_SIGNAL >> 8)) temp_hi = (PPM_SIGNAL >> 8);
return( (temp_hi << 8) | temp_lo);
}
/*##############################################################################*/
// MAIN
/*##############################################################################*/
int main (void)
{
#define STEP 256
#define MUL 1
#define REDUCE 2
#define EEPSIGNATURE 0x55aa
#define inimin 1200
#define inimax 1800
unsigned int ppm;
signed int color;
volatile unsigned int setupdly;
volatile unsigned int ppmtodly;
volatile unsigned int flashdly;
volatile unsigned int dly1;
unsigned char flags;
unsigned char setup;
unsigned int lmax;
unsigned int lmin;
unsigned int max;
unsigned int min;
unsigned char temp;
signed long temp1;
signed long temp2;
flags = 0;
DDRB = (CH0_B|CH1_B|CH2_B);
PORTB = 0x00;
DDRC = (ledred);
PORTC = 0x00;
DDRD = (ledgreen|CH3_D|CH4_D|CH5_D);
PORTD = 0x00;
CH0 = 0xFF; //PORTB RGBLED red
CH1 = 0xFF; //PORTB RGBLED green
CH2 = 0xFF; //PORTB RGBLED blue
CH3 = 0;
CH4 = 0;
CH5 = 0;
lmax = 0x0000;
lmin = 0xffff;
StartUART();
StartPPM();
//StartI2C();
StartPWM();
sei();
min = inimin; //default min
max = inimax; //default max
if (eeprom_read_word(&EEPSIG) != EEPSIGNATURE) //check eep if signature is there
{
eeprom_write_word(&EEPMIN, min); //no, write initial min
eeprom_write_word(&EEPMAX, max); //and max values
eeprom_write_word(&EEPSIG, EEPSIGNATURE); //along with eep signature
}
else
{
min = eeprom_read_word(&EEPMIN); //signature ok
max = eeprom_read_word(&EEPMAX); //read min and max
}
setup = 0; //reset setup toggle counter
temp = (1<<0);
setupdly = SetDelay(5000);
ppmtodly = SetDelay(2000);
flashdly = SetDelay(200);
while (1)
{
if (PPM_NEW > 20) //ppm Signal ok
{
PORTC clrbit ledred;
ppm = GetPPM();
ppmtodly = SetDelay(500); //reset timeout
if (lmax < ppm) lmax=ppm; //update impulse max
if (lmin > ppm) lmin=ppm; //and min boundarys
}
else
{
PORTC setbit ledred; //ppm signal not ok
ppm = min; //set ppm to minimum
}
if (CheckDelay(ppmtodly)) //timeout
{
ppmtodly = SetDelay(5000);
PPM_NEW = 0; //set ppm signal not ok
}
if (setup < 6)
{
if ((ppm > 1600) && ((setup&1)==0)) setup++; //
if ((ppm < 1400) && ((setup&1)==1)) setup++; //
if (CheckDelay(flashdly))
{
CH0 = (temp & (1<<0)) * 255;
CH1 = (temp & (1<<1)) * 255;
CH2 = (temp & (1<<2)) * 255;
CH3 = (temp & (1<<3)) * 255;
CH4 = (temp & (1<<4)) * 255;
CH5 = (temp & (1<<5)) * 255;
temp <<= 1;
if (temp == (1<<6)) temp = (1<<0);
/*
CH0 = CH0 ^ 0xff; //invert brightness
CH1 = CH1 ^ 0xff;
CH2 = CH2 ^ 0xff;
CH3 = CH3 ^ 0xff;
CH4 = CH4 ^ 0xff;
CH5 = CH5 ^ 0xff;
*/
flashdly = SetDelay(100);
}
}
if (setup == 6) //if stick is toggled 6 times
{ //within setup timeout
PORTD setbit ledgreen; //store ppm min and max
setupdly = SetDelay(3000); //for 2000ms
eeprom_write_word(&EEPMIN, lmin); //in eeprom
eeprom_write_word(&EEPMAX, lmax);
min = lmin;
max = lmax;
setup = 7; //enter PWM toggle mode
}
if (setup == 7)
{
if (CheckDelay(flashdly)) //each 25ms toggle PWM's
{
CH0 = CH0 ^ 0xff; //invert brightness
CH1 = CH1 ^ 0xff;
CH2 = CH2 ^ 0xff;
CH3 = CH3 ^ 0xff;
CH4 = CH4 ^ 0xff;
CH5 = CH5 ^ 0xff;
flashdly = SetDelay(25);
}
}
if ((CheckDelay(setupdly)) && setup < 8) //setup timeout reached
{
setup = 8; //lockdown setup
PORTD clrbit ledgreen;
CH0 = 0; //start CH3
CH1 = 85; //CH4
CH2 = 170; //and CH4 with about 120° phase shift
flags = 0;
dly1 = SetDelay(100);
}
if (setup == 8)
{
/************************************************************************************/
/* control CH3, CH4 and CH5 (RGB LED) */
/************************************************************************************/
temp1 = ((long)STEP * 7 * 40000) / ((max-REDUCE) - (min+REDUCE));
temp2 = (((int)ppm - ((int)min+REDUCE)) * temp1);
color = temp2 / 40000;
if (color < 0) color = 0;
if (color > ((STEP*7)+1)) color = ((STEP*7)+1);
//printf("p %u ",ppm);
//printf("pm %u ",(min+REDUCE));
//printf("t1 %li ",temp1);
//printf("t2 %li ",temp2);
//printf("c %i\n ",color);
// Farbablauf: off > red > purple > blue > cyan > green > yellow > white
if ((color >= (STEP * 0)) && (color < (STEP * 1)))
{
CH3 = MUL * ((color - (STEP * 0))); //fade in red > red (red only)
CH4 = 0;
CH5 = 0;
}
if ((color >= (STEP * 1)) && (color < (STEP * 2)))
{
CH3 = ((STEP-1) * MUL);
CH4 = 0;
CH5 = MUL * ((color - (STEP * 1))); //fade in blue > purple (red + blue)
}
if ((color >= (STEP * 2)) && (color < (STEP * 3)))
{
CH3 = MUL * ((STEP - 1) - (color - (STEP * 2))); //fade out red > blue (blue only)
CH4 = 0;
CH5 = ((STEP-1) * MUL);
}
if ((color >= (STEP * 3)) && (color < (STEP * 4)))
{
CH3 = 0;
CH4 = MUL * ((color - (STEP * 3))); //fade in green > cyan (blue + green)
CH5 = ((STEP-1) * MUL);
}
if ((color >= (STEP * 4)) && (color < (STEP * 5)))
{
CH3 = 0;
CH4 = ((STEP-1) * MUL);
CH5 = MUL * ((STEP - 1) - (color - (STEP * 4))); //fade out blue > green (green only)
}
if ((color >= (STEP * 5)) && (color < (STEP * 6)))
{
CH3 = MUL * ((color - (STEP * 5))); //fade in red > yellow (green + red)
CH4 = ((STEP-1) * MUL);
CH5 = 0;
}
if ((color >= (STEP * 6)) && (color < (STEP * 7)))
{
CH3 = ((STEP-1) * MUL);
CH4 = ((STEP-1) * MUL);
CH5 = MUL * ((color - (STEP * 1))); //fade in blue > purple (red + blue)
}
if (color >= (STEP * 7))
{
CH3 = ((STEP-1) * MUL);
CH4 = ((STEP-1) * MUL);
CH5 = ((STEP-1) * MUL);
}
/************************************************************************************/
/* control CH0, CH1 and CH2 */
/************************************************************************************/
if (CheckDelay(dly1)) //timeout reached ?
{
if ((flags & (1<<0))==0) //check if up or down
{
if (CH0++ == 254) //run CH0 up to 255
{
flags setbit (1<<0); //255 reached next time go down
}
}
else //run down
{
if (CH0-- == 1) //run CH0 down to 0
{
flags clrbit (1<<0); //0 reached next time go up
}
}
if ((flags & (1<<1))==0) //same for CH1
{
if (CH1++ == 254)
{
flags setbit (1<<1);
}
}
else
{
if (CH1-- == 1)
{
flags clrbit (1<<1);
}
}
if ((flags & (1<<2))==0) //and same for CH2
{
if (CH2++ == 254)
{
flags setbit (1<<2);
}
}
else
{
if (CH2-- == 1)
{
flags clrbit (1<<2);
}
}
dly1 = SetDelay(1); //set next timeout in 25ms
// printf("ch3:%i\n",CH0);
}
}
}
}