找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 600|回复: 2
收起左侧

使用STC8H1K08内部EEPROM保存数值,求大佬讲出问题所在

[复制链接]
ID:622606 发表于 2025-2-20 16:20 | 显示全部楼层 |阅读模式
使用STC8H1K08单片机做一个电机定时控制程序,想着使用内部EEPROM保存电机工作时间和停止时间,结果按键设置好数值之后断电重启显示又变为000,保存不到值。一直找不错原因,发帖寻求帮助,希望得到解决,谢谢!
下面是我写的完整程序,麻烦大家指出我调用不了EEPROM的原因:
#include<STC8H.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
//#include "reg51.h"
#include "intrins.h"
/*sfr     IAP_DATA    =   0xC2;
sfr     IAP_ADDRH   =   0xC3;
sfr     IAP_ADDRL   =   0xC4;
sfr     IAP_CMD     =   0xC5;
sfr     IAP_TRIG    =   0xC6;
sfr     IAP_CONTR   =   0xC7;
sfr     IAP_TPS     =   0xF5;*/
#define uchar unsigned char
#define uint unsigned int
#define Offset 0x2000
sbit L1=P1^1;//定义千位
sbit L2=P1^2;// 百位
sbit L3=P1^3;// 十位

sbit KEY_CH=P1^5; //模式设置
sbit KEY_ADD=P1^6;  //加
sbit KEY_DEC=P1^7;  //减
sbit INB=P5^4;
sbit INA=P1^4;
//定义变量
uchar code smgduan[13]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff,0x89,0x92};//共阳极,显示段码值0~9,空,H,S;
bit ch;//定义上下限设置
uchar d1,d2,d3,mode;//显示数据各位暂存变量
uint day ,out;//关停天数,启动时间
unsigned long int time,second,minute,hour;
void init_IO()
{
                P1M0 = 0x1f;                                //设置P1.1为ADC口
    P1M1 = 0x00;
    P3M0 = 0x00;                                //设置P3.0~P3.7为开漏模式
    P3M1 = 0x00;       
    P5M0 = 0x10;                                //设置P3.0~P3.7为开漏模式
    P5M1 = 0x00;       
}

/*------------------------------------------------
mS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
void DelayMs(uchar n)//12M
{     
        uchar i, j;
         while (n--)
         {
                 for(i=0;i<10;i++);
                 for(j=0;j<105;j++);
                 
         }
}

/*内部EEPROM*/
//单片机内部EEPROM不使能
void IapIdle()
{
    IAP_CONTR = 0;                              //关闭IAP功能
    IAP_CMD = 0;                                //清除命令寄存器
    IAP_TRIG = 0;                               //清除触发寄存器
    IAP_ADDRH         = 0x80;                           //将地址设置到非IAP区域
    IAP_ADDRL = 0;
//          IAP_DATA=0;                              //清除数据
}

//从单片机内部EEPROM读一个字节,从0x0000地址开始
uchar EEPROM_Read(uint addr)
{
    uchar dat;
    IAP_CONTR = 0x80;                           //使能IAP,SYSCLK<24MHz  0x81  SYSCLK<=24
    IAP_TPS = 12;                               //设置等待参数12MHz
    IAP_CMD = 1;                                //设置IAP读命令
          IAP_ADDRH = addr >> 8;                      //设置IAP高地址
    IAP_ADDRL = addr & 0xff;                           //设置IAP低地址
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
    _nop_();
    dat = IAP_DATA;                             //读IAP数据
    IapIdle();                                  //关闭IAP功能

    return dat;
}

//往单片机内部EEPROM写一个字节
void EEPROM_Write(uint addr, uchar dat)
{
    IAP_CONTR = 0x80;                           //使能IAP
    IAP_TPS = 12;                               //设置等待参数12MHz
    IAP_CMD = 2;                                //设置IAP写命令
          IAP_ADDRH = addr >> 8;                     //设置IAP高地址
    IAP_ADDRL = addr & 0xff;                          //设置IAP低地址
    IAP_DATA = dat;                             //写IAP数据
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
    _nop_();

    IapIdle();                                  //关闭IAP功能
}
//擦除单片机内部EEPROM的一个扇区
//写8个扇区中随便一个的地址,便擦除该扇区,写入前要先擦除
void EEPROM_Erase(uint addr)
{
    IAP_CONTR = 0x80;                           //使能IAP
    IAP_TPS = 12;                               //设置等待参数12MHz
    IAP_CMD = 3;                                //设置IAP擦除命令
    IAP_ADDRH = addr >> 8;                      //设置IAP高地址
    IAP_ADDRL = addr & 0xff;                          //设置IAP低地址
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
     _nop_();   
    IapIdle();                                  //关闭IAP功能
}

