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.
 
 

175 lines
3.9 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;
}
}
//############################################################################
//HSV to RGB 8Bit
//Farbkreis h = 0 bis 360 (Farbwert)
// s = 0 bis 100 (Dunkelstufe)
// v = 0 bis 100 (Farbsättigung)
//Rückgabewert r,g,b als Pointer
void hsv_to_rgb (unsigned int h,unsigned char s,unsigned char v,
unsigned char* r, unsigned char* g, unsigned char* b)
{
unsigned char diff;
//Winkel im Farbkeis 0 - 360 in 1 Grad Schritten
//h = (englisch hue) Farbwert
//1 Grad Schrittweite, 4.25 Steigung pro Schritt bei 60 Grad
if(h<61){
*r = 255;
*b = 0;
*g = (425 * h) / 100;
}else if(h < 121){
*g = 255;
*b = 0;
*r = 255 - ((425 * (h-60))/100);
}else if(h < 181){
*r = 0;
*g = 255;
*b = (425 * (h-120))/100;
}else if(h < 241){
*r = 0;
*b = 255;
*g = 255 - ((425 * (h-180))/100);
}else if(h < 301){
*g = 0;
*b = 255;
*r = (425 * (h-240))/100;
}else if(h< 360){
*r = 255;
*g = 0;
*b = 255 - ((425 * (h-300))/100);
}
//Berechnung der Farbsättigung
//s = (englisch saturation) Farbsättigung
s = 100 - s; //Kehrwert berechnen
diff = ((255 - *r) * s)/100;
*r = *r + diff;
diff = ((255 - *g) * s)/100;
*g = *g + diff;
diff = ((255 - *b) * s)/100;
*b = *b + diff;
//Berechnung der Dunkelstufe
//v = (englisch value) Wert Dunkelstufe einfacher Dreisatz 0..100%
*r = (*r * v)/100;
*g = (*g * v)/100;
*b = (*b * v)/100;
}
void led_fill (unsigned int h, unsigned int v, unsigned char en) {
// work as hsv model, hue = color temperature, value = brightness
// saturation = 1 for now
unsigned char amber,warm,cold;
hsv_to_rgb (h, 100, (unsigned char)v, &amber, &warm, &cold);
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_fill(temperature, brightness, enabled);
ws2812_setleds (led, LED_COUNT);
// echo current settings over serial port
uart_putc(0xFF);
uart_putc(0xFF);
uart_putc(brightness);
uart_putc(temperature);
}
}