打印

大家帮忙看看,我这个程序是哪里的问题

[复制链接]
1742|20
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
nwjjdwx|  楼主 | 2020-1-3 17:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
AN, ixia, AI, ge, TE
本帖最后由 nwjjdwx 于 2020-1-3 21:25 编辑

各位朋友大家好,我在这里请教一个问题,我用STC15W404AS做了一个8分钟倒计时的定时器的实验,用了片内的EEPROM,模拟断电存储当前数据,并且提前将“从零开始学单片机”这本书提供的EEPROM驱动加到了KEIL当中,程序写好后编译正常通过,可是断电时的数据怎么就存不到EEPROM中去呢?不好意思我水平太低了,希望大家帮我看看问题出在那儿了。下面上图和程序:C:\Documents and Settings\Administrator\桌面


#include"STC15.H"
#include "STC_EEPROM.h"           //随书附赠的EEPROM驱动软件包
#define uint unsigned int
#define uchar unsigned char


sbit ge=P1^0;                  //声明秒个位驱动(19脚)
sbit shi=P1^1;                 //声明十秒位驱动(20脚)
sbit bai=P1^2;                 //分钟数驱动
sbit dian=P1^3;                 //小数点
                       

sbit key5=P1^4;                //模拟断电按钮(按下引起比较器中断)
sbit out1=P5^4;                //继电器驱动


uchar code table[]={ 0x48,0x5f,0x38,0x19,    //定义字段编码表
           0x0f,0x89,0x88,0x5b,0x08,0x09};

uchar gexian,shixian,num,num2,num3,baixian;      /ixian=秒十位数,gexian=秒个位数,baixian=分钟数,num=分钟数num3=秒点,
                                                 //num2=毫秒计数变量(num=20为1秒),

int num1;                            //num1=分钟数

///////////////
/*延时子程序 */
/////////////

void delayms(uint xms)             //延时1ms子程序
    {
     uint i,j;
       for(i=xms;i>0;i--)
            for(j=400;j>0;j--);
     }



////////////
/*初始化*/
///////////

void init()
     {
   
   
P1M1=0x10;              //设置P1.0,P1.1,P1.2为推挽
P1M0=0x07;              //设置P1.0,P1.1,P1.2为推挽
   P5M1=0x00;              //设置P5.4为推挽,
P5M0=0x10;              //设置P5.4为推挽.

                                                     
num=byte_read(0x0000);  //读出**的分钟数
num1=byte_read(0x0001);  //读出**的秒数

if(num==0)
  {
    if(num1==0)
   {
num=8;
}
}
out1=1;                 //继电器吸合
                                          
                  
   dian=1;                //暂时关闭小数点
   TMOD=0x01;             //设置定时器0为工作方式1(M1M0为01)
      
TH0=(65536-45872)/256;
   TL0=(65536-45872)%256;
   EA=1;                        //开总中断
   ET0=1;                      //开定时器0中断
TR0=1;
   CMPCR1=0x90;            //启动比较器,下降沿触发中断,正极P5.5为输入,负极为内部1.27作比较
CMPCR2=0x3f;            //0.1us延时后正常输出,63个时钟后动作,
                     
}

////////////////
/*计时判断程序*/
////////////////
void panduan()
    {
   

   if(num==0)
        {
   if(num1==0)
{
              TR0=0;             //关定时器
              out1=0;            //关输出(继电器释放)

   }
    }
   
if(num1<0)
      {   
  if(num>=1)
    {
  num--;
num1=59;
}
   
}

}

  

     ///////////////////////
     /*--------------------
显示子程序函数
      --------------------*/
     ///////////////////////
  
   void display(uchar gexian,uchar shixian,uchar baixian)
      {
shixian=num1/10;               //将num1中的数求模,然后赋值给秒十位显示
gexian=num1%10;                //将num1中的数求余,然后赋值给秒个位显示
baixian=num;                   //将num中的数赋值给分钟数显示
P3=table[gexian];
dian=1;
        ge=1;
        delayms(5);
ge=0;
P3=table[shixian];
dian=1;
shi=1;
delayms(5);
shi=0;
        P3=table[baixian];
dian=num3;
bai=1;
delayms(5);
bai=0;
       }
        





       //////////////////
      /*---------------
         主程序函数
       ---------------*/
      //////////////////


