用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 2018-03-10
升级记录:
增加上电自动选择设置正计时与倒计时的初步程序编写。 2018-3-11 23:08
P1.0 & P1.1 对地时为倒计秒
P1.0 对地时为倒计分
P1.1 对地时为正计秒
P1.0 & P1.1 不接时为正计分 2018-3-11 09:33- /*********************************************************************/
- #include
- #include
- #include
- #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 ********************************/
复制代码
|