desk-light with brightness and color temperature (remote) control
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

125 lines
2.6 KiB

#include "main.h"
struct cRGB led[LED_COUNT];
void adc_init (void) {
// enable internal vref
ADMUX |= (1 << REFS1) | (1 << REFS0);
// enable adc in free running mode with /64 prescaler, fixed adc0 input
ADCSRA |= (1 << ADEN) | (1 << ADFR) | (1 << ADPS2) | (1 << ADPS1);
}
void fan_init (void) {
// Set PB1/OC1A to output
DDRB |= (1 << 1);
// Set on match, clear on TOP
TCCR1A = ((1 << COM1A1) | (1 << COM1A0));
TCCR1B = ((1 << CS11) | (1 << CS10) | (1 << WGM13));
ICR1 = 2048;
}
void fan_set (unsigned int i) {
// sunon fan reliably starts up at ~768
i %= 255;
if (i >= 1) {
OCR1A = 1024 - (i * 4);
} else {
OCR1A = 2048;
}
}
void led_output(unsigned int brightness, unsigned int temperature, unsigned char en) {
unsigned int amber,warm,cold;
// translate temperature to color mixing
amber = ranged(1023 - x * 2, 1023)
cold = ranged(x * 2 - 1023, 1023)
if (x > 512) {
warm = 2047 - x * 2
} else {
warm = x * 2
}
// apply brightness
amber = (amber * brightness) / 255
if (en == 0) {
amber = 0;
warm = 0;
cold = 0;
}
for (int i = 0; i < LED_COUNT; i++) {
led[i].r = amber;
led[i].g = cold; // remap color order to actual leds
led[i].b = warm;
}
}
int ranged (int i, int max) {
if (i >= max) return max;
if (i <= 0) return 0;
return i;
}
int main (void) {
fan_init();
fan_set(0);
encoder_init();
uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU));
// vars for serial decode state machine
unsigned int c;
int ser_step = 0;
int temperature = 0;
char brightness = 0;
unsigned char enabled = 1;
// state vars if encoder was turned or depressed since last run
int diff = 0;
char btn = 0;
while (1) {
diff = encoder_read();
btn = encoder_read_btn();
if (diff != 0) {
// encoder was turned
if (btn == 1) {
temperature = ranged(temperature + (diff*7), 240);
} else {
brightness = ranged(brightness + (diff*2), 100);
}
}
// read serial port values
c = uart_getc();
if (!( c & UART_NO_DATA || c & UART_FRAME_ERROR || c & UART_OVERRUN_ERROR || c & UART_BUFFER_OVERFLOW)) {
if (c == 0xFF) {
ser_step = 0;
} else {
switch (ser_step++) {
case 0:
brightness = ranged(c, 100);
break;
case 1:
temperature = ranged(c, 240);
break;
}
}
}
// output new values
led_output(temperature, brightness, enabled);
ws2812_setleds (led, LED_COUNT);
// echo current settings over serial port
uart_putc(0xFF);
uart_putc(brightness);
uart_putc(temperature);
}
}