Sophie

Sophie

distrib > Mandriva > 2010.0 > i586 > media > contrib-release > by-pkgid > 0a79d88ef992ed59615a5fe9eb545218 > files > 10

vdr-plugin-atmo-0.0.1-18mdv2010.0.i586.rpm

/************************************************************/
/*                 Atmo-Light fuer VDR                      */
/*----------------------------------------------------------*/
/* Hardware-Vorrausetzungen:                                */
/*  -Fotodiode Rot   an AD-Kanal 0                          */
/*  -Fotodiode Gruen an AD-Kanal 1                          */
/*  -Fotodiode Blau  an AD-Kanal 2                          */
/*  -PWM-Treiber Rot   an Output Compare 1A                 */
/*  -PWM-Treiber Gruen an Output Compare 1B                 */
/*  -PWM-Treiber Blau  an Output Compare 2                  */
/*  -Taster an INT0 gegen +5V (+ext. Pulldown am Pin)       */
/*  -Taster an INT1 gegen +5V (+ext. Pulldown am Pin)       */
/*  -LED an PD4 gegen VCC (CPU int. Pulldown)               */
/*  -LED an PD6 gegen VCC (CPU int. Pulldown)               */
/*  -LED an PD7 gegen VCC (CPU int. Pulldown)               */
/*  -Quarz: 11,0592 MHz                                     */
/************************************************************/
/*  Aufbau des seriellen Telegramms:                        */
/*                                                          */
/*     - Parameter: 57600 Baud, 8N1                         */
/*     1. Startbyte                                         */
/*     3. Sollwert ROT                                      */
/*     4. Sollwert GRUEN                                    */
/*     5. Sollwert BLAU                                     */
/*                                                          */
/************************************************************/
/*  Versionshistorie:                                       */
/*                                                          */
/*     V0.01 Initial Release                                */
/*                                                          */
/************************************************************/

/************************************************************/
/*                     Includes                             */
/************************************************************/
#include <avr/io.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>

/************************************************************/
/*                Definitionen Konstanten                   */
/************************************************************/
//Quarz: 11,0592 MHz
#define SYSCLK     			11059200
//Zielbaudrate
#define BAUDRATE   			57600
//Baudraten-Prescaler, haendisch berechnet, da die folgende
//Formel zu einem Ueberlauf im Compiler fuehrt?!?
#define UBRR_BAUD				(11)
//#define UBRR_BAUD				((SYSCLK/(16*BAUDRATE))-1)
//etwas sprechendere Bezeichner fuer die PWM-Ausgaenge
#define PWM_ROT_OUT     OCR1AL
#define PWM_GRUEN_OUT   OCR1BL
#define PWM_BLAU_OUT    OCR2
//Startbyte der RS232-Uebertragung vom Controller
#define STARTBYTE   		0xFF

typedef enum SERIAL_STEP_E
{
  SERIAL_START,    /* aufs Startbyte warten */
  SERIAL_BYTE1,    /* Sollwert ROT          */
  SERIAL_BYTE2,    /* Sollwert GRUEN        */
  SERIAL_BYTE3     /* Sollwert BLAU         */
} SERIAL_STEP_T;

typedef enum ATMO_MODE_E
{
  MODE_RGB,        /* Daten im RGB-Modus               */
	MODE_RAW         /* Rohdaten fuer PWM                */
} ATMO_MODE_T;

/************************************************************/
/*             Deklaration Initialisierungen                */
/************************************************************/
/* Hardware initialisieren */
void init(void);
/* UART initialisieren */
void uart_init(void);
/* Delay-Routine */
void delay_ms(unsigned int ms);
/* Timer initialisieren */
void timer_init(void);
/* Analog/Digital Wandler initialisieren */
void adc_init(void);

/************************************************************/
/*             Deklaration Funktionen                       */
/************************************************************/
/* Zeichen ueber RS-232 senden */
void putc(unsigned char c);
/* Helligkeit ueber ADC einlesen */
void read_ad(void);
/* Regelung */
void regelung(void);

/************************************************************/
/*                Definitionen Variablen                    */
/************************************************************/
/* Sollwert des AD-Wandlerwertes der Einzelfarben 10 bit (aus LUT) */
volatile unsigned int rot_soll_rgb   = 0;
volatile unsigned int gruen_soll_rgb = 0;
volatile unsigned int blau_soll_rgb  = 0;

/* Istwert der Einzelfarben (ueber AD-Wandler) 10 bit */
volatile unsigned int rot_ist    = 0; 
volatile unsigned int gruen_ist  = 0;
volatile unsigned int blau_ist   = 0;

