這是一個用51單片機通過過零檢測來調整可控硅的導通角從而實現調光調壓,其中過零電路用一個p620光耦,220v這端的電阻是40k,這是一個已經有成熟應用的例子,現在公開給51hei單片機論壇的網友.
視頻演示:
全部代碼下載:http://www.raoushi.com/f/kkggl.rar
以下是c51源代碼部分:
#include <reg52.H>
#include "intrins.h"
#define _50msL_ 50000*0.9216
#define _50msH_ 50000*0.9216
#define _1ms_ 922
#define _10ms_ 9216
#define _50us 46 //50*0.9216
#define uchar unsigned char
#define uint unsigned int
void delaySTD_ms(uchar ms); // 延時毫秒@12M,ms最大值255
unsigned char scankey();
sbit PWM_PIN= P1^0;
sbit PWM_TESTLED= P1^2;
/*在
/INT0為過零檢測,36v,注意安全!! 外接了兩個按鍵,用來調整占空比;
注意由于P1.1口也控制繼電器,因此杜絕字節賦值,不要出現如P1=1;
如果把 PWM 波形的頻率提高,也可以用 LED 觀察到漸亮漸暗的效果,目前看,只是閃爍的時間發生變化。
220v調光設定為1kHz@12M,每周期1000us,分為10次比較合理,每CELL為1000us!
*/
sbit key1pressed= P1^5;
sbit key2pressed= P1^6;
sbit key3pressed= P1^7;
#define LEVEL0 0
#define LEVEL1 1
#define LEVEL2 2
#define LEVEL3 3
#define LEVEL4 4
#define GRADE 10 //單位次,調光多少級?推薦10級,比較合理(實際只能顯示7級,請加MAP映射處理!);20級的話到13級就會出現誤判讀!
//GRADE固定為10,以便完成9級調光!!!sw除開滅是8級調光,號稱10級!
#define CELL (9216/GRADE) //10為半個市電周期,一個波
//#define CELL 10000 //10000us,實際是9216
#define KEYPRESSTIME 7 //10ms,key bound delay time
int iShiftPoint;
int b; //b一定要有符號整型!
uint timemultiplex;
uint timemultiplex_maxvalue;
//------------------------------------------
void main()
{
PWM_PIN = 0; //先關了PWM,免得一開始就給5V導通220V了!!安全考慮!!
timemultiplex_maxvalue=3;
timemultiplex=1;
//外部過零中斷
IT0 = 1; //1為邊沿觸發
EX0 = 1;
//開啟定時中斷
TMOD = 0x01; //T0定時方式1
b =8;//初亮度調整
iShiftPoint=b;
TH0 = (65536-CELL*iShiftPoint) / 256; //歷史:50ms@12MHz,這里定時沒意義,通過外中斷過零定時
TL0 = (65536-CELL*iShiftPoint) % 256;
ET0 = 1;
TR0 = 1;//TR0 = 1;定時只是為了計算延時時長!10ms即10000us,分成10種時長,由t1產生這10種時長
//定時器1初始化:
TMOD |= 0x10; //T1定時方式1
TH1 = (65536-_50us) / 256;
TL1 = (65536-_50us) % 256;
ET1 = 1;
TR1 = 1;//TR0 = 1;定時只是為了計算延時時長!10ms即10000us,分成10種時長,由t1產生這10種時長
EA = 1;
//調光級別從0到4共5級別 能調光級別811~910
#define MAXAA 998
#define MINAA 11
while(1)
{
unsigned char buf;
//以下為自動化按鍵測試
b =MINAA;
if (b>MAXAA)
{
// delaySTD_ms(500);
// delaySTD_ms(500);
// delaySTD_ms(500);
// delaySTD_ms(500);
// b=MINAA;
PWM_PIN=0;
EA=0;
}
if (b<MINAA)
b=MINAA;
b+=30;
delaySTD_ms(500);
continue;
//以上為自動化按鍵測試
// while(1)
// {
// unsigned char buf;
buf=scankey();
if(buf==1) //調滅
{
b++;
}
if(buf==2)
{//二鍵調亮。b--是亮,765,從滅到月牙到亮
b--;
}
if(buf==3)
{//3鍵盤關閉繼電器,同時也得關PWM燈才得滅;再按一次3鍵,則全亮
PWM_PIN=!PWM_PIN;
}
if (b>(GRADE-1)) b=LEVEL4;//仍然最亮 //歷史:在這里調整周期.不能無限增加
if (b<0) b=LEVEL0;//必須設置為>20,<1,不能設置為>19,<0,否則最后亮了就熄滅一下
iShiftPoint=b;
//other while
/*
delaySTD_ms(500);
delaySTD_ms(500);
delaySTD_ms(500);
delaySTD_ms(500);
timemultiplex_maxvalue++;
if (timemultiplex_maxvalue>40) timemultiplex_maxvalue=40;
*/
}
}
//------------------------------------------
void X0_INT(void) interrupt 0
{
//過零檢測,來個中斷就表過零了,過零時才能重新基準一次10ms。
// EA = 0;
TR0=0;
// PWM_PIN = 0;
TH0 = (65536-CELL*iShiftPoint) / 256; //1000ms@12MHz,這里定時沒意義,只是個時間流逝。通過外中斷過零定時
TL0 = (65536-CELL*iShiftPoint) % 256;
TR0=1;
// EA = 1;
}
void time0(void) interrupt 1
{
/*
TR0 = 0;
TH0 = (65536-CELL*iShiftPoint) / 256; //歷史:50ms@12MHz,這里定時沒意義,通過外中斷過零定時
TL0 = (65536-CELL*iShiftPoint) % 256;
TR0 = 1;
*/
int i;
// 1次外部中斷產生,其滅會等待CELL*iShiftPoint us之后就開pwm,直至下次過零點關掉 ;CELL*iShiftPoint us由定時器來計算
PWM_PIN = 1;
/*
//隨便兩語句延時
for (i=0;i<100;i++)
{
_nop_();
_nop_();
_nop_();
}
*/
TR1 = 0;
TH1 = (65536-_50us) / 256; //歷史:50ms@12MHz,這里定時沒意義,通過外中斷過零定時
TL1 = (65536-_50us) % 256;
TR1 = 1;
//關要!
// PWM_PIN = 0;//亮個4us關,效果比一直亮好
}
//------------------------------------------
void time1(void) interrupt 3
{
timemultiplex++;
if (timemultiplex==timemultiplex_maxvalue)
{
timemultiplex=0;
//關要!
PWM_PIN = 0;
}
}
/*********************************************************/
// 延時子程序
/*********************************************************/
void delaySTD_ms(uchar ms) // 標準延時毫秒@12M,ms最大值255
{
uchar i;
while(ms--)
for(i = 0; i < 124; i++);
}
//那個鍵按下返回幾
unsigned char scankey()
{
if (key1pressed==0)
{
delaySTD_ms(KEYPRESSTIME);
if (key1pressed==0)
{
while(!key1pressed);
delaySTD_ms(KEYPRESSTIME);
return 1;
}
}
if (key2pressed==0)
{
delaySTD_ms(KEYPRESSTIME);
if (key2pressed==0)
{
while(!key2pressed);
delaySTD_ms(KEYPRESSTIME);
return 2;
}
}
if (key3pressed==0)
{
delaySTD_ms(KEYPRESSTIME);
if (key3pressed==0)
{
while(!key3pressed);
delaySTD_ms(KEYPRESSTIME);
return 3;
}
}
return 0; //0表示沒按鍵按下,更表示誤按了快速彈起了。
}