void main()
           {

       init();
         while(1)
            {              
display(gexian,shixian,baixian);               //显示程序
              
panduan();                                   //判断程序
              
             }

}

     
////////////////////////
/*定时器0中断服务程序*/
///////////////////////
  
        void T0_tame() interrupt 1
             {
                  TH0=(65536-45872)/256;
                  TL0=(65536-45872)%256;
                  
num2++;
                  

                 
if(num2==20)              //num2==20为1秒
                     {
                       
                       num2=0;
                       num1--;               //秒数减1(倒计时)
                                 
                        
                       }

  if(num2<7)         
    {
      num3=1;        //小数点灭0.3秒
     }
                           
   if(num2>8)
{
  num3=0;        //小数点亮0.7秒   

                            }                 
                         }


   ///////////////////////
   ////比较器中断服务程序//
   ///////////////////////

void cmp()interrupt 21
{
  CMPCR1=0x90;              //清比较器中断标志
   TR0=0;
   EA=0;                                   //关中断
   
     
  SectorErase(0x0000);                   //擦除扇区,Sector=扇区,Erase=擦除,擦除从0x0000开始的一个扇区
     
     byte_write(0x0000,num);                 //将小时数存入0x0000单元中
     byte_write(0x0001,num1);                //将分钟数存入0x0001单元中

      num3=0;                                 //小数点保留显示

  }

使用特权

评论回复

相关帖子

沙发
nwjjdwx|  楼主 | 2020-1-3 17:26 | 只看该作者
图没传成功

使用特权

评论回复
板凳
nwjjdwx|  楼主 | 2020-1-3 17:28 | 只看该作者
本帖最后由 nwjjdwx 于 2020-1-3 17:34 编辑

又传了一次,
我是在开发板上实验的,程序中的数码管编码和这个图并不匹配,只是说明一下电路就是这个。

图纸.png (68.94 KB )

图纸.png

使用特权

评论回复
地板
nwjjdwx|  楼主 | 2020-1-3 19:46 | 只看该作者
下面是买书后附赠的EEPROM驱动软件包:

#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define RdCommand 0x01        //定义ISP的操作命令
#define PrgCommand 0x02
#define EraseCommand 0x03       
#define Error 1
#define Ok 0
#define WaitTime 0x01 //定义CPU的等待时间
sfr ISP_DATA=0xe2;  //寄存器申明
sfr ISP_ADDRH=0xe3;
sfr ISP_ADDRL=0xe4;
sfr ISP_CMD=0xe5;
sfr ISP_TRIG=0xe6;
sfr ISP_CONTR=0xe7;

