以下是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表示没按键按下,更表示误按了快速弹起了。
}