/************************************************************/ /* 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; }