/* ================ 打开 ISP,IAP 功能 ================= */
void ISP_IAP_enable(void)
{
        EA        =        0;                                                        /* 关中断                 */
        ISP_CONTR =        ISP_CONTR & 0x18;       /* 0001,1000        */
        ISP_CONTR =        ISP_CONTR | WaitTime;        /* 写入硬件延时        */
        ISP_CONTR =        ISP_CONTR | 0x80;       /* ISPEN=1                */
}
/* =============== 关闭 ISP,IAP 功能 ================== */
void ISP_IAP_disable(void)
{
        ISP_CONTR        =        ISP_CONTR & 0x7f;        /* ISPEN = 0 */
        ISP_TRIG        =        0x00;
        EA                        =   1;                        /* 开中断 */
}
/* ================ 公用的触发代码 ==================== */
void ISPgoon(void)
{
        ISP_IAP_enable();                        /* 打开 ISP,IAP 功能        */
        ISP_TRIG        =        0x46;                /* 触发ISP_IAP命令字节1        */
        ISP_TRIG        =        0xb9;                /* 触发ISP_IAP命令字节2        */
        _nop_();
}
/* ==================== 字节读 ======================== */
uchar byte_read(uint byte_addr)
{
        ISP_ADDRH = (uchar)(byte_addr >> 8);/* 地址赋值        */
        ISP_ADDRL = (uchar)(byte_addr & 0x00ff);
        ISP_CMD   = ISP_CMD        & 0xf8;                        /* 清除低3位         */
        ISP_CMD   = ISP_CMD        | RdCommand;        /* 写入读命令        */
        ISPgoon();                                                        /* 触发执行                */
        ISP_IAP_disable();                                /* 关闭ISP,IAP功能        */
        return (ISP_DATA);                                /* 返回读到的数据        */
}
/* ================== 扇区擦除 ======================== */
void SectorErase(uint sector_addr)
{
        uint iSectorAddr;
        iSectorAddr = (sector_addr & 0xfe00); /* 取扇区地址 */
        ISP_ADDRH = (uchar)(iSectorAddr >> 8);
        ISP_ADDRL = 0x00;
        ISP_CMD        = ISP_CMD & 0xf8;                        /* 清空低3位         */
        ISP_CMD        = ISP_CMD | EraseCommand;        /* 擦除命令3         */
        ISPgoon();                                                        /* 触发执行                */
        ISP_IAP_disable();                                /* 关闭ISP,IAP功能        */
}
/* ==================== 字节写 ======================== */
void byte_write(uint byte_addr, uchar original_data)
{
        ISP_ADDRH =        (uchar)(byte_addr >> 8);         /* 取地址         */
        ISP_ADDRL =        (uchar)(byte_addr & 0x00ff);
        ISP_CMD         = ISP_CMD & 0xf8;                                /* 清低3位        */
        ISP_CMD  = ISP_CMD | PrgCommand;                /* 写命令2        */
        ISP_DATA = original_data;                        /* 写入数据准备        */
        ISPgoon();                                                        /* 触发执行                */
        ISP_IAP_disable();                                        /* 关闭IAP功能        */
}


使用特权

评论回复
5
nwjjdwx|  楼主 | 2020-1-3 21:17 | 只看该作者
这个倒计时定时器的实验,在倒计时计到一半时,我按下模拟断电按钮,数码管倒计时停止了,那个闪动的秒点也停了,和这些有关的语句是写在比较器中断里的,证明比较器中断已经产生,中断程序也已经响应了,这时关机再开机程序应该从EEPROM中读出模拟断电时存进去的数据,继续倒计下去,直到计时结束才对,可是问题却是再开机从8分钟开始倒计的,这个8分钟的来源是:开机程序先读EEPROM,如果读出的是0,证明上次运行没有产生过模拟断电中断,程序就自动赋值8分钟开始倒计时,直到结束。现在是比较器中断产生了,中断程序也响应了,数据为什么存不到EEPROM中去呢?求高手看看问题是出在哪里?

使用特权

评论回复
6
mycomputer0000| | 2020-1-4 09:44 | 只看该作者
nwjjdwx 发表于 2020-1-3 19:46
下面是买书后附赠的EEPROM驱动软件包:

#include

扇区擦除需要时间的

使用特权

评论回复
7
nwjjdwx|  楼主 | 2020-1-4 10:34 | 只看该作者
本帖最后由 nwjjdwx 于 2020-1-4 21:15 编辑

