Implemented dimming based on amount of ambient light.
Requires a phototranistor (TEPT4400) and series resistor (I used 2.2 kOhm) on ADC0 (pin 23). Range is quite limited though, so will probably need to modify hardware a bit and do some more software tuning.
This commit is contained in:
parent
4380334947
commit
ff698171aa
|
@ -362,8 +362,11 @@ all: $(OBJDIR) $(TARGET_HEX)
|
|||
$(OBJDIR):
|
||||
mkdir $(OBJDIR)
|
||||
|
||||
# need to add -lm to the end of CC line for ELF target due to compiler / linker
|
||||
# bug; see
|
||||
# http://stackoverflow.com/questions/8188849/avr-linker-error-relocation-truncated-to-fit
|
||||
$(TARGET_ELF): $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(SYS_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(SYS_OBJS) -lm
|
||||
|
||||
$(DEP_FILE): $(OBJDIR) $(DEPS)
|
||||
cat $(DEPS) > $(DEP_FILE)
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
function lightlevelmapping()
|
||||
MINBRIGHTNESS = 2;
|
||||
MAXBRIGHTNESS = 20;
|
||||
|
||||
LIGHTSENSOR_BOTTOM = 270;
|
||||
LIGHTSENSOR_TOP = 350;
|
||||
|
||||
l = [LIGHTSENSOR_BOTTOM - 10:LIGHTSENSOR_TOP + 10];
|
||||
b = zeros(size(l));
|
||||
|
||||
LIGHTSENSOR_SCALE = 1024;
|
||||
LIGHTSENSOR_BASE = 1.35;
|
||||
|
||||
if (LIGHTSENSOR_BASE <= 1)
|
||||
error 'LIGHTSENSOR_BASE must be > 1';
|
||||
end
|
||||
|
||||
brightness_per_unit_light = floor(floor( LIGHTSENSOR_SCALE * (MAXBRIGHTNESS - MINBRIGHTNESS)) / ...
|
||||
(LIGHTSENSOR_TOP - LIGHTSENSOR_BOTTOM))
|
||||
|
||||
LIGHTSENSOR_BASE^(MAXBRIGHTNESS - MINBRIGHTNESS) * (MAXBRIGHTNESS - MINBRIGHTNESS) + MINBRIGHTNESS
|
||||
|
||||
% b = floor(brightness_per_unit_light * (l - LIGHTSENSOR_BOTTOM) / LIGHTSENSOR_SCALE ) + MINBRIGHTNESS;
|
||||
b1 = (LIGHTSENSOR_BASE.^(brightness_per_unit_light * (l - LIGHTSENSOR_BOTTOM) / ...
|
||||
LIGHTSENSOR_SCALE)) / LIGHTSENSOR_BASE^(MAXBRIGHTNESS - MINBRIGHTNESS) * (MAXBRIGHTNESS - ...
|
||||
MINBRIGHTNESS) + MINBRIGHTNESS;
|
||||
b = floor( (LIGHTSENSOR_BASE.^floor(brightness_per_unit_light * (l - LIGHTSENSOR_BOTTOM) / ...
|
||||
LIGHTSENSOR_SCALE)) / LIGHTSENSOR_BASE^(MAXBRIGHTNESS - MINBRIGHTNESS) * (MAXBRIGHTNESS - ...
|
||||
MINBRIGHTNESS)) + MINBRIGHTNESS;
|
||||
|
||||
[brightness_per_unit_light * (l - LIGHTSENSOR_BOTTOM) / LIGHTSENSOR_SCALE; l]
|
||||
|
||||
b1(l <= LIGHTSENSOR_BOTTOM) = MINBRIGHTNESS;
|
||||
b1(l >= LIGHTSENSOR_TOP) = MAXBRIGHTNESS;
|
||||
b(l <= LIGHTSENSOR_BOTTOM) = MINBRIGHTNESS;
|
||||
b(l >= LIGHTSENSOR_TOP) = MAXBRIGHTNESS;
|
||||
|
||||
b2 = round(b1);
|
||||
|
||||
figure
|
||||
plot(l, b1, l, b, l, b2)
|
||||
A = axis;
|
||||
A(3) = -1;
|
||||
A(4) = MAXBRIGHTNESS + 1;
|
||||
axis(A);
|
||||
grid on
|
|
@ -3,6 +3,7 @@
|
|||
#include <DS1302.h> // I use the library that Matt Sparks created
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
#include <math.h>
|
||||
|
||||
// uncomment the following to speed up the timer for testing
|
||||
//#define TESTMODE
|
||||
|
@ -61,11 +62,30 @@ void SWversion(void);
|
|||
*/
|
||||
|
||||
|
||||
// set USELIGHTSENSOR to 1 to use ambient light sensor connected to ADC0 (pin
|
||||
// 23)
|
||||
#define USELIGHTSENSOR 1
|
||||
// analog input put to which ambiend light sensor is connected
|
||||
#define LIGHTSENSOR_INPUTPIN 0
|
||||
// bottom of light sensor (ambient light values at or lower than this level will
|
||||
// be mapped to MINBRIGHTNESS)
|
||||
#define LIGHTSENSOR_BOTTOM 270
|
||||
// top of light sensor (ambient light values at or higher than this level will
|
||||
// be mapped to MAXBRIGHTNESS)
|
||||
#define LIGHTSENSOR_TOP 300
|
||||
// weight for exponential decaying averaging (actual weigth is 2 ^ LIGHTSENSOR_WEIGHT)
|
||||
#define LIGHTSENSOR_WEIGHT 4
|
||||
// base of exponential mapping (must be > 1)
|
||||
#define LIGHTSENSOR_BASE 1.35
|
||||
|
||||
// DAY Brightness setting 0 = off 20 = full
|
||||
#define DAYBRIGHTNESS 20
|
||||
#define MAXBRIGHTNESS 20
|
||||
// start MAXBRIGHTNESS at DAYLIGHTHOUR (7 am)
|
||||
#define DAYLIGHTHOUR 7
|
||||
// NIGHT Brightness setting 0 = off 20 = full
|
||||
#define NIGHTBRIGHTNESS 15
|
||||
#define MINBRIGHTNESS 2
|
||||
// start MINBRIGHTNESS at NIGHTLIGHTHOUR (7 pm)
|
||||
#define NIGHTLIGHTHOUR 19
|
||||
|
||||
|
||||
|
||||
|
@ -79,8 +99,12 @@ void SWversion(void);
|
|||
#define INIT_TIMER_COUNT 6
|
||||
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT
|
||||
|
||||
|
||||
|
||||
// there are only 20 brightness levels and 1024 lightsensor levels -> we need to
|
||||
// scale the brightness levels to something closer to avoid having to work with
|
||||
// floating point numbers
|
||||
#define LIGHTSENSOR_SCALE 10
|
||||
unsigned int brightness_per_unit_light = ((1 << LIGHTSENSOR_SCALE) * (MAXBRIGHTNESS -
|
||||
MINBRIGHTNESS)) / (LIGHTSENSOR_TOP - LIGHTSENSOR_BOTTOM);
|
||||
|
||||
int hour=12, minute=0, second=00;
|
||||
static unsigned long msTick =0; // the number of Millisecond Ticks since we last
|
||||
|
@ -115,6 +139,8 @@ int LED4PIN=16; // Arduino analog 2
|
|||
|
||||
int current_brightnes=0;
|
||||
|
||||
char ambient_light_to_brightness[1024];
|
||||
|
||||
|
||||
// define the language to be used for this project:
|
||||
#include LANGUAGE // The language pack
|
||||
|
@ -146,6 +172,8 @@ void print_DS1302time()
|
|||
|
||||
void setup()
|
||||
{
|
||||
int n;
|
||||
|
||||
// initialise the hardware
|
||||
// initialize the appropriate pins as outputs:
|
||||
pinMode(LEDClockPin, OUTPUT);
|
||||
|
@ -165,7 +193,9 @@ void setup()
|
|||
pinMode(LED3PIN, OUTPUT);
|
||||
pinMode(LED4PIN, OUTPUT);
|
||||
|
||||
current_brightnes=DAYBRIGHTNESS;
|
||||
analogReference(DEFAULT);
|
||||
|
||||
current_brightnes=MAXBRIGHTNESS;
|
||||
|
||||
|
||||
Serial.begin(9600); // setup the serial port to 9600 baud
|
||||
|
@ -202,6 +232,28 @@ void setup()
|
|||
else Serial.println("absent");
|
||||
}
|
||||
|
||||
// compute ambient light level to brightness level mapping
|
||||
for (n = 0; n < sizeof(ambient_light_to_brightness); n++)
|
||||
{
|
||||
if (n <= LIGHTSENSOR_BOTTOM)
|
||||
ambient_light_to_brightness[n] = MINBRIGHTNESS;
|
||||
else if (n >= LIGHTSENSOR_TOP)
|
||||
ambient_light_to_brightness[n] = MAXBRIGHTNESS;
|
||||
else
|
||||
{
|
||||
ambient_light_to_brightness[n] =
|
||||
round( pow((double) LIGHTSENSOR_BASE, (
|
||||
(double) brightness_per_unit_light * ((double) n - (double)
|
||||
LIGHTSENSOR_BOTTOM) / (double) (1 << LIGHTSENSOR_SCALE))) / pow((double)
|
||||
LIGHTSENSOR_BASE, (double) (MAXBRIGHTNESS - (double) MINBRIGHTNESS)) *
|
||||
((double) MAXBRIGHTNESS - (double) MINBRIGHTNESS) + (double) MINBRIGHTNESS );
|
||||
/* Serial.print(n);
|
||||
Serial.print(": ");
|
||||
Serial.println(ambient_light_to_brightness[n], DEC); */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// determine whether we are running on old or new hardware
|
||||
// old hardware tied the push buttons to ground using 4k7 resistors
|
||||
// and relied on the buttons to pull them high
|
||||
|
@ -353,6 +405,10 @@ void SWversion(void) {
|
|||
|
||||
void loop(void)
|
||||
{
|
||||
static unsigned long int lightlevel_avg;
|
||||
unsigned long int lightlevel_sample;
|
||||
static char n_lightlevel_samples = 0;
|
||||
static unsigned int counter = 0;
|
||||
|
||||
#ifdef TESTMODE
|
||||
second=59;
|
||||
|
@ -373,13 +429,6 @@ void loop(void)
|
|||
digitalWrite(13,HIGH);
|
||||
delay(50);
|
||||
digitalWrite(13,LOW);
|
||||
|
||||
#ifndef TESTMODE
|
||||
if (second%5==0) {
|
||||
Serial.print(second);
|
||||
Serial.print("..");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -401,10 +450,56 @@ void loop(void)
|
|||
|
||||
// set the brightnes level based on the current hour - night=7pm - 6.59am
|
||||
//
|
||||
if ((hour <7) | (hour >=19))
|
||||
current_brightnes=NIGHTBRIGHTNESS;
|
||||
#if (USELIGHTSENSOR == 1)
|
||||
lightlevel_sample = analogRead(LIGHTSENSOR_INPUTPIN);
|
||||
|
||||
// update average
|
||||
if (n_lightlevel_samples < (1 << LIGHTSENSOR_WEIGHT))
|
||||
{
|
||||
// add (1 << (LIGHTSENSOR_WEIGHT - 1)) to average before division so that
|
||||
// the average is round()-ed instead of floor()-ed
|
||||
lightlevel_avg = (n_lightlevel_samples * lightlevel_avg +
|
||||
lightlevel_sample + (1 << (LIGHTSENSOR_WEIGHT - 1))) /
|
||||
(n_lightlevel_samples + 1);
|
||||
n_lightlevel_samples++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// do not update n_lightlevel_samples to prevent overflow
|
||||
|
||||
// add (1 << (LIGHTSENSOR_WEIGHT - 1)) to average before division so that
|
||||
// the average is round()-ed instead of floor()-ed
|
||||
lightlevel_avg = ( ((1 << LIGHTSENSOR_WEIGHT) - 1) * lightlevel_avg +
|
||||
lightlevel_sample + (1 << (LIGHTSENSOR_WEIGHT - 1))) >> LIGHTSENSOR_WEIGHT;
|
||||
}
|
||||
|
||||
// compute new brightness level
|
||||
/*
|
||||
// linear method
|
||||
if (lightlevel_avg <= LIGHTSENSOR_BOTTOM)
|
||||
current_brightnes = MINBRIGHTNESS;
|
||||
else if (lightlevel_avg >= LIGHTSENSOR_TOP)
|
||||
current_brightnes = MAXBRIGHTNESS;
|
||||
else
|
||||
{
|
||||
current_brightnes = (brightness_per_unit_light * (lightlevel_avg -
|
||||
LIGHTSENSOR_BOTTOM)) / (1 << LIGHTSENSOR_SCALE) + MINBRIGHTNESS;
|
||||
} */
|
||||
|
||||
current_brightnes = ambient_light_to_brightness[lightlevel_avg];
|
||||
|
||||
Serial.print("lightsensor: ");
|
||||
Serial.print(lightlevel_sample);
|
||||
Serial.print(" / ");
|
||||
Serial.print(lightlevel_avg);
|
||||
Serial.print(", brightness: ");
|
||||
Serial.println(current_brightnes);
|
||||
#else
|
||||
if ((hour < DAYLIGHTHOUR) | (hour >= NIGHTLIGHTHOUR))
|
||||
current_brightnes=MINBRIGHTNESS;
|
||||
else
|
||||
current_brightnes=DAYBRIGHTNESS;
|
||||
current_brightnes=MAXBRIGHTNESS;
|
||||
#endif
|
||||
|
||||
|
||||
// test to see if both buttons are being held down
|
||||
|
|
Loading…
Reference in New Issue