/* PWM-Breite der Einzelfarben 8 bit */
volatile unsigned char pwm_rot   = 0;
volatile unsigned char pwm_gruen = 0;
volatile unsigned char pwm_blau  = 0;

/* State-Machine serielle Schnittstelle */
static SERIAL_STEP_T ser_step = SERIAL_START;

/* Modus der Uebertragung */
static ATMO_MODE_T mode = MODE_RGB;

/* Togglen der LED */
unsigned char toggle = 0;				

// 1 = AD-Wandlerwerte über RS232 versenden
unsigned char send_rs232 = 0;

// Lookup-Tables fuer Istwerte, die vom AD-Wandler kommen muessen

/* Samael */
unsigned int rot_lut[32]   = {   0,  10,  34,  57,  81, 104, 128, 152,
                                 175, 199, 222, 246, 270, 293, 317, 340, 
																 364, 388, 411, 435, 458, 482, 506, 529, 
																 553, 576, 600, 624, 647, 671, 694, 718};
																 
unsigned int gruen_lut[32] = {   0,  10,  26,  41,  57,  72,  88, 103,
                                 119, 134, 150, 165, 181, 196, 212, 227,
                                 243, 258, 274, 289, 305, 320, 336, 351, 
																 367, 382, 398, 413, 429, 444, 460, 475};
                                 
unsigned int blau_lut[32]  = {   0,  10,  27,  44,  61,  78,  95, 112,
                                 129, 146, 163, 180, 197, 214, 231, 248, 
																 265, 282, 299, 316, 333, 350, 367, 384, 
																 401, 418, 435, 452, 469, 486, 503, 520};


/* daniel_k 
unsigned int rot_lut[32]   = {   0,  10,  27,  44,  61,  78,  95, 112,
                                 129, 146, 163, 180, 197, 214, 231, 248, 
																 265, 282, 299, 316, 333, 350, 367, 384, 
																 401, 418, 435, 452, 469, 486, 503, 510};
																 
unsigned int gruen_lut[32] = {   0,  10,  28,  47,  65,  83, 102, 120,
                                 138, 157, 175, 193, 212, 230, 248, 267, 
																 285, 303, 322, 340, 358, 377, 395, 413, 
																 432, 450, 468, 487, 505, 523, 542, 560};
                                 
unsigned int blau_lut[32]  = {   0,   8,  24,  41,  57,  73,  90, 106,
                                 122, 139, 155, 171, 188, 204, 220, 237, 
																 253, 269, 286, 302, 318, 335, 351, 367, 
																 384, 400, 416, 433, 449, 465, 482, 498};

*/																 
/************************************************************/
/*                      Hauptroutine                        */
/************************************************************/
int main(void)
{

	/* HW-Initialisierung */
	init();	
	
	/* UART initialisieren */
	uart_init();
	
	/* A/D - Wandler initialisieren */
	adc_init();
	
	/* Timer initialisieren */
	timer_init();


  GIMSK = (1<<INT0)|(1<<INT1);           // enable external int0/1
  MCUCR = (1<<ISC01)|(1<<ISC11);         // falling egde: int0/1
	
	/* Serial Interrupt enable */
	sei(); 
	
  /* mit Schwarz anfangen */
  PWM_ROT_OUT   = 0x00;
  PWM_GRUEN_OUT = 0x00; 
  PWM_BLAU_OUT  = 0x00;
	
  /* Endlosschleife */
	while (1)
	{
	  /* IST-Helligkeiten einlesen */
		read_ad();
	  
	  /* Regelung (nur RGB-Modus, nicht im RAW-Modus) */
		if (MODE_RGB == mode)
		{
		  regelung();
		}	
		
	  /* LED anschalten, wenn Daten senden aktiv */
		if (send_rs232)
		{
		  PORTD &= ~0x10; /* LED an */
		}
		else
		{
		  PORTD |= 0x10;  /* LED aus */
		}
		
	} /* Ende Endlosschleife */	
  
	/* hier kommen wir hoffentlich nie an ;-) */
	return 0;
}

