• 回复
  • 收藏
  • 点赞
  • 分享
  • 发新帖

STC15F104E制作的15小时(或150分钟)定时器

//*****使用STC15F104E制作的计时器*****
//1. 上电为关闭状态。
//2. 长按按键上电可转换模式,默认模式1:10分-150分 步进10分钟设置,共15档设置。模式2:1小时-15小时 步进1小时设置,共15档设置。
//3. 按一下按键可以递增计时时间,1、2、3...一直可以累加到15档,再按则关闭(计时时间为0)。
//4. 使用4个LED分别按8421码指示总计时时间,最多15档。
//5. 计时期间,继电器吸合,计时结束后继电器释放,蜂鸣器响起。
//6. 计时期间相应的LED每秒闪一次。
//7. 可以断电记忆未完成的时间,来电接着继续计时。考虑到STC单片机EEPROM寿命问题,故10分钟保存一次计时状态。
//8. 因STC15F104E上电后P3.3是低电平,故P3.3接按键,以避免副作用。
//9. 使用内部振荡11.0592M

#include 
#include 

typedef unsigned char  UINT8;
typedef unsigned int   UINT16;

//***************************************************************************
//定义Flash操作等待时间及允许IAP/ISP/EEPROM 操作的常数
#define ENABLE_ISP 0x83 //系统工作时钟<12MHz 时,对IAP_CONTR 寄存器设置此值

sbit relay= P3^5; 	
sbit key1 = P3^3;	//因STC15F104E加电P3.3为低电平,为避免副作用,作为按键输入。
sbit led1 = P3^4;
sbit led2 = P3^2;
sbit led3 = P3^1;
sbit led4 = P3^0;

UINT8 sec, min,count;	 //时间计数
UINT8 buzz_time = 0;	 //蜂鸣器响铃时间设置
UINT8 Delay_counting = 0;//按键消抖

bit light, save;
bit min_hour = 0 ;		 //分和时计数选择  模式选择:0=时钟计数  1=分钟计数
bit system_time = 0;	 //系统时间标记	
bit run_stop = 0; 		 //时间计数与停止  0=停止计数  1=允许计数
bit buzz_run = 0 ;		 //1 = 启动蜂鸣器  0= 关闭蜂鸣器

#define MAX_HOURS   15	 //时设置最大值




//***************************************************************************
void IAP_Disable()
{
    //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
    //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
    IAP_CONTR = 0;  //关闭IAP 功能
    IAP_CMD   = 0;  //清命令寄存器,使命令寄存器无命令,此句可不用
    IAP_TRIG  = 0;  //清命令触发寄存器,使命令触发寄存器无触发,此句可不用
    IAP_ADDRH = 0;
    IAP_ADDRL = 0;
}

//***************************************************************************
//eeprom读一字节
//入口: addr = 要读取字节的地址
//返回: 读出的字节
//***************************************************************************
UINT8 Byte_Read(UINT16 addr)
{
    IAP_DATA = 0x00;
    IAP_CONTR = ENABLE_ISP; //打开IAP 功能, 设置Flash 操作等待时间
    IAP_CMD = 0x01;         //IAP/ISP/EEPROM 字节读命令

    IAP_ADDRH = addr >> 8;  //设置目标单元地址的高8 位地址
    IAP_ADDRL = addr;       //设置目标单元地址的低8 位地址
    
    IAP_TRIG = 0x5A;   //先送5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
    IAP_TRIG = 0xA5;   //送完A5h后,ISP/IAP 命令立即被触发起动
    _nop_();    _nop_();    _nop_();
    //IAP_Disable();  //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
                      //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
    return (IAP_DATA);  //返回读到的数据
}

