您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 酒店餐饮 > 基于STC15L104E单片机模拟PWM调光小夜灯
基于STC15L104E单片机模拟PWM调光小夜灯(2012-10-2314:44:44)转载▼标签:单片机stc15模拟pwmled调光杂谈分类:硬件鉴于宿舍晚上会被宿管灭灯,所以制作了一个小台灯在关灯后窥探用,但是舍友陈某反应光线太强影响其睡眠,所以决心做个可以调光的LED小夜灯,窥探自己的隐私,让别人睡觉去吧...搜索自己的原件库,发现上半年买的STC15L104E一直没用,所以打算就用单片机来控制了,当然,如果用模拟电路,可能几个元件就可以完成了,但是,模拟对我来说更难设计,所以,,,好吧,废话多了下面贴电路:其实也没什么,纯粹是IO操作,两个开光是调光用,AMS117是降压用,AMP4953就相当于开关,后面的电感电容电路是防止出现闪烁的,额,如果有问题的话可以贴出来.下面介绍模拟PWM操作,毕竟不是硬件的PWM而且要顾及程序长度,所以模拟出来的PWM频率600HZ,不过用在LED上应该足够了.设PWM基数为PWM_NUM,PWM比较输出值为PWM_CMP.主要思路就是利用单片机内部计时器按一定周期中断,然后在中断服务程序里令PWM_NUM加一,判断是否小于PWM_CMP比较值,如果小于,则IO输出高,否则输出低,这样,我们就可以通过修改PWM_CMP的值来调节IO输出脉宽,达到模拟PWM的效果了.PWM周期=计时器中断时间/PWM_NUM;好吧,我的文字表达能力不好,贴张图来说明可能比较好:如图,假设PWM_CMP=6,PWM_NUM=16,也就是,PWM_NUM达到16后清零.每个计时器中断周期PWM_NUM自动加一,判断是否小于PWM_CMP,是则输出高电平,否则输出低电平,所以,如图所示,当PWM_NUM累加到6前,输出电平是一直是高的,知道PWM_NUM累加到6后,输出就拉低了,当PWM_NUM达到16后,清零,这时PWM_NUM又小于PWM_CMP,故PWM输出又为高了,周而复始,就达到模拟PWM的效果了,PWM周期就等于PWM_NUM重装周期.当然值得注意的是,因为判断是在中断服务程序中执行,所以计时器周期不能太短.好吧,贴整个完整的程序出来,它的功能我先说明一下.按下key1变亮,按下key2变暗,长按则连续调节,两个键一起按下改变显示方式,分别有四个模式,单个分别亮,两个亮,两个都不亮.每次改变亮度和模式都写入单片机EEPROM,开机读取EEPROM,这样便能开机保持上次关机的状态,不用每次打开都要调节了.说到这我就要吐槽了,这STC15系列A版外部中断呐,连掉电唤醒都实现不了,那几个外部中断口都是摆设的.所以原本打算使用掉电模式作为关机状态的,但是唤醒不了(除了复位键),所以只好用外部硬件开关关机了....废话不多说,贴程序,程序有标注,看不明白或有问题指教的贴出来,虚心接受.#includereg52.h#includeintrins.h#defineON0//LED是低电平有效#defineOFF1#definePWM_TIME200//计时器计数值#defineMODEL_ADDR0x0000//EEPEOM地址#definePWM_CMP_ADDR0x0200sfrAUXR=0x8e;sfrP3M1=0xb1;sfrP3M0=0xb2;sfrIAP_DATA=0xc2;sfrIAP_ADDRH=0xc3;sfrIAP_ADDRL=0xc4;sfrIAP_CMD=0xc5;sfrIAP_TRIG=0xc6;sfrIAP_CONTR=0xc7;sbitKEY1=P3^0;sbitKEY2=P3^1;sbitLED1=P3^2;sbitLED2=P3^3;unsignedcharkey_down,key_cont,key_up;//donw为上升沿,cont为长效,up为下降沿unsignedcharpwm_cmp=1;//PWM比较值unsignedcharpwm_num=0;//PWM计数值unsignedcharled_model=0;//LED模式unsignedcharpwm_delay=0;//延时暂存unsignedcharcmp_temp;//led_cmp的暂存,用于运算是否写入EEPROM//计时器0初始化voidtimer_init(){TMOD=0x00;//模式0,16位自动装载模式EA=1;ET0=1;TR0=1;AUXR|=0x80;//1T模式TL0=65536-PWM_TIME;TH0=(65536-PWM_TIME)8;}//EEPROM读写后防止误操作voideeprom_dle(){IAP_CONTR=0;IAP_CMD=0;IAP_TRIG=0;IAP_ADDRH=0;IAP_ADDRL=0;}//擦除EEPROM扇区voideeprom_erase(unsignedintaddr){IAP_CONTR=0x83;IAP_CMD=0x03;IAP_ADDRL=addr;IAP_ADDRH=addr8;IAP_TRIG=0x5a;IAP_TRIG=0xa5;_nop_();_nop_();_nop_();//eeprom_dle();}//读取EEPROM,因为EEPROM只存两个变量,故读取直接改变变量voidread_eeprom(){IAP_CONTR=0x83;IAP_CMD=0x01;IAP_ADDRL=MODEL_ADDR;IAP_ADDRH=MODEL_ADDR8;IAP_TRIG=0x5a;IAP_TRIG=0xa5;_nop_();_nop_();_nop_();led_model=IAP_DATA;IAP_CMD=0x01;IAP_ADDRL=PWM_CMP_ADDR;IAP_ADDRH=PWM_CMP_ADDR8;IAP_TRIG=0x5a;IAP_TRIG=0xa5;_nop_();_nop_();_nop_();pwm_cmp=IAP_DATA;if(pwm_cmp180)pwm_cmp=0x01;eeprom_dle();}//写EEPROMvoidwrite_eeprom(unsignedintadd,unsignedchardat){if(PCON&0x20)return;//如果电压过低,不操作eeprom_erase(add);IAP_CONTR=0x83;IAP_CMD=0x02;IAP_ADDRL=add;IAP_ADDRH=add8;IAP_DATA=dat;IAP_TRIG=0x5a;IAP_TRIG=0xa5;_nop_();_nop_();_nop_();eeprom_dle();}//模式切换voidmodel_change(){//因为模式切换无非是改变P3^2,P3^3状态而led_model是直接赋值给P3的(在T0中断函数里)//所以相应的只改变led_model相应位即可led_model+=4;write_eeprom(MODEL_ADDR,led_model);//将模式写入EEPROMwhile((key_cont&0x03)==0x03);//直到按键释放}voidmain(){P3M1=0x0f;P3M0=0x0f;//P3为开漏模式PCON=0x00;//清除低电压标志(必须)LED2=LED1=OFF;read_eeprom();//读取状态timer_init();//计数器初始化cmp_temp=pwm_cmp;while(1){cmp_temp=pwm_cmp;//储存pwm比较值if((key_down&0x01)&&(pwm_cmp180)){//如果KEY1按下,比较值加一,相应的是LED变亮pwm_cmp++;pwm_delay=0;}if((key_down&0x02)&&(pwm_cmp1)){//如果KEY2按下,比较值减一,相应的是LED变暗pwm_cmp--;pwm_delay=0;}if(pwm_delay30)//延时,延时时间为PWM周期*30{//如果按键长按,则每次延时周期自加减,实现长按快速调光if((key_cont&0x01)&&(pwm_cmp180))pwm_cmp++;if((key_cont&0x02)&&(pwm_cmp1))pwm_cmp--;pwm_delay=0;//重新计时//如果两个按键都是按下的,则改变模式if((key_cont&0x03)==0x03)model_change();}//如果比较值改变了,而且只是上升沿和下降沿,则写入EEPROM//因为EEPROM操作时间较长,所以如果每次改变都写入,则在长按状态下会出现闪烁现象//所以只在单次按下或按键长按释放时写入EEPROMif((pwm_cmp^cmp_temp)&&(key_down|key_up)){//关停LED再做写入操作,如果写入操作前LED为亮的状态//则在整个EEPROM操作时间里LED都为亮,故出现爆闪现象EA=0;P3|=0x0c;write_eeprom(PWM_CMP_ADDR,pwm_cmp);EA=1;}}}voidtimer0()interrupt1{unsignedcharread_data=(P3&0x03)^0x03;//按键扫描key_down=read_data&(read_data^key_cont);//按键上升沿key_up=key_cont&(read_data^key_cont);//按键下降沿key_cont=read_data;//按键长效值pwm_num++;//PWM周期数自加if(pwm_numpwm_cmp)//控制PWM输出P3&=(0xf3|led_model);//开elseP3|=0x0c;//关if(pwm_num200)//PWM周期{pwm_num=0;pwm_delay++;}}里要说说程序下载的问题,因为这片单片机是没有外部晶振的,所以下载时要确认单片机完全掉电,就连串口的GND端都要从电路板上拔出.下载软件我用的是STC-ISPV4.88beta版本,下载时选好型号,然后修改最低波特率为2400,在我实际应用中,默认的4800是写不进去的,RC频率按自己要求修改,其他的默认就好了.单片机如果第一次写可能要将P3.2和P3.3接GND,如果勾选下次冷启动P3.2/P3.3与下载无关(默认),那以后就不用在乎它们的状态了.好了,程序也贴了,也没什么可以供我诉说的了,实物太丑陋,就不贴了.
本文标题:基于STC15L104E单片机模拟PWM调光小夜灯
链接地址:https://www.777doc.com/doc-4562483 .html