这是一个用51单片机通过过零检测来调整可控硅的导通角从而实现调光调压,其中过零电路用一个p620光耦,220v这端的电阻是40k,这是一个已经有成熟应用的例子,现在公开给51hei单片机论坛的网友.
视频演示:
全部代码下载:http://www.51hei.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表示没按键按下,更表示误按了快速弹起了。 }