//***************************************************************************
//eeprom写一字节
//入口: addr = 要写字节的地址
//      ch = 要写入的字节数据
//***************************************************************************
void Byte_Write(UINT16 addr, UINT8 ch)
{
    IAP_CONTR = ENABLE_ISP; //打开 IAP 功能, 设置Flash 操作等待时间
    IAP_CMD = 0x02;         //IAP/ISP/EEPROM 字节编程命令
    
    IAP_ADDRH = addr >> 8;  //设置目标单元地址的高8 位地址
    IAP_ADDRL = addr;       //设置目标单元地址的低8 位地址
    
    IAP_DATA = ch;        //要编程的数据先送进IAP_DATA 寄存器
    IAP_TRIG = 0x5A;   //先送5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
    IAP_TRIG = 0xA5;   //送完A5h后,ISP/IAP 命令立即被触发起动
    _nop_();    _nop_();    _nop_();
    //IAP_Disable();  //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
                      //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}

//***************************************************************************
//eeprom扇区擦除
//入口: sect_addr = 扇区地址
//***************************************************************************
void Sector_Erase(UINT16 sect_addr)
{
    IAP_CONTR = ENABLE_ISP; //打开IAP 功能, 设置Flash 操作等待时间
    IAP_CMD = 0x03;         //IAP/ISP/EEPROM 扇区擦除命令
    
    IAP_ADDRH = (sect_addr & 0xFE00) >> 8; //设置目标单元地址的高8 位地址
    IAP_ADDRL = sect_addr;                 //设置目标单元地址的低8 位地址

    IAP_TRIG = 0x5A;   //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
    IAP_TRIG = 0xA5;   //送完A5h 后,ISP/IAP 命令立即被触发起动
    _nop_();    _nop_();    _nop_();
    //IAP_Disable();  //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
    //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}




//***************************************************************************
//**Run and stop**
//***************************************************************************
void BeginRun()
{
    relay = 0;
    led1 = led2 = led3 = led4 = 1;
    run_stop = 1;
    sec = min = 0;
}

//***************************************************************************
void StopRun()
{
    relay = 1;
    run_stop = 0;
    led1 = led2 = led3 = led4 = 1;
    sec = min = 0;
    count = 0;
}

//***************************************************************************
//**定时器**
//***************************************************************************
void Init()		//50毫秒@11.0592MHz
{
    AUXR &= 0x7F;	//定时器时钟12T模式
    TMOD &= 0xF0;	//设置定时器模式
    TL0 = 0x00;		//设置定时初值
    TH0 = 0x4C;		//设置定时初值
    TF0 = 0;		//清除TF0标志
    TR0 = 1;		//启动定时器0计时
    ET0 = 1;
    EA = 1;
    
}

//***************************************************************************
//定时器0中断
//***************************************************************************
void Timer0() interrupt 1
{
	   system_time = 1 ; //系统时间标记
}




//***************************************************************************
//**模式:按时钟计数**
//***************************************************************************
void time_hour()
{
	static UINT8 tim0, tim1, tim2;
	if(1==system_time && 1==run_stop)
	{
		system_time = 0;
		if(++tim0 >= 10)    //500ms
	    {
	        tim0 = 0;
	        light = !light;
	        if(++tim1 >= 2) //1s
	        {
	            tim1 = 0;
	            if(++sec >= 60) //1m
	            {
	                if(++tim2 >= 10)    //10m
	                {
	                    tim2 = 0;
	                    save = 1;
	                }
	                sec = 0;


	                if(++min >= 60) //1h
	                {
	                    min = 0;
	                    if(count>=1){count--;if(0==count){buzz_run = 1;}}
						else
	                    {
	                        StopRun();
	                        Sector_Erase(0);	//计时结束后清除保存的信息,以防下次加电继续计时。					
	                    }
	                }

	            }
	        }
	    }
	}

}	  


 
//***************************************************************************
//**模式:按分钟计数**
//***************************************************************************
void time_min()
{
	static UINT8 tim0, tim1, tim2;
	if(1==system_time && 1==run_stop)
	{
		system_time = 0;
		if(++tim0 >= 5)    //500ms
	    {
	        tim0 = 0;
	        light = !light;
	        if(++tim1 >= 4) //1s
	        {	
	            tim1 = 0;
	            if(++sec >= 60) //1min
	            {
					sec = 0;
					
	                if(++tim2 >= 10)    //10min
	                {	
	                    tim2 = 0;
	                    save = 1;
						if(count>=1){count--;if(0==count){buzz_run = 1 ;}}
						else 
						{					
							StopRun();			//停止计数
							Sector_Erase(0);	//计时结束后清除保存的信息,以防下次加电继续计时。							
						}
	                }		                
	            
	            }
	        }
		}
	}   
}


//***************************************************************************
//**蜂鸣器输出**
//***************************************************************************
void buzz_out()
{
	static UINT8 number;
	if(1==buzz_run){buzz_time = 50;buzz_run = 0;}//如果时间到........
	
	if(1 == system_time && 0== run_stop && buzz_time>=1)
	{
		system_time = 0;  //系统时间时标
		if(++number >= 5) //响铃间隔
		{
			number = 0 ;
			if(--buzz_time>=1)
			{
				key1 = ~key1;
			}	
			else {key1 = 1 ;buzz_time = 0;}
		} 

	}

}





//***************************************************************************
//**10us延时**用于按键消抖
//***************************************************************************
void Delay(void)
{
  UINT8 i,j,k;
 
  	 for(i=6;i>0;i--)
     for(j=1;j>0;j--)
     for(k=1;k>0;k--);
}



//***************************************************************************
//**按键设置时间**
//***************************************************************************
void ReadKey()
{
	if(buzz_time<=0)   //按键引脚与蜂鸣器输出共用,蜂鸣器响时按键不参与检测
	{
		if(!key1)					
		{
	
			if(Delay_counting < 40)  //按键消抖
			{
				Delay();			 //延时10us
				Delay_counting++;	
			}
			
	
	
	
			if(!key1 && Delay_counting == 40)	
			{
				count++ ; 
				if(count > MAX_HOURS)  count=0;
			    if(count == 0)
			    {
			        StopRun();
			    }
			    else
			    {
			        BeginRun();
			    }
				Delay_counting = 210 ;					
			}
	
		}
				else if(key1)Delay_counting = 0;//松手清0,待下一次延时消抖

	}

}




//***************************************************************************
//**检查时间**
//***************************************************************************
void check()	
{
	    
	
		if(count == 0 || count > MAX_HOURS)
	    {
	        count = 0;
	        run_stop = 0;
	    }
	    else
	    {
	        relay = 0;
	        run_stop = 1;
	    }

}




//***************************************************************************
//**8 4 2 1 LED显示时间**
//***************************************************************************
void display()
{
        if(count == 0)  //运行检查
    {
        StopRun();
    }
    else
    {
        led4 = count & 8 ? light : 1;	//显示时间
        led3 = count & 4 ? light : 1;
        led2 = count & 2 ? light : 1;
        led1 = count & 1 ? light : 1;
    }
}




//***************************************************************************
//**读EPPROM**
//***************************************************************************
void read_data()
{
	sec = Byte_Read(0);	 //读秒
    min = Byte_Read(1);	 //读分
    min_hour = Byte_Read(2);//读模式
    count = Byte_Read(3);	//读时间设置
}




//***************************************************************************
//**写EPPROM**
//***************************************************************************
void Write_epprom()
{
        if(save & TR0)  //保存到eeprom中
    {
        save = 0;
        Sector_Erase(0);//擦除EEPROM
        Byte_Write(0, sec);//写秒
        Byte_Write(1, min);//写分
        Byte_Write(2, min_hour);//写模式
        Byte_Write(3, count);//写设置时间
    }
}




//***************************************************************************
//**程序入口**
//***************************************************************************
void main()
{
    P3 = 0xFF;  //初始化端口状态
    light = 0;	
    save = 0; 	//10分钟保护一次时间数据

    Init();		//初始化定时器
  	read_data();//读epprom
	check();	//检查时间是否到
	buzz_time = 0;//蜂鸣器响铃时间清0

	//模式选择(按住按键上电)
	if(!key1){min_hour=~min_hour;buzz_time = 5;Sector_Erase(0);while(!key1){if(0==min_hour){led1 = 0;}else led4=0;};}	 
	//01 LED代表10 - 150 分钟模式	 08 LED代表1 - 15 小时模式



    while(min_hour == 1)//**模式:时间按时钟来计数**
    {

        ReadKey();  	//读取按键
		time_hour();	//时计数
		buzz_out();		//蜂鸣器输出
        Write_epprom(); //写epprom
		display();	    //8 4 2 1 LED显示时间
    }



	while(min_hour == 0)//**模式:时间按分钟来计数**
	{
	    ReadKey();  	//读取按键
		time_min();		//分钟计数
		buzz_out();		//蜂鸣器输出
		Write_epprom();	//写epprom
		display();		//8 4 2 1 LED显示时间
	}
}

 

 

全部回复(8)
正序查看
倒序查看
2014-04-28 08:39

不错挺好的帖子,也给其他想使用STC15F104的新人做了样本程序!支持!

0
回复
2014-04-28 08:41
@yueyunno1
不错挺好的帖子,也给其他想使用STC15F104的新人做了样本程序!支持!

个人建议你这个程序可以适当优化一下:

    1.按键释放问题,防止按一次多次动作;

    2.程序LED比较部分可以优化;                                                    

0
回复
shenx123
LV.10
4
2014-04-28 15:27
有没有详细的程序解释呢?
0
回复
178064035
LV.4
5
2014-04-28 18:37
@yueyunno1
个人建议你这个程序可以适当优化一下:    1.按键释放问题,防止按一次多次动作;    2.程序LED比较部分可以优化;                                                    

按键释放时是没有问题的,不存在多次动作。

 

 

 

0
回复
178064035
LV.4
6
2014-04-28 18:38
@shenx123
有没有详细的程序解释呢?
基本上就这样了 
0
回复
2014-04-28 23:30
@178064035
基本上就这样了[图片] 
其实可以把定时的时间再搞长点,或则设置几个档位,这样可能更实用一些,150MIN有时候都显得时间短了点!
0
回复
2014-04-29 00:20
@yueyunno1
其实可以把定时的时间再搞长点,或则设置几个档位,这样可能更实用一些,150MIN有时候都显得时间短了点!
说的是啊, 如果功能再多点就好了,反正程序可以随便编写的
0
回复
cltwolf
LV.5
9
2014-04-29 13:30

挺好的,振奋人心啊

0
回复