User Tools

Site Tools


projects:touch_led_dimmer:home

Touch LED dimmer

~~META:description abstract=A low voltage touch dimmer intended to be used with a LED strip.~~ microcontroller led touch

A low voltage dimmer intended to be used with a LED strip. Features remote touch buttons and power saving stand-by mode.

Features

  • High output power, up to 9A at 30V (depending on output MOSFET)
  • uC driven
  • any number of remote touch buttons
  • uC goes into deep-sleep mode when waiting for initial touch
  • while waiting for touch uC uses 4.8V battery pack, it starts the power supply when needed
  • optionnal solar cell to charge the battery pack in addition to the on-state charger

Ideas

Electronics

mainboard.svg

button.svg

Source code

main.c
#define F_CPU 8000000
 
// Sensor on AIN1 (PD7)
// PSU turn on on PXY
// Output on OC0A (PD6)
 
#define TOUCH_COUNTER_IRQ SIG_TIMER1_CAPTURE
#define TOUCH_RESET Bit(PORTX).bitY
 
#define TIMER_OVF SIG_TIMER0_OVERFLOW
#define TIMER_CMP SIG_TIMER0_COMPAREA
 
#define POWERON Bit(PORTX).bitY
#define STATUS Bit(PORTX).bitY
#define OUTPUT OCR0A
 
//global
volatile struct sensor {
	uint8_t cnt[64];
	uint8_t idx = 0x00;
	uint8_t noise_base = 0x10; // 16
	uint8_t trig_margin = 0x30; // 48
	uint8_t on = 0;
	uint16_t on_time = 0x0000;
};
volatile uint16_t heartbeat_timer = 0x0000;
 
//init
void init(void) {
	uint8_t i;
 
	// Timer 0 : touch length counter and output PWM @ 120Hz
	TCCR0A = 0x43; // Fast PWM with OC0A toggle
	TCCR0B = 0x0c; // Fast PWM + Presc. = 256 => 122 ovf/s
	TIMSK0 = 0x01; // Overflow irq enabled
	OUTPUT = 0x00;
 
	// Comparator : touch detection
	ADCSRB = 0x00; // No mux
	ACSR = 0x40; // No irq, internal 1.1V ref on positive input, sensor on AIN1, output capture enabled
	DIDR1 = 0x02; // Disable digital input on AIN1
 
	// Timer 1 : touch counter
	TCCR1A = 0x00; // No PWM
	TCCR1B = 0x01; // No noise canceler (takes 4 clock cycle if enabled), capture on falling edge, presc. = 1
	TCCR1C = 0x00;
	TIMSK1 = 0x20; // Capture irq enabled
 
	// I/O
	sbi(DDRX, PXY); // Status output
	sbi(DDRX, PXY); // PowerOn output
 
	STATUS = 1;
 
	for(i=0; i<64; i++) sensor.cnt[i] = 0x00;
}
 
//irq
SIGNAL(TOUCH_COUNTER_IRQ) { // Every 10us (avg), leaves 160 cycles minus 30-40 cycles, heavy load, must exit asap ...
	uint8_t c;
	// When here Vsensor went from 0 to 1.1V, must read ICR1 to get count (in 1/F_CPU units)
	// More than 0xff counts mean 32us (less than 32kHz) sensor input => bug
 
	TCNT1 = 0x0000;
	c = ICR1L; // Release hold onto ICR1 asap
 
	TOUCH_RESET = 1; // Empty capacitive load accumulated in sensor
	_delay_us(1);
	TOUCH_RESET = 0;
 
	if(c >= sensor.noise_base + sensor.trig_margin) {
		sensor.on = 1;
		sensor.on_time = 0x0001;
	}
	if(c <= sensor.noise_base) {
		sensor.on = 0;
		sensor.cnt[sensor.idx] = c;
		sensor.idx++;
	}
}
 
SIGNAL(TIMER_OVF) { // Every 8.192ms, leaves 64k cycles minus 1k cycles
	sensorUpdateNoiseBase();
	if(sensor.on) sensor.on_time++;
 
	if(heartbeat_timer) heartbeat_timer--;
	if(heartbeat_timer == 0x000c) STATUS = 1; // 0.1s
	if(!heartbeat_timer && !OUTPUT) {
		STATUS = 0;
		heartbeat_timer = 0x0262; // 5s
	}
}
 
// Utilities
void sensorUpdateNoiseBase(void) { // Takes something like 1k cycles ?
	uint8_t i;
	float nb = 0;
	for(i=0; i<64; i++) nb += 128 * sensor.cnt[i] / (128 - i); // Regressive averaging
	sensor.noise_base = (uint8_t)(nb / 64);
}
 
uint8_t sensorTriggered(uint8_t s) {
	if(sensor.on_time > s * 122.07) return 0;
	sensor.on_time = 0x0000;
	return 1;
}
 
// Use example
int main(void) {
	init();
 
	while(1) {
		/*if(sensorTriggered(3)) {
			// Sensor has been triggered for more than 3s
		}*/
		if(sensorTriggered()) {
			// Sensor has been triggered even for only 50us ...
			if(OUTPUT == 0xff) {
				OUTPUT = 0x00;
				POWERON = 0;
			}else{
				if(!POWERON) POWERON = 1;
				OUTPUT += 0x55;
			}
			_delay_ms(100); // Debounce
		}
	}
 
	return 0;
}

How to

Manual

projects/touch_led_dimmer/home.txt · Last modified: 2022/06/30 21:13 by 127.0.0.1