?? dim.c
字號:
/*
* Digital AC Dimmer
*
* Copyright (c) 2005-2008 Chris Fallin <chris@cfallin.org>
* Placed under the modified BSD license
*
* dim.c: interrupt-driven AC dimmer module
*/
#include "dim.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
// PD2 (INT0) is AC negative detect, PD3 is triac trigger
#define ACDET 4
#define TRIAC 8
#define nop asm volatile("nop")
// triac needs pulse width of 48 nops (clk = 16 MHz) to reliably trigger
// (empirically determined for an NTE 56003 triac)
#define triac_nop \
nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; \
nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; \
nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; \
nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
// minimum phase delay, in timer ticks of 500 ns -- we need some buffer
// on either end of the intensity scale, near the zero crossings, to
// ensure that we don't try to trigger during the crossing or on
// the other side of it.
#define MIN_DELAY 1000
unsigned char lvl = 0;
unsigned int lvl_counts[256];
void dim_initialize()
{
DDRD = (DDRD & 0xf3) | 0x08; // PD3 out, PD2 in
TCCR1A = 0x00;
TCCR1B = 0x02; // timer: Clock / 8 == 2 MHz (mains halfcycle ~ 16667 counts)
// initialize by timing one half-cycle
unsigned int halfcount;
while(!(PIND & ACDET)) nop; // wait until we're in a negative half-cycle
while((PIND & ACDET)) nop; // now wait for the beginning of pos half-cycle
TCNT1 = 0;
while(!(PIND & ACDET)) nop; // wait for the negative half-cycle again
halfcount = TCNT1;
// now calculate the timing table
int i;
int step = halfcount >> 8;
int value = 0;
for (i = 255; i >= 0; i--, value += step)
{
lvl_counts[i] = value;
// enforce minimum and maximum phase delay limits
if (lvl_counts[i] < MIN_DELAY)
lvl_counts[i] = MIN_DELAY;
if (lvl_counts[i] > (halfcount - MIN_DELAY))
lvl_counts[i] = (halfcount - MIN_DELAY);
}
// now set up the AC detector interrupt (INT0)
MCUCR = (MCUCR & 0xfc) | 0x01; // ISC01:ISC00 = 01b: int on rise or fall
GICR = (GICR & 0x3f) | 0x40; // enable INT0
// enable the timer compare interrupt
TIMSK |= 0x10;
}
// AC zero-crossing interrupt
SIGNAL(SIG_INTERRUPT0)
{
OCR1A = lvl_counts[lvl]; // start timer for precalculated phase delay
TCNT1 = 0;
}
// timer compare trigger interrupt
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
// trigger the triac
if (lvl != 0)
{
PORTD |= TRIAC;
triac_nop;
PORTD &= ~TRIAC;
}
}
void dim_set_level(char l)
{
lvl = l;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -