Tirdad Sadri NejadAmir Kazemi
Published © GPL3+

Tiny Isolated Dimmer with Linearly Corrected Output

Unlike many simple dimmers, this dimmer dims a resistive load based on the delievered power, not just a simple fraction of delay.

IntermediateFull instructions provided4 hours762
Tiny Isolated Dimmer with Linearly Corrected Output

Things used in this project

Hardware components

microchip - ATtiny13
×1
Triac thyristor
×1

Software apps and online services

Microchip Studio
Microchip Studio
Proteus suite

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

the circuit

it's the schematic :)

Code

Main.c

C/C++
it's pretty straightforward and commented.
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

void init_priphs(void);
void readADC();
void sup_delay(uint16_t del);
uint8_t adc_val;

//LED brightness to compare with counter values
const uint8_t LED1_B[4] = {20,80,150,255};
//the 8 level of dimmer values
const uint16_t Dimmers[8] = {0,253,369,468,531,631,760,900};

int main()
{
	//check the function below
	init_priphs();
	//enable interrupts
	sei();

	while(1)
	{
		//read the pot value
		readADC();

		//==============================
		//change light according to pot value
		if (adc_val < 128)
		{
			if (TCNT0 < (LED1_B[adc_val / 40]))
			{
				PORTB &= ~(1 << PORTB3);
			}
			else	PORTB |= (1 << PORTB3);
			PORTB |= (1 << PORTB4);
		}
		else
		{
			if (TCNT0 < (LED1_B[adc_val / 80]))
			{
				PORTB &= ~(1 << PORTB4);
			}
			else	PORTB |= (1 << PORTB4);
		}
		//==============================
	}
}


void init_priphs(void)
{
	//SETUP GPIO
	DDRB	|= (1 << DDB3) | (1 << DDB4);//LED outputs
	DDRB	|= (1 << DDB0);//triac fire outputs
	PORTB	|= (1 << PB1);//pullup for ZCD,interrupt
	MCUCR	= 3;//RisingEdge interrupted
	GIMSK	= (1 << INT0);
	
	//SETUP ADC
	DDRB	&= ~(1 << DDB2);//ADC1 channel
	ADMUX	= (1 << ADLAR) | 1;//left adjust, set AIN3
	ADCSRA	= (1 << ADSC) | (1 << ADEN) | 5;//start in free running with 32 prescaler
	ADCSRA	|= (1 << ADSC);
	DIDR0	= (1 << ADC1D);//disable the schmitt trigger
	
	
	//SETUP TIMER TIME_BASE
	TCCR0B	= 1; //prescale of 1
}



ISR(INT0_vect)
{
	//wait according to the Dimming table
	sup_delay(Dimmers[adc_val / 34]);
	//fire triac
	PORTB |= (1 << PORTB0);
	_delay_us(30);
	PORTB &=~(1 << PORTB0);
}

//simple function to read the ADC, some oversampling done to smooth it out
void readADC()
{
	uint16_t ad_temp=0;
	for (uint8_t i = 0; i <20; i++)
	{
		ADCSRA |= (1 << ADSC);
		while(!(ADCSRA & (1<<ADIF)));
		ad_temp += ADCH;
	}
	adc_val = (uint8_t)(ad_temp / 20);
}
//delay function. you can't use inbuilt macro as it needs a constant value
//but we have to feed it a variable
void sup_delay(uint16_t del)
{
	while (del--)
	{
		_delay_us(10);
	}
}

Credits

Tirdad Sadri Nejad

Tirdad Sadri Nejad

6 projects • 19 followers
AI masters degree student. a guitar player and an electronic hobbyist.
Amir Kazemi

Amir Kazemi

4 projects • 3 followers
Material science engineering MSc nano material researcher

Comments