昨天查了一下用户手册,发现了一点问题,发现EEPROM驱动包这里寄存器申明这里和我用的15系列不对,驱动包申明特殊功能寄存器为:
sfr ISP_DATA=0xe2;  //寄存器申明
sfr ISP_ADDRH=0xe3;
sfr ISP_ADDRL=0xe4;
sfr ISP_CMD=0xe5;
sfr ISP_TRIG=0xe6;
sfr ISP_CONTR=0xe7;
而手册上是:
sfr ISP_DATA=0xc2;  //寄存器申明
sfr ISP_ADDRH=0xc3;
sfr ISP_ADDRL=0xc4;
sfr ISP_CMD=0xc5;
sfr ISP_TRIG=0xc6;
sfr ISP_CONTR=0xc7;
仔细看书,原来书作者是按照STC89C系列芯片写的,而我用的却是STC15W系列的芯片,EEPROM的特殊功能寄存器的地址是不一样的,就随手改了过来,再编译后再试,还是存不到EEPROM中去,这个哪里还有错的?我一时看不出来了,望高手不吝赐教。

使用特权

评论回复
8
nwjjdwx|  楼主 | 2020-1-4 10:41 | 只看该作者
mycomputer0000 发表于 2020-1-4 09:44
扇区擦除需要时间的

谢谢您的回复,您是说那个EEPROM的驱动包里的擦除程序里没有擦除延时造成的?对他的那个程序也看不太懂,我再仔细看看,

使用特权

评论回复
9
nwjjdwx|  楼主 | 2020-1-4 12:34 | 只看该作者
本帖最后由 nwjjdwx 于 2020-1-4 12:37 编辑

又找到了一点原因,这个触发程序也和STC15W的也不对,

/* ================ 公用的触发代码 ==================== */
void ISPgoon(void)
{
        ISP_IAP_enable();                        /* 打开 ISP,IAP 功能        */
        ISP_TRIG        =        0x46;                /* 触发ISP_IAP命令字节1        */
        ISP_TRIG        =        0xb9;                /* 触发ISP_IAP命令字节2        */
        _nop_();
}

这句:ISP_TRIG        =        0x46;这个应该是:ISP_TRIG        =        0x5a;

这句:ISP_TRIG        =        0xb9; 这个应该是:ISP_TRIG        =        0xa5;

改过来试了一下还是不行,读出来的数很大,超出了显示范围,以前不是这样的,是从8分钟开始倒计时的,看来之前就没有触发成功, 现在的显示应该是读取的EEPROM,也就是只有擦除和写入这里有问题了,关于擦除延时问题:

ISP_CONTR =        ISP_CONTR | WaitTime;

这句没看懂,我直接改成:ISP_CONTR =0x83;  了,试了一下还是不行,
不知问题在哪里?

使用特权

评论回复
10
nwjjdwx|  楼主 | 2020-1-4 21:19 | 只看该作者
自己顶一下,防止沉了,各位高手请您指点迷津。

使用特权

评论回复
11
nwjjdwx|  楼主 | 2020-1-4 23:41 | 只看该作者
进行了艰苦卓绝的摸索,还是不行,下面是修改过的EEPROM驱动文件,我的水平实在是再看不出什么毛病了,希望高手指点,目前的情况是:按下模拟停电按钮,倒计时的数码管会停止,跟秒一块显示的那个秒点也跟着停止,关机再开机读出的数很大,证明此数是从EEPROM中出来的,也证明EEPROM驱动文件(STC_EEPROM.h)中的“读”函数正常,读出的数很大应该是“擦除函数”没有把0000扇区给擦除掉,反复查看(STC_EEPROM.h)中的擦除文件,看不出毛病,C51编程是自学的,没有水平,希望高手出手相救,指点是哪里的问题。在这先谢过,

(STC_EEPROM.h)文件:

#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define RdCommand 0x01                  //定义ISP的操作命令(读命令)
#define PrgCommand 0x02            //(写命令)
#define EraseCommand 0x03          //(擦除命令)       
#define Error 1
#define Ok 0
#define WaitTime 0x01            //定义CPU的等待时间
sfr ISP_DATA=0xc2;                //寄存器申明
sfr ISP_ADDRH=0xc3;
sfr ISP_ADDRL=0xc4;
sfr ISP_CMD=0xc5;
sfr ISP_TRIG=0xc6;
sfr ISP_CONTR=0xc7;



