设计要求:
STC15W101
芯片,1脚按键接地,5脚PWM输出用于调光,6脚接红LED,7脚接绿LED,8脚接蓝LED,三个自检灯负极接地(高电平亮)
通电时,芯片自检,三个灯闪亮一下。
开机时,按住按键,达到1秒钟时,三个指示灯按8绿→7红→6蓝的顺序依次点亮一下,一次只亮一个灯,每个灯亮的时间约1秒,这期间5脚无输出。
三个自检灯依次亮完后,蓝灯熄灭,返回到绿灯长亮,此时5脚有输出,是最小档(即1档,占空比20%)。
点一下按键(要求是按下去的时刻),会增加一档PWM,指示灯点亮的组合也不同(此时是绿+蓝,2档),依次点击按钮,共有五档,5脚占空比逐档变大,第五档最大(100%),再按一下又回到最低档(绿灯亮,占空比20%),继续按又增加一档,指示灯的组合也
同步变化……点击按钮可以反复循环……12345档的PWM宽度依次加大(20%,40%,60%,80%,100%),每档对应点亮的指示灯是:1、绿。2、绿+蓝。3、蓝。4、蓝+红。5、红。
不管在哪个档位工作时,按住按键达到1秒时就关机,三个指示灯和负载全灭。芯片进入掉电状态。
PWM频率500Hz。
程序部分:
/************* 功能说明 **************
使用
timer0模拟16通道PWM驱动程序。
定时器中断频率一般不要超过100KHZ, 留足够的时间给别的程序运行.
本例子使用33.1776MHZ时钟, 50K的中断频率, 100级PWM, 周期为2ms.
中断里处理的时间不超过4us, 占CPU时间大约为25%.
pwm 频率为500HZ
******************************************/
#include <reg52.h>
#define MAIN_Fosc 33177600UL //定义主时钟
#define Timer0_Rate 50000 //中断频率
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
//sfr AUXR = 0x8E;
#define Timer0_Reload (65536UL -(MAIN_Fosc / Timer0_Rate)) //Timer 0 重装值
//************** PWM8 变量和常量以及IO口定义 ***************
//******************** 8通道8 bit 软PWM ********************
#define PWM_DUTY_MAX 100 // 0~255 PWM周期, 最大255
#define PWM_ON 1 // 定义占空比的电平, 1 或 0
#define PWM_OFF (!PWM_ON)
#define PWM_ALL_ON (0xff * PWM_ON)
///
#define LAMP_ON 1
#define LAMP_OFF 0
//I/O设置
sbit pwm_out=P3^0;
sbit red_lamp=P3^1;
sbit green_lamp=P3^2;
sbit blue_lamp=P3^3;
sbit key_in=P3^4;
//
//档位占空比设置
#define one_dang 20 //一档
#define two_dang 40 //二档
#define three_dang 60 //三档
#define four_dang 80 //四档
#define five_dang 100 //五档 six seven eight nine ten
#define dianan 2000 //点按
#define duanan 4000 //短按
#define changan 8000 //长按
u8 dangshu; //在某个档,存某个档的占空比数
u8 dangcount; //档位存储
u8 pwm_duty; //周期计数值
u16 key_jishu;
bit key_down;
bit kaiji_f; //标志开机
bit huandang; //档位记录
/**********************************************/
void delay(u16 x)
{
do{x=x-1;WDT_CONTR=0x3c;}while(x>0);
}
//
//开机自检
void kaiji_lamp_out(void)
{
u8 i;
//绿红兰依次点亮一下,每次只亮一个灯,每个亮灯时间约0.4秒(0.2~0.4秒)
green_lamp=LAMP_ON;
for(i=0;i<100;i++){delay(15000);}
green_lamp=LAMP_OFF;
red_lamp=LAMP_ON;
for(i=0;i<100;i++){delay(15000);}
red_lamp=LAMP_OFF;
blue_lamp=LAMP_ON;
for(i=0;i<100;i++){delay(15000);}
blue_lamp=LAMP_OFF;
for(i=0;i<100;i++){delay(15000);}
green_lamp=LAMP_ON;
pwm_out=PWM_ON;
for(i=0;i<100;i++){delay(15000);}
pwm_out=PWM_OFF;
}
/////按键
void int2() interrupt 10
{
INT_CLKO&=0xef; //先关中断,系统会自动清除中断标志
}
/////
void huandang_chuli()
{
if(huandang)
{
huandang=0;
green_lamp=blue_lamp=red_lamp=LAMP_OFF;
switch(dangcount)
{
case 0: dangshu=one_dang; green_lamp=LAMP_ON; break;
case 1: dangshu=two_dang; green_lamp=blue_lamp=LAMP_ON; break;
case 2: dangshu=three_dang; blue_lamp=LAMP_ON; break;
case 3: dangshu=four_dang; blue_lamp=red_lamp=LAMP_ON; break;
case 4: dangshu=five_dang; red_lamp=LAMP_ON; break;
default: dangshu=one_dang; green_lamp=LAMP_ON; break;
}
}
}
void main(void)
{
//char i;
green_lamp=blue_lamp=red_lamp=LAMP_OFF;
dangshu=one_dang;
dangcount=0;
key_jishu=0;
pwm_out=PWM_OFF;
key_down=0;
kaiji_f=0;
huandang=0;
pwm_duty=0;
//INT_CLKO|=0x10; //打开按键唤醒功能
AUXR |= (1<<7); // Timer0 set as 1T mode
TMOD &= ~(1<<2); // Timer0 set as Timer
TMOD &= ~0x03; // Timer0 set as 16 bits Auto Reload
TH0 = Timer0_Reload / 256; //Timer0 Load
TL0 = Timer0_Reload % 256;
ET0 = 1; //Timer0 Interrupt Enable
PT0 = 1; //高优先级
//TR0 = 1; //Timer0 Run
EA = 1; //打开总中断
while(1)
{
if(!key_in){ if(key_jishu<60000){key_jishu++;}
if(!kaiji_f) //若是关机时,长按则开机
{
if(key_jishu>duanan)
{kaiji_f=1;kaiji_lamp_out();pwm_out=PWM_ON; dangshu=one_dang;TR0 = 1;key_jishu=0;do{delay(1000);}while(!key_in);}
else
{
delay(200);
if(key_in){key_jishu=0;}
}
}
else //开机时
{key_down=1;
delay(200);
if(!key_in)
{
if((key_jishu>(dianan-2000))&&(key_jishu<(dianan+1000))&&(kaiji_f)) //换档
{huandang=1;if(dangcount<4)dangcount++;else{dangcount=0;}}
huandang_chuli();
key_jishu=0;
do{delay(1000);
if(key_jishu<60000){key_jishu++;}
if((key_jishu>changan)&&(kaiji_f)) //按1秒关机
{key_down=0;kaiji_f=0; key_jishu=0;TR0 = 0;pwm_out=PWM_OFF;green_lamp=blue_lamp=red_lamp=LAMP_OFF;INT_CLKO|=0x10;PCON|=0x02;}
}while(!key_in);
key_down=0;
key_jishu=0;
}
}
}
delay(200); //假如10000次延时200US,如果不是需要调整
}
}
/********************** Timer0 40us中断函数 ************************/
void timer0 (void) interrupt 1
{
if(++pwm_duty == PWM_DUTY_MAX) //PWM周期结束,重新开始新的周期
{
pwm_duty = 0;
pwm_out=PWM_ON;
}
if(pwm_duty>=dangshu){pwm_out=PWM_OFF;}
}
现在的问题是:
一直不断电工作,长按按键1秒关机后可以掉电,再开机,按第一下无反应,但已经重新上电了(此时灯不亮,但有十几mA电流,电池会耗尽哦!!!),松手再长按一次才可以开机成功(亮灯开始自检),为什么要按两下?怎么解决?
另外,按键有点跳档的状况(就像连续按了两次一样),如何改善?特别是自检完后,1档转2档时,按一下很容易到3档(按键没问题)
如何精简程序?(现在编译后是530字节,如何小于500字节,这样可以选择STC15W100芯片)
恳请各位高手帮忙分析改善程序,小弟感激不尽。。。
一周热门 更多>