So my old Renault 16 has a dimming switch to dim the Dashboard backlight. I am changing over from incandescent bulbs to LED's also because i wanted to change the color from Green to Blue.
Bulbs get their power through a low resistance potmeter, and share common Ground.
Now of course i want the LED's to be dimmable as well.
Now there are several ways of doing this. Using a pot to control the voltage of a PNP transistor was my first attempt, but getting the voltage division proved a bit to fiddly.
Then i tried using a LM317 regulator to provide a variable voltage, which showed promise, but then i thought to switch to PWM dimming, using an ATtiny13a
I use a PNP - transistor (BC557B) to open the power to the LED's a 10 K resistor gets GND from a PC817 Opto-coupler which is driven by the ATtiny.
Works fine, but i found that the resolution makes quite a big step between fully-off and just on. I know it also has something to do with the type of LED, but these are the blue ones i have for now and i still have plenty of them.
#define PWM_PIN 0
#define POT_PIN A3
void setup() {
pinMode(PWM_PIN, OUTPUT);
}
void loop() {
uint16_t val = analogRead(POT_PIN);
val = map(val, 0, 1023, 0, 254); // never fully off
analogWrite(PWM_PIN, val);
}
Simple enough.
Now i found this project, and i can manage 8 bit PWM like that, but increasing the resolution caused it to flicker due to slow speed.
this is the implementation of PWM on the ATtiny in the microcore, and i decided to combine these 2 things and came to this
#define POT_PIN A3
#define RESO (0xff >> 6)
volatile uint8_t i = 0;
volatile uint8_t pwmValH = 0;
volatile uint8_t pwmValL = 0;
void setup() {
noInterrupts();
DDRB |= (1 << PB0);
TCCR0B = _BV(CS01);
TIMSK0 |= (1 << TOIE0);
interrupts();
}
void loop() {
uint16_t val = (analogRead(POT_PIN));
delay(1);
pwmWrite(val);
bright++;
}
void pwmWrite(uint16_t duty) {
noInterrupts();
pwmValH = (duty >> 8) & RESO;
pwmValL = duty & 0xff;
interrupts();
}
ISR(TIM0_OVF_vect) {
i++;
i &= RESO;
if (i == pwmValH) {
switch (pwmValL) {
case 0:
TCCR0A &= ~_BV(COM0A1); // stop pwm
PORTB &= ~(1 << PB0); // set pin LOW
break;
case 255:
TCCR0A &= ~_BV(COM0A1); // stop pwm
PORTB |= (1 << PB0); // set pin HIGH
break;
default:
OCR0A = pwmValL;
TCCR0A |= _BV(WGM00) | _BV(COM0A1); // start PWM
}
}
else {
TCCR0A &= ~_BV(COM0A1); // stop pwm
if (i < pwmValH) {
PORTB |= (1 << PB0); // set pin HIGH
}
else {
PORTB &= ~(1 << PB0); // set pin LOW
}
}
}
which does provide me with a small enough step for minimum brightness, but it seems that on the crossover between the steps there is some inaccuracy. No i wonder if anybody knows how that could be helped, or has any other bright ideas.