/* ================ 打开 ISP,IAP 功能 ================= */
void ISP_IAP_enable(void)
{
        EA        =        0;                       /* 关中断 */
        ISP_CONTR =        ISP_CONTR & 0x18;       /* 0001,1000        */
        ISP_CONTR =ISP_CONTR | WaitTime;        /* 写入硬件延时        */
        ISP_CONTR =        ISP_CONTR | 0x83;       /* ISPEN=1*/
}



/* =============== 关闭 ISP,IAP 功能 ================== */
void ISP_IAP_disable(void)
{
        ISP_CONTR        =   ISP_CONTR & 0x7f;                /* ISPEN = 0 */ //0x00是自改。
        ISP_TRIG        =        0x00;
        EA                        =   1;                        /* 开中断 */
}



/* ================ 公用的触发代码 ==================== */
void ISPgoon(void)
{
        ISP_IAP_enable();                        /* 打开 ISP,IAP 功能        */
        ISP_TRIG        =        0x5a;                /* 触发ISP_IAP命令字节1        */
        ISP_TRIG        =        0xa5;                /* 触发ISP_IAP命令字节2        */
        _nop_();
}



/* ==================== 字节读 ======================== */
uchar byte_read(uint byte_addr)
{
        ISP_ADDRH = (uchar)(byte_addr >> 8);             /* 地址赋值*/
        ISP_ADDRL = (uchar)(byte_addr & 0x00ff);
        ISP_CMD   = ISP_CMD & 0xf8;                         /* 清除低3位*/
        ISP_CMD   = ISP_CMD | RdCommand;                /* 写入读命令*/
        ISPgoon();                                        /* 触发执行*/
        ISP_IAP_disable();                                /* 关闭ISP,IAP功能*/
        return (ISP_DATA);                                /* 返回读到的数据*/
}


/* ================== 扇区擦除 ======================== */
void SectorErase(uint sector_addr)
{
        uint iSectorAddr;
        iSectorAddr = (sector_addr & 0xfe00);          /* 取扇区地址 */
        ISP_ADDRH = (uchar)(iSectorAddr >> 8);
        ISP_ADDRL = 0x00;
        ISP_CMD        = ISP_CMD & 0xf8;                        /* 清空低3位 */
        ISP_CMD        =0x03;  // ISP_CMD | EraseCommand;        /* 擦除命令3 */
        ISPgoon();                                       /* 触发执行*/
        ISP_IAP_disable();                                /* 关闭ISP,IAP功能*/
}



/* ==================== 字节写 ======================== */
void byte_write(uint byte_addr, uchar original_data)
{
        ISP_ADDRH =        (uchar)(byte_addr >> 8);            /* 取地址 */
        ISP_ADDRL =        (uchar)(byte_addr & 0x00ff);
        ISP_CMD         = ISP_CMD & 0xf8;                          /* 清低3位*/
        ISP_CMD  =ISP_CMD | PrgCommand;                          /* 写命令2*/
        ISP_DATA = original_data;                        /* 写入数据准备        */
        ISPgoon();                                        /* 触发执行*/
        ISP_IAP_disable();                                /* 关闭IAP功能*/
}

使用特权

评论回复
12
nwjjdwx|  楼主 | 2020-1-4 23:52 | 只看该作者
mycomputer0000 发表于 2020-1-4 09:44
扇区擦除需要时间的

这个擦除时间查了手册已经修改过了,还是不行,

/* ================ 打开 ISP,IAP 功能 ================= */
void ISP_IAP_enable(void)
{
        EA        =        0;                       /* 关中断 */
        ISP_CONTR =        ISP_CONTR & 0x18;       /* 0001,1000        */
        ISP_CONTR =ISP_CONTR | WaitTime;        /* 写入硬件延时        */
        ISP_CONTR =        ISP_CONTR | 0x83;       /* ISPEN=1*/
}

