本帖最后由 weixiaoxiaoji 于 2011-11-14 17:38 编辑
我想用STC89C52RC做一个计时器,用来统计通电时间的。比例,我们在测试一个产品的寿命,有可能中间停电了,那么这个时间就自动停止,然后来电了,自动开始计时。我想用其内部的eeprom,从网上找了一段程序,不知道哪有问题。初学,不太懂,请各位大侠帮忙,如果可以帮忙注释一下,更好了,谢谢!
/************************************************************************************************************************************/
#include <REG52.h>
#include <stdio.h>
#include <string.h>
#include <intrins.h>
/************************************************************************************************************************************/
#define Uchar unsigned char
#define Uint unsigned int
#define Ulong unsigned long
//定义Flash 操作等待时间及允许IAP/ISP/EEPROM 操作的常数
#define ENABLE_ISP 0x83 //系统工作时钟<12MHz 时,对IAP_CONTR 寄存器设置此值
/************************************************************************************************************************************/
sfr IAP_DATA = 0xE2;
sfr IAP_ADDRH = 0xE3;
sfr IAP_ADDRL = 0xE4;
sfr IAP_CMD = 0xE5;
sfr IAP_TRIG = 0xE6;
sfr IAP_CONTR = 0xE7;
/************************************************************************************************************************************/
//全局变量及共用体变量
/************************************************************************************************************************************/
Uchar buff[8];
Uchar buff1[8];// = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
union union_temp16
{
Uint un_temp16;
Uchar un_temp8[2];
} my_unTemp16; //定义共用体,给存储eeprom使用
/************************************************************************************************************************************/
//函数声明区
/************************************************************************************************************************************/
void Read_8byte(Uchar *buf, Uint add, Uchar bitt); //读多个字节,调用前需打开IAP 功能
void Program_8byte(Uchar *buf, Uint add, Uchar bitt); //写多个字节,调用前需打开IAP 功能
void Sector_Erase(Uint add); //擦除扇区
void IAP_Disable(); //关闭IAP 功能
void Delay(); //延时函数
void mcu_ini(void);//mcu初始化函数
unsigned char code dispcode[] = {0xc0, 0xF9, 0xA4, 0xB0,
0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x77, 0x7c,
0x39, 0x5e, 0x79, 0x71, 0xbf
};
unsigned char dispbitcode[] = {0xfe, 0xfd, 0xfb, 0xf7,
0xef, 0xdf, 0xbf, 0x7f
};
unsigned char dispbuf[8] = {0, 0, 16, 0, 0, 16, 0, 0};
unsigned char aa[8] = {0, 0, 16, 0, 0, 16, 0, 0};
unsigned char dispbitcnt;
unsigned char second;
unsigned char minite;
unsigned char hour;
unsigned int tcnt;
unsigned char mstcnt;
unsigned char i, j;
//从stc89.h中复制过来的
//sfr P1 = 0x90; //I/O端口0 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
//位描述 P1.7 P1.6 P1.5 P1.4 P1.3 P1.2 P1.1 P1.0
//初始值=1111,1111 1 1 1 1 1 1 1 1
sbit P17 = P1^7; //I/O口P1.7
sbit P16 = P1^6; //I/O口P1.6
sbit P15 = P1^5; //I/O口P1.5
sbit P14 = P1^4; //I/O口P1.4
sbit P13 = P1^3; //I/O口P1.3
sbit P12 = P1^2; //I/O口P1.2
sbit P11 = P1^1; //I/O口P1.1
sbit P10 = P1^0; //I/O口P1.0
//从stc89.h中复制过来的
/************************************************************************************************************************************/
//主函数区
/************************************************************************************************************************************/
void main (void)
{
TMOD = 0x02;
TH0 = 0x06;
TL0 = 0x06;
TR0 = 1;
ET0 = 1;
EA = 1;
Sector_Erase(0x4000); //擦除整个扇区
Program_8byte(aa, 0x4000, 8); //写入数据,初始值为00 00 00
Read_8byte(buff, 0x4000, 8); //读EEPROM的数据
dispbuf[0]=buff[0];
dispbuf[1]=buff[1];
dispbuf[2]=buff[2];
dispbuf[3]=buff[3];
dispbuf[4]=buff[4];
dispbuf[5]=buff[5];
dispbuf[6]=buff[6];
dispbuf[7]=buff[7];
//memcpy(dispbuf, buff, sizeof(dispbuf)); // dispbuf = buff;
while(1)
{
if(P14 == 0) //看一下秒钟加的按键是否按下了
{
for(i = 5; i > 0; i--)
for(j = 248; j > 0; j--); //延时去抖
if(P14 == 0) //再看下秒钟加的按键是否按下了,是则秒钟加1
{
second++;
if(second == 60)
{
second = 0;
}
dispbuf[0] = second % 10; //将秒钟的个位赋给显示
dispbuf[1] = second / 10; //将秒钟的十位赋给显示
while(P14 == 0); //如果按键不放开,就一直循环;松下了,就开始执行下一条
}
}
if(P15 == 0)
{
for(i = 5; i > 0; i--)
for(j = 248; j > 0; j--);
if(P15 == 0)
{
minite++;
if(minite == 60)
{
minite = 0;
}
dispbuf[3] = minite % 10;
dispbuf[4] = minite / 10;
while(P15 == 0);
}
}
if(P16 == 0)
{
for(i = 5; i > 0; i--)
for(j = 248; j > 0; j--);
if(P16 == 0)
{
hour++;
if(hour == 24)
{
hour = 0;
}
dispbuf[6] = hour % 10;
dispbuf[7] = hour / 10;
while(P16 == 0);
}
}
if(P17 == 0) //按下后清零
{
for(i = 5; i > 0; i--)
for(j = 248; j > 0; j--);
if(P17 == 0)
{
P0=0;
Sector_Erase(0x4000); //擦除整个扇区
P0=0xfe;
Program_8byte(aa, 0x4000, 8); //清零
}
}
//Sector_Erase(0x4000); //擦除整个扇区
//memcpy(dispbuf, buff, sizeof(dispbuf)); //buff1 = dispbuf; //将正在显示的值赋给要写入的数组,以后要将这个判断一下是否到了1个小时再写入。不到一个小时自动放弃不计。后面考虑轮片写入的时可以试一下实时写入
//Program_8byte(buff1, 0x4000, 8); //写入数据
}
}
/********************************************************************************************************************************/
//读一字节,调用前需打开IAP 功能,入口:DPTR = 字节地址,返回:A = 读出字节
/********************************************************************************************************************************/
Uchar Byte_Read(Uint add)
{
IAP_DATA = 0x00;
IAP_CONTR = ENABLE_ISP; //打开IAP 功能, 设置Flash 操作等待时间
IAP_CMD = 0x01; //IAP/ISP/EEPROM 字节读命令
my_unTemp16.un_temp16 = add;
IAP_ADDRH = my_unTemp16.un_temp8[0]; //设置目标单元地址的高8 位地址
IAP_ADDRL = my_unTemp16.un_temp8[1]; //设置目标单元地址的低8 位地址
//EA = 0;
IAP_TRIG = 0x46; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xB9; //送完A5h 后,ISP/IAP 命令立即被触发起动
_nop_();
//EA = 1;
return (IAP_DATA);
}
/********************************************************************************************************************************/
//读多个字节,调用前需打开IAP 功能,入口:DPTR = 字节地址,返回:A = 读出字节
/********************************************************************************************************************************/
void Read_8byte(Uchar *buf, Uint add, Uchar bitt)
{
Uchar i;
for (i = 0; i < bitt; i++)
{
buf = Byte_Read(add + i);
}
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}
/********************************************************************************************************************************/
//字节编程,调用前需打开IAP 功能,入口:DPTR = 字节地址, A= 须编程字节的数据
/********************************************************************************************************************************/
void Byte_Program(Uint add, Uchar ch)
{
IAP_CONTR = ENABLE_ISP; //打开 IAP 功能, 设置Flash 操作等待时间
IAP_CMD = 0x02; //IAP/ISP/EEPROM 字节编程命令
my_unTemp16.un_temp16 = add;
IAP_ADDRH = my_unTemp16.un_temp8[0]; //设置目标单元地址的高8 位地址
IAP_ADDRL = my_unTemp16.un_temp8[1]; //设置目标单元地址的低8 位地址
IAP_DATA = ch; //要编程的数据先送进IAP_DATA 寄存器
//EA = 0;
IAP_TRIG = 0x46; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xB9; //送完A5h 后,ISP/IAP 命令立即被触发起动
_nop_();
//EA = 1;
}
/********************************************************************************************************************************/
//多字节写入函数
/********************************************************************************************************************************/
void Program_8byte(Uchar *buf, Uint add, Uchar bitt)
{
Uchar i;
for (i = 0; i < bitt; i++)
{
Byte_Program(add + i, buf);
}
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}
/***************************************************************************************************************************************/
//扇区擦除, 入口:DPTR = 扇区地址
/***************************************************************************************************************************************/
void Sector_Erase(Uint add)
{
IAP_CONTR = ENABLE_ISP; //打开IAP 功能, 设置Flash 操作等待时间
IAP_CMD = 0x03; //IAP/ISP/EEPROM 扇区擦除命令
my_unTemp16.un_temp16 = add;
IAP_ADDRH = my_unTemp16.un_temp8[0]; //设置目标单元地址的高8 位地址
IAP_ADDRL = my_unTemp16.un_temp8[1]; //设置目标单元地址的低8 位地址
//EA = 0;
IAP_TRIG = 0x46; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xB9; //送完A5h 后,ISP/IAP 命令立即被触发起动
_nop_();
//EA = 1;
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}
/***************************************************************************************************************************************/
//关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
/***************************************************************************************************************************************/
void IAP_Disable()
{
IAP_CONTR = 0; //关闭IAP 功能
IAP_CMD = 0; //清命令寄存器,使命令寄存器无命令,此句可不用
IAP_TRIG = 0; //清命令触发寄存器,使命令触发寄存器无触发,此句可不用
IAP_ADDRH = 0;
IAP_ADDRL = 0;
}
/***************************************************************************************************************************************/
//延时函数
/***************************************************************************************************************************************/
void Delay()
{
Uchar i;
Uint d = 100;
while (d--)
{
i = 255;
while (i--);
}
}
void t0(void) interrupt 1 using 0
{
mstcnt++;
if(mstcnt == 8)
{
mstcnt = 0;
P2 = 0xff; //关闭所有显示
P0 = dispcode[dispbuf[dispbitcnt]];
P2 = dispbitcode[dispbitcnt];
dispbitcnt++;
if(dispbitcnt == 8)
{
dispbitcnt = 0;
}
}
tcnt++;
if(tcnt == 4000)
{
tcnt = 0;
second++;
if(second == 60)
{
second = 0;
minite++;
if(minite == 60)
{
minite = 0;
hour++;
if(hour == 24)
{
hour = 0;
}
}
}
dispbuf[0] = second % 10;
dispbuf[1] = second / 10;
dispbuf[3] = minite % 10;
dispbuf[4] = minite / 10;
dispbuf[6] = hour % 10;
dispbuf[7] = hour / 10;
}
} |