/*------------------------------------------------
* 函数名         : DigDisplay()
* 函数功能                   : 数码管显示函数
* 输入           : 无
* 输出                  : 无
------------------------------------------------*/
void Display()
{
                L1=1;
           P3=smgduan[d1];
          DelayMs(1);
          L1=0;

                L2=1;
           P3=smgduan[d2];
          DelayMs(1);       
                L2=0;

          L3=1;
           P3=smgduan[d3];
          DelayMs(1);       
                L3=0;
       
}
/*------------------------------------------------
                    按键扫描程序
------------------------------------------------*/
void keyscan()
{
        if(!KEY_CH)
                {
                                DelayMs(100);
                if(!KEY_CH)       
                        ch=!ch;
                while(!KEY_CH);       
                }
               
        if(ch==1)
        {
                d1 =11;  //H,停限定
                d2= day/10;
                d3= day%10;
                Display();
               
                if(!KEY_ADD)
                {
                        DelayMs(20);
                        if(!KEY_ADD)
                        {
                                day+=5;
                                if(day>=100)
                                        day=99;  //最大加到100
                        }
                                while(!KEY_ADD);
                        }
                                if(!KEY_DEC)
                {
                        DelayMs(50);
                        if(!KEY_DEC)
                        {
                                if(day<=0)
        {day=0;}
                                else
                                day-=1;
                               
                        }
                                while(!KEY_DEC);
                        }       
                }
       
                if(ch==0)
        {
                d1 =12;  //S ,启限定
                d2= out/10;
                d3 =out%10;
        Display();       
                if(!KEY_ADD)
                {
                        DelayMs(20);
                        if(!KEY_ADD)
                        {
                                out+=5;
                                if(out>=99)  //上下限3度区间
                                        out=99;
                        }
                                while(!KEY_ADD);
                        }
                                if(!KEY_DEC)
                {
                        DelayMs(50);
                        if(!KEY_DEC)
                        {
                                        if(out<=0)
                                        {out=0;}
                                        else
                                out-=1;

                        }
                                while(!KEY_DEC);
                        }       
                }
}
/*------------------------------------------------
                    定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
AUXR &= 0x7f;                //定时器时钟12T模式
TMOD |= 0xf0;          //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响                     
TH0=0xb0;              //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出
TL0=0x3c;        //50ms
EA=1;            //总中断打开
ET0=1;           //定时器中断打开
TF0=0;          //清除TF0标志
TR0=1;           //定时器开关打开

}
/*------------------------------------------------
                 定时器中断子程序 12MHZ 12T
------------------------------------------------*/
void Timer0_isr(void) interrupt 1 using 1
{
  int n;
TH0=0xb0;              //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出
TL0=0x3c;     //50ms
        if(mode==0 && out!=0)
        {
                n++;
        if(n==49)//一秒后
        {
                n=0;
                second++;
        }
        if(second==2)//等2秒
        {
                INA=1;//启动水泵               
        }
        if(second==(out+2)) //out+2秒后
          {
                INA=0;//关闭
          }
         if(second==2+out+3600*day)        //2+out+day后time清零
                {
                second=0;
                }
        }
        else if(mode==1)
        {
                n=0;
                second=0;
                INA=0;
        }
}


/*------------------------------------------------
                    主函数
------------------------------------------------*/
void main (void)
{  
                int c;
  init_IO();
                mode=0;
                INA=0;
           day=EEPROM_Read(0x2000);  //天数
          out=EEPROM_Read(0x2001);
        Init_Timer0();
    while (1)
    {
                while ( mode==0)         //不按按键时
    {
//                Init_Timer0();
         d1=day/100; d2=(day%100)/10; d3=(day%100)%10;
                Display();
                if(!KEY_CH ||!KEY_ADD || !KEY_DEC)
                {
                        mode=1;
                }
   }
          while ( mode==1)         //按按键时
    {                       
                keyscan();       
                          EEPROM_Erase(0x2000); //存储前必须先擦除
                     EEPROM_Write(0x2000, day); //
                    EEPROM_Write(0x2001, out);
                        if(KEY_CH && KEY_ADD && KEY_DEC)
                {
                        c++;
                        DelayMs(10);
                        if(c==9000)//停留9秒
                {
                        c=0;                       
                        mode=0;
                }               
                }
          }
          }
}

回复

使用道具 举报

ID:1133081 发表于 2025-2-20 21:41 | 显示全部楼层
STC8H1K08单片机的EEPROM只有4K,8个扇区,每个扇区512字节。各扇区首地址0x0000、0x0200、0x0400......0x0e00,你读写0x2000的地址根本不存在。

评分

参与人数 1黑币 +10 收起 理由
wpppmlah + 10 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:68189 发表于 2025-2-21 08:16 | 显示全部楼层
EEPROM 地址从0x0000 开始计算,大小由ISP软件下载时决定,,,,另外,把写EEPROM的语句,不要放在这个WHILE循环中,,,,,,不然你按下键不放,就会一直重写,不科学啊
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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