一乐电子

一乐电子百科

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

快捷登录

手机号码,快捷登录

搜索
查看: 7983|回复: 19
收起左侧

[51单片机] 用STC系列单片机制作四位可预置计时器

  [复制链接]
发表于 2012-5-6 11:28 | 显示全部楼层 |阅读模式
本帖最后由 LBQ691477940 于 2012-5-6 11:48 编辑

2.jpg 3.jpg 4.jpg 1.jpg
/***************************************************************************************
      用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后自动重载预设值。
程序设计:LBQ691477940  2012-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_key  P1  //定义键盘口
#define KEY  P3   //定义键盘口
#define set_djm  0x00 //P1.0 & P1.1 对地时为倒计秒
#define set_zjm  0x01 //P1.0        对地时为倒计分
#define set_djf  0x02 //P1.1    对地时为正计秒
//#define set_zjf  0x03 //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; //长按为开始键、短按加数
bit  DPP = 0, g_shi = 0,up_dn; //闪烁标志位、千位是否显示标志位、正计时与倒计时标志位为1时倒计。
static uchar yiwei = 4;   //用于设置时间值时移位
static uint count = 0;    //定时器0内的计数器
uint  set_count,set_time,time1 = 0; //倒计数次数、设置的时间值(倒计时计数器)、正计时计数器
uchar  shi,ge,sf,bf,xflash,flash1;  //千位、百位、十位、个位、10s后自动退出设置、到时间后输出1s
uchar  Ttotal[4];  //前面三个字节为设置好的时间,最后一个字节用来判断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   1  2 3  4   5    6 7  8   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[0] = time1 / 100;
Ttotal[1] = time1 % 100 / 10;
Ttotal[2] = time1 % 10;
Ttotal[3] = 0x00;
Sector_Erase(EEPROM_ADD);   //擦除扇区
String_write(EEPROM_ADD,4,Ttotal);  //重新写入数据
String_Read(EEPROM_ADD,4); //重新设置后读出来备用,目的是更新Read_buf[]数组方便定时器0
}       //中断后time = Read_buf[0] * 100 + Read_buf[1] * 10 + Read_buf[2];的取值
/*************************************************************************************/
/***************************** 转换时间值供显示 *************************************/
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[3] != 0)//不为0表示eeprom内容未写过
{
  time1 = 138;//给一个为138的初值
  write_time();//写入eeprom
}
set_time = Read_buf[0] * 100 + Read_buf[1] * 10 + Read_buf[2];
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[0] * 100 + Read_buf[1] * 10 + Read_buf[2];//重调回之前值
     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[0] * 100 + Read_buf[1] * 10 + Read_buf[2];//如果为倒计时重调回之前值
  else
  time1 = 0;  //如果为倒计时则清0
  DPP = 0;  //关闭小数点闪烁标志位
  g_shi = 0;  //关闭千位是否显示标志位
}
switch(led)
{
  case 0:
  {
   P1_7 = 0;
   if(g_shi)
   P2 = table[10]; //不显示千位
   else
   P2 = table[11]; //显示千位
   P1_4 = 1;
   led = 1;
   break;
  }
  case 1:
  {
   if((flas)&&(yiwei == 0))//跟据移位值来使某位闪焕
   P2 = table[11]; //不显示
   else
   P2 = table[ge]; //显示个位
   P1_4 = 0;
   P1_5 = 1;
   led = 2;
   break;
  }
  case 2:
  {
   if((flas)&&(yiwei == 1))//跟据移位值来使某位闪焕
   P2 = table[11]; //不显示
   else
   P2 = table[sf]; //显示十分位
   P1_5 = 0;
   P1_6 = 1;
   led = 3;
   break;
  }
  case 3:
  {
   if((flas)&&(yiwei == 2))//跟据移位值来使某位闪焕
   P2 = table[11]; //不显示
   else
   P2 = table[bf]; //显示百分位
   if(DPP)
    DP = 0;  //直接打开小数点
   else
    DP = 1;  //直接关闭小数点
   P1_6 = 0;
   P1_7 = 1;
   led = 0;
   break;
  }
  default:break;
}
}
/******************************************** END  ********************************/
STC12C5A60S2四位可调倒计时.pdf (31.64 KB, 下载次数: 1762) STC12C5A60S2四位可调倒计时程序.rar (2.17 KB, 下载次数: 1670)

评分

参与人数 2一乐金币 +40 收起 理由
非凡电子 + 20 楼主的分享精神值得敬佩!
fujiachun + 20 很给力!

查看全部评分

发表于 2012-5-6 12:09 | 显示全部楼层
要是有套件供应就好了,很想要一个。
发表于 2012-5-6 14:50 | 显示全部楼层
这个很好,希望有套件
发表于 2012-5-6 16:36 | 显示全部楼层
标记 学习
发表于 2012-5-6 16:50 | 显示全部楼层
收藏了。
发表于 2012-5-6 17:34 | 显示全部楼层
这玩意,可以做定时炸弹了
发表于 2012-5-6 19:36 | 显示全部楼层
要是有套件供应就好了,很想要一个。
发表于 2012-5-6 21:56 | 显示全部楼层
lz无私奉献,多谢了
发表于 2012-5-28 16:16 | 显示全部楼层
无私奉献,谢了
发表于 2013-1-11 17:09 | 显示全部楼层
谢谢分享源程序。

本版积分规则

QQ|一淘宝店|手机版|商店|电子DIY套件|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2024-4-27 10:25 , Processed in 0.068550 second(s), 46 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表