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:
Admar Schoonen 2012-01-04 23:01:43 +01:00
parent 4380334947
commit ff698171aa
3 changed files with 160 additions and 16 deletions

View File

@ -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)

View 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

View File

@ -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