/*****************************************/
/*     Helligkeit ueber ADC einlesen,    */
/*    erste Wandlung jeweils verwerfen   */
/*****************************************/
void read_ad(void)
{
	/***********************************/
	/*    Ist-Helligkeit ROT einlesen  */
	/***********************************/
	/* AD-Mux-Kanal anwaehlen */
	ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
	ADMUX = 0x00;
	/* Wandlung starten */
	ADCSRA |= (1<<ADSC);
	/* Warten bis die AD-Wandlung abgeschlossen ist */
	while ( (ADCSRA & (1<<ADSC)) )
		;

	/* AD-Wert auslesen, 5V entspricht 0% Helligkeit!!! */
	rot_ist = 0x03FF - ADCW;
	/*------------------------------*/
	/* Messwerte ueber RS-232       */
	/* verschicken, falls aktiviert */
	/*------------------------------*/
	if (send_rs232)
	{
		putc(STARTBYTE);
		putc(0xFE);
    putc((unsigned char)((rot_soll_rgb>>8)&0xFF));
		putc((unsigned char)(rot_soll_rgb&0xFF));
		putc((unsigned char)((rot_ist>>8)&0xFF));
		putc((unsigned char)(rot_ist&0xFF));
	}
	/***********************************/
	/*  Ist-Helligkeit GRUEN einlesen  */
	/***********************************/
	/* AD-Mux-Kanal anwaehlen */
	ADMUX = 0x01;
	/* Wandlung starten */
	ADCSRA |= (1<<ADSC);
	/* Warten bis die AD-Wandlung abgeschlossen ist */
	while ( (ADCSRA & (1<<ADSC)) )
		;

	/* AD-Wert auslesen, 5V entspricht 0% Helligkeit!!! */
	gruen_ist = 0x03FF - ADCW;
	/*------------------------------*/
	/* Messwerte ueber RS-232       */
	/* verschicken, falls aktiviert */
	/*------------------------------*/
	if (send_rs232)
	{
    putc((unsigned char)((gruen_soll_rgb>>8)&0xFF));
		putc((unsigned char)(gruen_soll_rgb&0xFF));
		putc((unsigned char)((gruen_ist>>8)&0xFF));
		putc((unsigned char)(gruen_ist&0xFF));
	}	

	/***********************************/
	/*   Ist-Helligkeit BLAU einlesen  */
	/***********************************/
	/* AD-Mux-Kanal anwaehlen */
	ADMUX = 0x02;
	/* Wandlung starten */
	ADCSRA |= (1<<ADSC);
	/* Warten bis die AD-Wandlung abgeschlossen ist */
	while ( (ADCSRA & (1<<ADSC)) )
		;

	/* AD-Wert auslesen, 5V entspricht 0% Helligkeit!!! */
	blau_ist = 0x03FF - ADCW;
	/*------------------------------*/
	/* Messwerte ueber RS-232       */
	/* verschicken, falls aktiviert */
	/*------------------------------*/
	if (send_rs232)
	{
    putc((unsigned char)((blau_soll_rgb>>8)&0xFF));
		putc((unsigned char)(blau_soll_rgb&0xFF));
		putc((unsigned char)((blau_ist>>8)&0xFF));
		putc((unsigned char)(blau_ist&0xFF));
	}	

}


/**************************************************/
/*                   Regelung                     */
/**************************************************/
void regelung(void)
{
	/***************       ROT        ***************/
	/* zu hell und noch Luft nach unten? */
	if ((rot_ist > rot_soll_rgb) && (pwm_rot > 0))
	{
		//PWM 1/255 schmaler
		pwm_rot--;
	}
	/* zu dunkel und noch Luft nach oben? */
	else if ((rot_ist < rot_soll_rgb) && (pwm_rot < 254))
	{
		//PWM 1/255 breiter
		pwm_rot++;
	}
	//PWM rot ausgeben
	PWM_ROT_OUT = pwm_rot;
	
	/***************      GRUEN        **************/
	/* zu hell und noch Luft nach unten? */
	if ((gruen_ist > gruen_soll_rgb) && (pwm_gruen > 0))
	{
		//PWM 1/255 schmaler
		pwm_gruen--;
	}
	/* zu dunkel und noch Luft nach oben? */
	else if ((gruen_ist < gruen_soll_rgb) && (pwm_gruen < 254))
	{
		//PWM 1/255 breiter
		pwm_gruen++;
	}
	//PWM gruen ausgeben
	PWM_GRUEN_OUT = pwm_gruen;
	
	/***************       BLAU         *************/
	/* zu hell und noch Luft nach unten? */
	if ((blau_ist > blau_soll_rgb) && (pwm_blau > 0))
	{
		//PWM 1/255 schmaler
		pwm_blau--;
	}
	/* zu dunkel und noch Luft nach oben? */
	else if ((blau_ist < blau_soll_rgb) && (pwm_blau < 254))
	{
		//PWM 1/255 breiter
		pwm_blau++;
	}
	//PWM blau ausgeben
	PWM_BLAU_OUT = pwm_blau;
}

