用STC系列单片机制作四位可预置计时器
/***************************************************************************************
用STC系列单片机制作四位可预置计时器_用UM5140X计时器电路改装
#:当使用的EEPROM起始地址不是C2~C7的IC时请到STC_EEPROM.h文件中注释#define EEPROM_C2_C7这行宏定义
功能: 具有二个按键,四位红色共阳极数码显示
P3.6长按 = 模式键、短按 = 移位、保存
P3.7长按 = 开始键、短按 = 加数、停止计时
具有正、倒;计分或计秒预设选择
具有预约、倒计时;开机功能分别输出一个1S低电平信号和一个长通低电平信号
使用说明:
A: 上电前若P1.0对地则为倒计秒//P1.1对地则为倒计分//其它状态组合未定义,建议不使用。
1: 长按P3.6口开关则先重新调出存在eeprom在的计时停止计时显示P***且第一个*以125ms闪烁
此时若依次短按P3.6口开关则移向下一位闪烁,在该位闪烁若短按P3.7口的开关则此位加1。
当第三个*闪烁时如果再短按一次P3.6口开关则保存此次设定值并退出设置状态,显示***。若
在闪烁10s内没有新键按下则自动退出设置状态并不保存此次设定值,显示***。
2: 长按P3.7口开关则开始计时显示***且最后一个dp点闪烁,在计时器运行中若短按P3.7口开关则
停止计时,10s内没有新键按下则自动重载预设值,显示***。
3: 当时间从预设值倒计到 000 时停止倒计时且P1^2口输出1S低电平信号(后自动变高)、P1.3口长通
低电平信号(短按P3.7口开关可关闭),10s后自动重载预设值。
程序设计:LBQ6914779402012-03-10
升级记录:
增加上电自动选择设置正计时与倒计时的初步程序编写。2012-3-11 23:08
P1.0 & P1.1 对地时为倒计秒
P1.0 对地时为倒计分
P1.1对地时为正计秒
P1.0 & P1.1 不接时为正计分 2012-3-11 09:33
/*********************************************************************/
#include<C:\Keil\C51\INC\STC\STC12C5A.h>
#include <intrins.h>
#include <STC_EEPROM.h>
#define nop _nop_()
#define uint unsigned int
#define uchar unsigned char
#define ulong unsigned long
#define SBI(Y,X) Y |= (1 << X) //让Y的X位置1
#define CBI(Y,X) Y &= ~(1 << X) //让Y的X位清0
#define set_keyP1//定义键盘口
#define KEYP3 //定义键盘口
#define set_djm0x00 //P1.0 & P1.1 对地时为倒计秒
#define set_zjm0x01 //P1.0 对地时为倒计分
#define set_djf0x02 //P1.1 对地时为正计秒
//#define set_zjf0x03 //P1.0 & P1.1 不接时为正计分
sbit P1_4 = P1^4; //位驱动
sbit P1_5 = P1^5; //位驱动
sbit P1_6 = P1^6; //位驱动
sbit P1_7 = P1^7; //位驱动
sbit OUT1S = P1^2; //到时间后输出约1S低电平
sbit OUTL = P1^3; //到时间后输出低电平,直到短按P3^7口开关键后才变高
sbit DP = P2^2;
sbit sw_mode = P3^6;//长按为模式键、短按移位
sbit sw_strat = P3^7; //长按为开始键、短按加数
bitDPP = 0, g_shi = 0,up_dn; //闪烁标志位、千位是否显示标志位、正计时与倒计时标志位为1时倒计。
static uchar yiwei = 4; //用于设置时间值时移位
static uint count = 0; //定时器0内的计数器
uintset_count,set_time,time1 = 0; //倒计数次数、设置的时间值(倒计时计数器)、正计时计数器
ucharshi,ge,sf,bf,xflash,flash1;//千位、百位、十位、个位、10s后自动退出设置、到时间后输出1s
ucharTtotal;//前面三个字节为设置好的时间,最后一个字节用来判断eeprom是否写过
/*********************函数声明*****************************************/
uchar key_function(void); //独立按键检测函数声明
void delay_ms(uint n);//12MHZ晶振时毫秒级CPU延时函数
void write_time(void);//转换时间值并写入
void abc_cba(unsigned int time); //转换时间值供显示
void Read_time(void);//读出存在eeprom内的时间值
/*********************** 共阳极数字编码********************************/
uchar code table[]={
//P2.0=E / P2.1=D / P2.2=DP / P2.3=C / P2.4=G / P2.5=B / P2.6=F / P2.7=A
// 0 12 34 5 6 78 9
0x14,0xd7,0x4c,0x45,0x87,0x25,0x24,0x17,0x04,0x05,0x0e,0xff};//0~9 P共阳极数字编码
/***************************************************************************/
/*********************************************************************
功能:12MHZ晶振时毫秒级CPU延时函数
参数: 1~65535(不可以为0)
结果:占用CPU方式延时与参数值相同的毫秒时间
备注:应用于1T单片机时i<600 ;12T单片机时i<125
XX: LBQ691477940 2011-02-19
/**************************************************************************/
void delay_ms(uint n)
{
uint i;
while(--n !=0)
{
#ifdef EEPROM_C2_C7
for(i = 0;i < 600;i++);
#else
for(i = 0;i < 125;i++);
#endif
}
}
/****************************************************************************
/*********************************************************************
函数名:独立按键检测函数(带参数返回)
全局变量:无
参数说明:无
返回说明:返回按键值
说明:延时消抖,返回值为0xff表示无按键按下或按键不正常
/**********************************************************************************/
uchar key_function(void)
{
uchar data keytemp = 0;//按键值局部变量
if ((set_key & 0x03) != 0x03) //如果有按键按下 0000 0011 03h
// 0000 0001 01h
{ // 0000 0010 02h
keytemp = set_key & 0x03; //取键值
delay_ms(50); //延时消抖
if ((set_key & 0x03) == keytemp)
{
return (keytemp); //返回按键值
}
else
{
return (0xff);//无正常按键
}
}
return (0xff); //无按键按下
}
/************************************************************************/
/*********************转换时间值并写入 ***************************/
void write_time(void)
{
Ttotal = time1 / 100;
Ttotal = time1 % 100 / 10;
Ttotal = time1 % 10;
Ttotal = 0x00;
Sector_Erase(EEPROM_ADD); //擦除扇区
String_write(EEPROM_ADD,4,Ttotal);//重新写入数据
String_Read(EEPROM_ADD,4); //重新设置后读出来备用,目的是更新Read_buf[]数组方便定时器0
} //中断后time = Read_buf * 100 + Read_buf * 10 + Read_buf;的取值
/*************************************************************************************/
/***************************** 转换时间值供显示 *************************************/
void abc_cba(unsigned int time)
{
ge = time / 100;
sf = time % 100 / 10;
bf = time % 10;
}
/**********************************************************************************/
/************************** 读出存在eeprom内的时间值 *********************/
void Read_time(void)
{
String_Read(EEPROM_ADD,4);//读出来备用
//EEPROM_ADD 要写读内部EEPROM的始起地扯
//4 共要读出4个数据
if(Read_buf != 0)//不为0表示eeprom内容未写过
{
time1 = 138;//给一个为138的初值
write_time();//写入eeprom
}
set_time = Read_buf * 100 + Read_buf * 10 + Read_buf;
if(up_dn)time1 = set_time;//如果为倒计送设置的值
else time1 = 0; //如果为正计送0
}
/******************************************************************************/
//*******************************主程序******************************************
void main()
{
uint keynum;//长按计数缓存区
bit key = 0 ;//sw_mode键长按标志位/正计、倒计
SP = 0x60; //堆栈指针
/******** 注意STC89系列没有此时钟频率分频功能故只能有 12M晶振******************/
//CLK_DIV = 0x00; //系统时钟
CLK_DIV = 0x01;//系统时钟/2
//CLK_DIV = 0x02; //系统时钟/4
//CLK_DIV = 0x03; //系统时钟/8
//CLK_DIV = 0x04; //系统时钟/16
//CLK_DIV = 0x06; //系统时钟/32
//CLK_DIV = 0x06; //系统时钟/64
//CLK_DIV = 0x07; //系统时钟/128
/*********************************************************************************/
set_key = 0xff;
switch (key_function())
{
case set_djm:
{
up_dn = 1;//正计时与倒计时标志位、为1时倒计。
set_count = 20;//P1.6对地倒计秒
break;
}
case set_djf:
{
up_dn = 1;//正计时与倒计时标志位、为1时倒计。
set_count = 1200; //P1.7对地倒计分
break;
}
case set_zjm:
{
up_dn = 0;//正计时与倒计时标志位、为1时倒计。
set_count = 20;//P1.6对地倒计秒
break;
}
/* case set_zjf:
{
break;
} */
default:
{
up_dn = 0;//正计时与倒计时标志位、为1时倒计。
set_count = 1200; //P1.7对地倒计分
break;
}
}
/***************************************************************************/
TMOD = 0x11; //设置定时器0/1为工作方式1(0001 0001)
//write_time();//写入eeprom
TH0 = (65536 - 50000) / 256;
TL0 = (65536 - 50000) % 256;
TH1 = (65536 - 2500) / 256;
TL1 = (65536 - 2500) % 256;
ET1 = 1;
TR1 = 1;
ET0 = 1;
EA = 1; //开定时器0中断、启动定时器0、开总中断
OUT1S = 1; //到时间后输出约1S低电平,上电后置1
OUTL = 1; //到时间后输出约低电平,上电后置1
Read_time(); //读出存在eeprom内的时间值
if(up_dn) time1 = set_time;
abc_cba(time1);//转换时间值供显示
/*********************长按为模式键、短按移位**************************************/
while(1)
{
if ((KEY & 0xc0) == 0x80) //如果有按键按下 1100 0000 C0h
// 1011 1111 80h
{
delay_ms(20); //延时消抖
while ((KEY & 0xc0) == 0x80) //长按为模式键、短按移位
{
keynum++;
delay_ms(10);//防止干扰
if (keynum > 200) //如果是长按sw_mode模式键则
{
TR0 = 0;//停止计时器0
DPP = 0;//关闭小数点闪烁标志位
key = 1;//置sw_mode键有长按标志位
g_shi = 1;//千位是否显示标志位置位
yiwei = 0;
xflash = 0; //每按一次清0一次让其永远达不到10s的退出值
time1 = Read_buf * 100 + Read_buf * 10 + Read_buf;//重调回之前值
if(up_dn) abc_cba(set_time);//如果为倒计时转换set_time时间值供显示
else abc_cba(time1); //如果为正计时转换time1时间值供显示
}
}
if (keynum > 200)
{
keynum = 0;
}
else if(keynum >= 10) //防止干扰
{
keynum = 0;
if(key)//如果sw_mode键有长按标志位
{
TR0 = 0;
DPP = 0; //关闭小数点闪烁标志位
xflash = 0; //每按一次清0一次让其永远达不到10s的退出值
yiwei++;
if(yiwei >= 3)
{
yiwei = 4;//让移位功能失效
key = 0;//关闪sw_mode键有长按标志位
g_shi = 0;//关闭千位是否显示标志位
write_time(); //转换时间值并写入
if(!up_dn)time1 = 0; //如果为正计时则保存完后恢复time1为 000
}
}
}
}
/**************** 长按为开始键、短按加数、停止计时************************************/
if ((KEY & 0xc0) == 0x40) //如果有按键按下 1100 0000 C0h
{ // 0111 1111 40h
delay_ms(20); //延时消抖
while ((KEY & 0xc0) == 0x40) //长按为开始键、短按加数、停止计时
{
keynum++;
delay_ms(10);//防止干扰
if (keynum > 200) //如果长按sw_strat开始键则
{
if((set_time !=0)||(up_dn == 0))//set_time=0未重置数时不能启动倒计时或为正计时模式时启动计时器
{
Read_time(); //启动前先更新set_time的值供定时器0中断程序参考
count = 0;//定时器0内的计数器清0保持每次时间一样
TR0 = 1;//开启计时器0
}
}
}
if (keynum > 200)
{
keynum = 0;
}
else if(keynum >= 10) //防止干扰
{
keynum = 0;
TR0 = 0; //关闪计时器0
DPP = 0; //关闭小数点闪烁标志位
xflash = 0; //每按一次清0一次让其永远达不到10s的退出值
OUTL = 1; //短按P3^7口开关键后才变高
switch(yiwei)
{
case 0:
{
ge++;
if(ge >= 10) //如果大于10清0
ge = 0;
break;
}
case 1:
{
sf++;
if(sf >= 10) //如果大于10清0
sf = 0;
break;
}
case 2:
{
bf++;
if(bf >= 10) //如果大于10清0
bf = 0;
break;
}
default:
{
break;
}
}
set_time = time1 = ge * 100 + sf * 10 + bf; //将调节后的值转换为time值
}
}
if(up_dn) abc_cba(set_time);//如果为倒计时转换set_time时间值供显示
else abc_cba(time1); //如果为正计时转换time1时间值供显示
}
}
/**************************************************************************/
/*****************************************************************************
函数功能:定时器中断
入口参数:
出口参数:
/****************************************************************************/
void timer0(void) interrupt 1
{
CY = 0;
TL0 +=(65536 - 50007) % 256;//中断响应时间同步修正/重装初值(低8位修正值)
TH0 = (65536 - 50000) / 256 +(unsigned char)CY;//高8位初值修正/重装初值(高8位修正值)
count++;
if (count == set_count) //50ms x 20 = 1秒钟
{ //50ms x 1200 = 1分钟
count = 0x00;
time1++;
set_time--;
if(!set_time) //如果已倒计为0则重读eeprom内的值
{
TR0 = 0;
flash1 = 0; //到时间后先将其清0保证1s输出的时间
DPP = 1; //这里置1经下面取反后则为0关闭小数点闪烁标志位
OUT1S = OUTL = 0; //输出低电平直到短按P3^7口开关键后才变高
} //到时间后输出约1S低电平
}
DPP = ~DPP;//烁标志位取反一次
xflash = 0;//让其永远达不到10s的退出值
}
/******************************************************************/
/******************************************************************/
void timer1(void) interrupt 3
{
static uchar led;
uchar flash;
bit flas;
TH1 = (65536 - 2500) / 256;
TL1 = (65536 - 2500) % 256;
flash++;
if(flash == 50)//2.5ms x 50 = 125ms
{
flash = 0;
flas = !flas; //跟据移位值来使某位闪焕
xflash++;
if(!OUT1S)//从OUT1S输出为低时才++
flash1++;
}
if(flash1 == 8)//125ms x 8 = 1s 后自动变为高电平
{
OUT1S = 1;//到时间后输出约1S低电平
}
if(xflash == 80) //125ms x 80 = 10s 后自动退出设置状态
{
xflash = 0;//清0
yiwei = 4;//让跟据移位值来使某位闪焕功能失效
if(up_dn)
set_time = Read_buf * 100 + Read_buf * 10 + Read_buf;//如果为倒计时重调回之前值
else
time1 = 0;//如果为倒计时则清0
DPP = 0;//关闭小数点闪烁标志位
g_shi = 0;//关闭千位是否显示标志位
}
switch(led)
{
case 0:
{
P1_7 = 0;
if(g_shi)
P2 = table; //不显示千位
else
P2 = table; //显示千位
P1_4 = 1;
led = 1;
break;
}
case 1:
{
if((flas)&&(yiwei == 0))//跟据移位值来使某位闪焕
P2 = table; //不显示
else
P2 = table; //显示个位
P1_4 = 0;
P1_5 = 1;
led = 2;
break;
}
case 2:
{
if((flas)&&(yiwei == 1))//跟据移位值来使某位闪焕
P2 = table; //不显示
else
P2 = table; //显示十分位
P1_5 = 0;
P1_6 = 1;
led = 3;
break;
}
case 3:
{
if((flas)&&(yiwei == 2))//跟据移位值来使某位闪焕
P2 = table; //不显示
else
P2 = table; //显示百分位
if(DPP)
DP = 0;//直接打开小数点
else
DP = 1;//直接关闭小数点
P1_6 = 0;
P1_7 = 1;
led = 0;
break;
}
default:break;
}
}
/******************************************** END********************************/
这个好。。。。。
页:
[1]