打印
[国产单片机]

求助:STC89C52RC做计时器

[复制链接]
1971|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
weixiaoxiaoji|  楼主 | 2011-11-14 17:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 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;
    }
}

相关帖子

沙发
weixiaoxiaoji|  楼主 | 2011-11-15 12:20 | 只看该作者
各位大侠,请指点一下,谢谢了!

使用特权

评论回复
板凳
谈的元| | 2011-11-15 21:46 | 只看该作者
万丈高楼从地起,一步步来吧

使用特权

评论回复
地板
weixiaoxiaoji|  楼主 | 2011-11-15 22:03 | 只看该作者
谢谢,我会努力学习

使用特权

评论回复
5
autopccopy| | 2011-11-16 11:57 | 只看该作者
《匠人手记》有个汽车里程表的例子可参考。。。

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
weixiaoxiaoji + 1 很给力!
6
weixiaoxiaoji|  楼主 | 2011-11-16 18:26 | 只看该作者
谢谢5楼的大侠

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

20

帖子

1

粉丝