/*****************************************/
/*          HW initialisieren            */
/*****************************************/
void init(void)
{
	DDRB  = 0xFF;	// PortB als Ausgang deklarieren
	PORTB = 0x00;	// Ports auf LOW schalten
	DDRD  = 0xD2; // TX RS232 auf Port D, INT0 und INT1 als Eingang, PD4, PD6, PD7 als LED out
	PORTD = 0xD2; // int. Pullups aktivieren
	DDRC  = 0x00; // Port C als Eingang
	PORTC = 0x00; // Pullups nicht aktivieren
}


/*****************************************/
/*          USART initialisieren         */
/*****************************************/
void uart_init(void)
{
	/* Baudrate einstellen ( Normaler Modus ) */
	UBRRH = (unsigned char) (UBRR_BAUD>>8);
	UBRRL = (unsigned char) UBRR_BAUD;

	/* Aktivieren des Empfaengers, des Senders und des "Daten empfangen"-Interrupts */
	UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);

	/* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */
	UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

/*****************************************/
/*         Timer initialisieren          */
/*****************************************/
void timer_init(void)
{
	/* normale 8-bit PWM aktivieren ( nicht invertiert ),
	   Das Bit WGM10 wird im Datenblatt auch als PWM10 bezeichnet */
	TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM10);

	/* Einstellen der PWM-Frequenz ( Prescaler = 1 ) */
	TCCR1B = (1<<CS10);

	/* Timer 2: Phase Correct PWM, Clear OC2 on Compare Match, set OC2 at TOP (Prescaler = 1) */
  TCCR2 = (1<<COM21)|(1<<WGM20)|(1<<CS20);

	/* Interrupts fuer Timer1 und 2 deaktivieren
	Achtung : Auch die Interrupts fuer die anderen Timer stehen in diesem Register */
	TIMSK &= ~0xFC;

  /* Timer Counter Register resetten */
	TCNT1H = 0x00;
	TCNT1L = 0x00;
	TCNT2  = 0x01;
	
}

/*****************************************/
/*               UART RX-ISR             */
/*****************************************/
/* Interrupt wird ausgeloest sobald neue  */
/* Daten im USART-Empfangspuffer liegen  */
SIGNAL(SIG_UART_RECV)
{
	unsigned char buffer;
	static unsigned char r_msb = 0;
	static unsigned char g_msb = 0;
	static unsigned char b_msb = 0;
	
	/* Daten aus dem Puffer lesen ... */
	buffer = UDR;
  //Bit 7 = 1? -> Startbyte!
  if (0x80 == (buffer & 0x80))
  { 
	  //Bit 0 untersuchen
	  switch (buffer & 0x01)
    {
      //0 = RGB mode
      case 0x00:
		    mode = MODE_RGB;
		    PORTD &= ~0x40; /* LED an */
		    PORTD |= 0x90;  /* LEDs aus */
		  break;
		 
      //1 = Raw PWM mode
      case 0x01:
		    mode = MODE_RAW;
		    PORTD &= ~0x10; /* LED an */
		    PORTD |= 0xC0;  /* LEDs aus */
		  break;
		 
		  default:
		  break;
	  }					 

    //Daten senden?
		if (0x02 == (buffer & 0x02))
		{
		  //Senden ueber RS232 aktivieren
		  send_rs232 = 1;
		}
		else
    {
		  //Senden ueber RS232 deaktivieren
		  send_rs232 = 0;
		}	
	 
	  //Raw-Mode gesetzt?
		//dann die MSBs aus dem Startbyte extrahieren
	  //MSB rot
		if ((MODE_RAW == mode) && (0x40 == (buffer & 0x40)))
	  {
		  r_msb = 1;
		}
		else
		{
		  r_msb = 0;
		}

	  //MSB gruen
		if ((MODE_RAW == mode) && (0x20 == (buffer & 0x20)))
	  {
		  g_msb = 1;
		}
		else
		{
		  g_msb = 0;
		}

	  //MSB blau
		if ((MODE_RAW == mode) && (0x10 == (buffer & 0x10)))
	  {
		  b_msb = 1;
		}
		else
		{
		  b_msb = 0;
		}

	  //Sequenz R,G,B beginnt
	  ser_step = SERIAL_BYTE1;
	}
  else
  { 

		switch (ser_step)
		{
			//erstes Datenbyte
			case SERIAL_BYTE1:
				//Daten im RGB-Modus?
				if (MODE_RGB == mode)
				{
					/* Sollwert aus LUT uebernehmen (VDR schickt den Index) */
					rot_soll_rgb = rot_lut[buffer & 0x1F];
				}
				else
				//Daten im Raw PWM-Modus?
				if (MODE_RAW == mode)
				{
					//MSB aus Startbyte holen
					if (1 == r_msb)
					{
						buffer |= 0x80;
					}
					//direkt raus auf die PWM
					PWM_ROT_OUT = buffer;
				}
				//Umschalten aufs naechste Byte
				ser_step = SERIAL_BYTE2;
			break;
			
			//zweites Datenbyte
			case SERIAL_BYTE2:
				//Daten im RGB-Modus?
				if (MODE_RGB == mode)
				{
					/* Sollwert aus LUT uebernehmen (VDR schickt den Index) */
					gruen_soll_rgb = gruen_lut[buffer & 0x1F];
				}
				else
				//Daten im Raw PWM-Modus?
				if (MODE_RAW == mode)
				{
					//MSB aus Startbyte holen
					if (1 == g_msb)
					{
						buffer |= 0x80;
					}
					//direkt raus auf die PWM
					PWM_GRUEN_OUT = buffer;
				}
				//Umschalten aufs naechste Byte
				ser_step = SERIAL_BYTE3;
			break;
			
			//drittes Datenbyte
			case SERIAL_BYTE3:
				//Daten im RGB-Modus?
				if (MODE_RGB == mode)
				{
					/* Sollwert aus LUT uebernehmen (VDR schickt den Index) */
					blau_soll_rgb = blau_lut[buffer & 0x1F];
				}
				else
				//Daten im Raw PWM-Modus?
				if (MODE_RAW == mode)
				{
					//MSB aus Startbyte holen
					if (1 == b_msb)
					{
						buffer |= 0x80;
					}
					//direkt raus auf die PWM
					PWM_BLAU_OUT = buffer;
				}
				//fettich, warten aufs naechste Startbyte
				ser_step = SERIAL_START;
			break;
	
			default:
				//nix tun, aufs naechste Startbyte warten
				ser_step = SERIAL_START;
			break;
		}
	}
}