不知修改的对不对,望指教

使用特权

评论回复
13
nwjjdwx|  楼主 | 2020-1-5 22:02 | 只看该作者
不管是对是错,大家发表一下见解和意见啊,不管说的对不对,都感谢了,

使用特权

评论回复
14
mycomputer0000| | 2020-1-6 10:22 | 只看该作者
nwjjdwx 发表于 2020-1-5 22:02
不管是对是错,大家发表一下见解和意见啊,不管说的对不对,都感谢了,

器件手册中有例程

使用特权

评论回复
15
mycomputer0000| | 2020-1-6 10:24 | 只看该作者
本帖最后由 mycomputer0000 于 2020-1-6 10:26 编辑

希望能帮到你

使用特权

评论回复
16
nwjjdwx|  楼主 | 2020-1-6 11:08 | 只看该作者
本帖最后由 nwjjdwx 于 2020-1-6 11:35 编辑

谢谢您的回复,您是说这个写的函数有问题?谢谢您了,随后我再试试,然后我回复您,

使用特权

评论回复
17
nwjjdwx|  楼主 | 2020-1-8 00:08 | 只看该作者
进行一番修改,终于成功了,其实原来的EEPROM.h文件除了特殊寄存器的地址和触发代码不同外,其他是能用的,只是写的繁琐和复杂了一点,之所以断电不能储存数据,是因为我写的比较器中断服务程序也有问题,特把我的经验分享给大家,以期望和我有同样困惑的朋友有所帮助,就是第1:比较器中断后一定要把比较器关掉,第2:要把所有的中断都关掉,我之前认为把EA关掉就万事大吉了,其实不然,像ET0之类都要统统关掉,不然那个擦除和写入的程序就会被这些中断所打断,从而造成写入失败。最后谢谢所有关注帖子的朋友,尤其是回复的朋友,启发我对相关的方向做了细致的梳理,从而对问题的解决起到了积极作用,谢谢您们了

使用特权

评论回复
18
nwjjdwx|  楼主 | 2020-1-8 22:00 | 只看该作者
经过几次的修改,终于可以了,这个EEPROM.h文件其实除了特殊寄存器的地址和触发代码不同外,其他是可以用的,就是写的繁琐复杂了一点,我仔细看了一下书作者是针对STC89C系列芯片写的,而我用的芯片是STC15W系列的芯片,两个芯片的特殊寄存器的地址和触发代码不一样,改过来后其实就可以了,之所以写不进数据,是因为我写的比较器服务程序也有问题,在这里分享给朋友们,以期望对那些和我一样被类似问题困惑的朋友有所帮助。第1:比较器中断产生后,要把比较器关掉;第2:要把所有的中断也都关掉,以前我认为把EA关了就万事大吉了,可是这个STC15W404AS的却不行,把ET和其他的的中断都要关了,我试过只把EA关了定时器还会中断,只有把ET也关了才行,不然那个擦除和写的程序会被不断产生的中断给打断,造成写入操作失败。在这里谢谢大家关注这个帖子,尤其是回帖的朋友,谢谢您们了,是您们的指点,让我对相关的方向做了细致的梳理,从而对问题的解决起到了积极的促进作用,谢谢了

使用特权

评论回复
19
nwjjdwx|  楼主 | 2020-1-9 15:30 | 只看该作者
写了两个内容相近的帖子哈,前面的帖子是我半夜写的,发表时提示需要审核,第二天晚上我查看时审核还没通过,我以为帖子丢了呢,就又写了一个,结果第三天我再查看时审核通过了,想删掉一个吧结果还删不掉,也就两个都保留吧,

使用特权

评论回复
20
a18975740015| | 2020-2-21 18:30 | 只看该作者
疯了 这年头盗版还真多~~~~~~

使用特权

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

本版积分规则

7

主题

63

帖子

3

粉丝