基于STC15L104E单片机模拟PWM调光小夜灯
搜索自己的原件库,发现上半年买的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版外部中断呐,连掉电唤醒都实现不了,那几个外部中断口都是摆设的.所以原本打算使用掉电模式作为关机状态的,但是唤醒不了(除了复位键),所以只好用外部硬件开关关机了....
废话不多说,贴程序,程序有标注,看不明白或有问题指教的贴出来,虚心接受.
#include "reg52.h"
#include "intrins.h"
#define ON 0 //LED是低电平有效
#define OFF 1
#define PWM_TIME 200 //计时器计数值
#define MODEL_ADDR 0x0000 //EEPEOM地址
#define PWM_CMP_ADDR 0x0200
sfr AUXR
sfr P3M1
sfr P3M0
sfr IAP_DATA =0xc2;
sfr IAP_ADDRH=0xc3;
sfr IAP_ADDRL=0xc4;
sfr IAP_CMD
sfr IAP_TRIG =0xc6;
sfr IAP_CONTR=0xc7;
sbit KEY1=P3^0;
sbit KEY2=P3^1;
sbit LED1=P3^2;
sbit LED2=P3^3;
unsigned char key_down,key_cont,key_up;
//donw为上升沿,cont为长效,up为下降沿
unsigned char pwm_cmp=1; //PWM比较值
unsigned char pwm_num=0; //PWM计数值
unsigned char led_model=0; //LED模式
unsigned char pwm_delay=0; //延时暂存
unsigned char cmp_temp;
//led_cmp的暂存,用于运算是否写入EEPROM
//计时器0初始化
void timer_init()
{
TMOD=0x00; //模式0,16位自动装载模式
EA=1;
ET0=1;
TR0=1;
AUXR|=0x80; //1T模式
TL0=65536-PWM_TIME;
TH0=(65536-PWM_TIME)>>8;
}
//EEPROM读写后防止误操作
void eeprom_dle()
{
IAP_CONTR=0;
IAP_CMD
IAP_TRIG =0;
IAP_ADDRH=0;
IAP_ADDRL=0;
}
//擦除EEPROM扇区
void eeprom_erase(unsigned int addr)
{
IAP_CONTR=0x83;
IAP_CMD
IAP_ADDRL=addr;
IAP_ADDRH=addr>>8;
IAP_TRIG =0x5a;
IAP_TRIG =0xa5;
_nop_();_nop_();_nop_();
//eeprom_dle();
}
//读取EEPROM,因为EEPROM只存两个变量,故读取直接改变变量
void read_eeprom()
{
IAP_CONTR=0x83;
IAP_CMD
IAP_ADDRL=MODEL_ADDR;
IAP_ADDRH=MODEL_ADDR>>8;
IAP_TRIG =0x5a;
IAP_TRIG =0xa5;
_nop_();_nop_();_nop_();
led_model=IAP_DATA;
IAP_CMD
IAP_ADDRL=PWM_CMP_ADDR;
IAP_ADDRH=PWM_CMP_ADDR>>8;
IAP_TRIG =0x5a;
IAP_TRIG =0xa5;
_nop_();_nop_();_nop_();
pwm_cmp=IAP_DATA;
if(pwm_cmp>180)pwm_cmp=0x01;
eeprom_dle();
}
//写EEPROM
void write_eeprom(unsigned int add,unsigned char dat)
{
if(PCON&0x20)return; //如果电压过低,不操作
eeprom_erase(add);
IAP_CONTR
IAP_CMD
IAP_ADDRL
IAP_ADDRH
IAP_DATA
STC15L104E单片机模拟PWM调光小夜 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)