/*****************************************/
/* INT0-ISR (Button 1)                   */
/*****************************************/
SIGNAL(SIG_INTERRUPT0)     
/* signal handler for external interrupt int0 */
{
		//RAW-Modus (ungeregelt) anwaehlen
		mode = MODE_RAW;
    if (pwm_rot <= 250)
		{
		  pwm_rot += 5;
      PWM_ROT_OUT = pwm_rot;
    }
    
    if (pwm_gruen <= 250)
		{
		  pwm_gruen += 5;
      PWM_GRUEN_OUT = pwm_gruen;
    }
		
    if (pwm_blau <= 250)
		{
		  pwm_blau += 5;
      PWM_BLAU_OUT = pwm_blau;
		}	
}

/*****************************************/
/* INT1-ISR (Button 2)                   */
/*****************************************/
SIGNAL(SIG_INTERRUPT1)     
/* signal handler for external interrupt int0 */
{
		//RAW-Modus (ungeregelt) anwaehlen
		mode = MODE_RAW;
    if (pwm_rot >= 5)
		{
		  pwm_rot -= 5;
      PWM_ROT_OUT = pwm_rot;
		}	

    if (pwm_gruen >= 5)
		{
		  pwm_gruen -= 5;
      PWM_GRUEN_OUT = pwm_gruen;
		}	

    if (pwm_blau >= 5)
		{
		  pwm_blau -= 5;
      PWM_BLAU_OUT = pwm_blau;
		}	
}


/*****************************************/
/* Analog/Digital Wandler initialisieren */
/*****************************************/
void adc_init(void)
{

	/* externe Referenzspannung und AD-Wandlerkanal 0 ( ADC0 ) auswaehlen */
	ADMUX = 0;

	/* AD-Wandler einschalten und Prescaler = 128 einstellen ( enstpricht 86,4 khz Wandlertakt ) */
	ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);

	/* Spezialfunktionen ausschalten */
	SFIOR = 0;
}


/*****************************************/
/* Character ueber RS-232 ausgeben       */
/*****************************************/
void putc(unsigned char c)
{
	  /* warten bis Puffer leer ... */
	  while ( !( UCSRA & (1<<UDRE)) )
	  {
		  ;
	  }	
	  /* Zeichen senden */
	  UDR = c;
}