//*****使用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显示时间 } }