/* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /* This is the main part of the LED light controller program. * It handles all peripherals (power, fan, channels, IR, serial) */ /* This program is specifically designed for hardware version A, * with schematic revision 2, and layout revision 5. */ #include /* Standard Integer Types */ #include /* Standard IO facilities */ #include /* General utilities */ #include /* Boolean */ #include /* Strings */ #include /* AVR device-specific IO definitions */ #include /* Convenience functions for busy-wait delay loops */ #include /* Interrupts */ #include "main.h" #include "uart.h" #include "ir_nec.h" #include "settings.h" volatile uint8_t* PORTS[CHANNELS_1+CHANNELS_2] = {&PORTC,&PORTC,&PORTC,&PORTC,&PORTC,&PORTD,&PORTD,&PORTD,&PORTD,&PORTD}; volatile uint8_t* DDRS[CHANNELS_1+CHANNELS_2] = {&DDRC,&DDRC,&DDRC,&DDRC,&DDRC,&DDRD,&DDRD,&DDRD,&DDRD,&DDRD}; const uint8_t BITS[CHANNELS_1+CHANNELS_2] = {PC0,PC1,PC2,PC3,PC4}; /* global variables */ #define INPUT_MAX 255 /* max length for user input string */ char input[INPUT_MAX+2]; /* user input from USART */ volatile uint8_t input_i = 0; /* user input index */ volatile uint8_t pwr_ok; /* is power ok */ volatile uint8_t fan; /* fan signal state, to measure tachometer */ volatile uint8_t timer2_ovf = 0; /* to measure fan speed using timer 2 */ const uint16_t TIMER2_PRESCALE[8] = {0,1,8,32,64,128,256,1024}; /* timer 2 CS2[2:0] values */ volatile uint16_t tachometer = 0; /* the tachometer time (from timer) */ volatile uint8_t ir; /* IR signal state, to measure IR code */ const uint16_t TIMER1_PRESCALE[8] = {0,1,8,64,256,1024,0,0}; /* timer 1 CS1[2:0] values */ volatile uint16_t ir_tick; /* number of counter ticks per millisecond */ volatile uint8_t pulse = 0; /* pulse index within the burst */ #define PULSE_MAX 128 /* maximum number of pulses to save */ uint16_t burst[PULSE_MAX]; /* pulse times forming a burst (from timer) */ /* channel variables */ #define LEVELS 10 /* the number of PWM levels */ volatile uint8_t ch_tick = 0; /* the tick counter for the channel PWM */ /* flags, set in the interrupts and handled in the main program */ volatile bool uart_flag = false; /* an incoming activity on the UART */ volatile bool power_flag = false; /* a change in the power or fan */ volatile bool ir_flag = false; /* to process a burst */ volatile bool pwm_flag = false; /* to trigger a PWM tick */ volatile bool channel_flag = false; /* indicate a change in the channel PWM values */ /* UART receive interrupt */ ISR(USART_RX_vect) { input[input_i] = getchar(); /* save input */ input[input_i+1] = 0; /* always end the string */ if (input_i0) { /* save pulse, except the first */ burst[pulse-1] = (TCNT1*1000UL)/ir_tick; burst[pulse] = 0; } if (pulse0 && !ir_flag) { /* warm an burst is ready when the timeout triggered */ ir_flag = true; } } /* timer 0 interrupt used generate a PWM for the channels */ ISR(TIMER0_COMPA_vect) { /* timer 0 OCR0A match interrupt vector */ ch_tick = (ch_tick+1)%LEVELS; pwm_flag = true; } void ioinit(void) { /* configure power */ DDRB |= (1<>CS10]; /* timer 1 presacler */ if (0!=prescale) { ir_tick = F_CPU/(1000*prescale); /* ticks per ms */ OCR1A = (uint32_t)(15*F_CPU)/(1000*prescale); /* set clear time to 15 ms (no IR toggle should be longer) */ } TIFR1 &= ~(1<3) { ir_action(ir_data.address,ir_data.command); } } pulse = 0; /* reset burst */ ir_flag = false; } } return 0; } void uart_action(char c) { switch (c) { case 'l': PIND |= (1<0) { OCR0A--; } printf("decreasing LED: %u\n",OCR0A); break; case '+': if (OCR0A<0xff) { OCR0A++; } printf("increasing LED: %u\n",OCR0A); break; case 't': if (tachometer) { uint16_t prescale = TIMER2_PRESCALE[TCCR2B&((1<