51单片机内部E2ROM

来源:互联网 发布:知乎hexo简书 编辑:程序博客网 时间:2024/05/22 14:39
/*main.c源程序*/
#include <reg52.h>
#include "E2ROM.c"
#include "key.c"

sfr WDT_CONTR = 0xE1;//定义STC单片机中新加入的看门狗寄存器

code uchar seven_seg[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};//共阳数码管0--9(0时为有效断)
code uchar scan_bit[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf};                                //数码管位选 6 5 4 3 2 1

uchar cp1 = 0;
uchar cp2 = 0;
uchar j = 0;           //控制数码管的位选
uchar flash = 0;     //控制小数点闪烁

/*延时函数*/
void delayms(uint ms)
{
     uint i, j;

     for(i = ms; i > 0; i--)//i = ms 即延时约ms毫秒
     {
          for(j = 110; j > 0; j--);
     }
}
/***********************中断初始化函数**********************/
void timer0_init(void)
{
     TMOD = 0x01;      //中断方式1    
     TH0 = 0xf8;
     TL0 = 0x2f;          //对机器脉冲计数,2000个计满溢出引发中断
     EA = 1;               //开总中断
     ET0 = 1;          //开T0中断
     TR0 = 1;          //启动定时器T0
}
/*******************Timer0中断服务函数**********************/
void timer0_isr(void) interrupt 1
{
     TH0 = 0xf8;        //重新附初值
     TL0 = 0x2f;        //重新附初值
     cp1++;
     if(cp1 >= 250)//半秒
     {
          cp1 = 0;
          cp2++;
          flash = ~flash;    //每半秒取反一次
     }
     if(cp2 >= 2)//一秒
     {         
          cp2 = 0;
          sec++;
          SectorErase(0x2000);          //擦除第一扇区
          byte_write(0x2000, sec);     //重新写入数据
     }
     if(sec >= 60)//当秒为60时分钟开始计数
     {
          sec = 0;
          min++;
          SectorErase(0x2200);          //擦除第二扇区
          byte_write(0x2200, min);     //重新写入数据
     }
     if(min >= 60)//当分钟为60时小时开始计数
     {
          min = 0;
          hour++;
          SectorErase(0x2400);          //擦除第三扇区
          byte_write(0x2400, hour);     //重新写入数据
     }
     if(hour  >= 24)
     {
          hour = 0;               //当小时大于24时小时赋值为0
     }
     P0 = 0xff;                    //Protues仿真需要消隐
     //显示正在走时间
     if(key_flag == 0)
     {
          switch(j)
          {
               case 0 : P0 = seven_seg[sec % 10]; break;
               case 1 : P0 = seven_seg[sec / 10]; break;
               case 2 : P0 = seven_seg[min % 10] & (0x7f | flash); break;
               case 3 : P0 = seven_seg[min / 10]; break;
               case 4 : P0 = seven_seg[hour % 10] & (0x7f | flash);break;
               case 5 : P0 = seven_seg[hour / 10]; break;
          }
     }
     //显示调整的小时
     if(key_flag == 1)
     {
          switch(j)
          {
               case 0 : P0 = seven_seg[time[2] % 10]; break;
               case 1 : P0 = seven_seg[time[2] / 10]; break;
               case 2 : P0 = seven_seg[time[1] % 10] & 0x7f; break;
               case 3 : P0 = seven_seg[time[1] / 10]; break;
               case 4 : P0 = seven_seg[time[0] % 10] & 0x7f | flash; break;
               case 5 : P0 = seven_seg[time[0] / 10] | flash; break;
          }
     }
     //显示调整的分钟
     if(key_flag == 2)
     {
          switch(j)
          {
               case 0 : P0 = seven_seg[time[2] % 10]; break;
               case 1 : P0 = seven_seg[time[2] / 10]; break;
               case 2 : P0 = seven_seg[time[1] % 10] & 0x7f | flash; break;
               case 3 : P0 = seven_seg[time[1] / 10] | flash; break;
               case 4 : P0 = seven_seg[time[0] % 10] & 0x7f; break;
               case 5 : P0 = seven_seg[time[0] / 10]; break;
          }
     }
     //显示调整的秒
     if(key_flag == 3)
     {
          switch(j)
          {
               case 0 : P0 = seven_seg[time[2] % 10] | flash; break;
               case 1 : P0 = seven_seg[time[2] / 10] | flash; break;
               case 2 : P0 = seven_seg[time[1] % 10] & 0x7f; break;
               case 3 : P0 = seven_seg[time[1] / 10]; break;
               case 4 : P0 = seven_seg[time[0] % 10] & 0x7f; break;
               case 5 : P0 = seven_seg[time[0] / 10]; break;
          }
     }
     //显示定闹的小时
     if(key_flag == 4)
     {
          switch(j)
          {
               case 0 : P0 = seven_seg[time[4] % 10]; break;
               case 1 : P0 = seven_seg[time[4] / 10]; break;
               case 2 : P0 = seven_seg[time[3] % 10] & 0x7f | flash; break;
               case 3 : P0 = seven_seg[time[3] / 10] | flash; break;
               case 4 : P0 = 0xc8; break;
               case 5 : P0 = 0xc8; break;
          }
     }
     //显示定闹的小时
     if(key_flag == 5)
     {
          switch(j)
          {
               case 0 : P0 = seven_seg[time[4] % 10] | flash; break;
               case 1 : P0 = seven_seg[time[4] / 10] | flash; break;
               case 2 : P0 = seven_seg[time[3] % 10] & 0x7f; break;
               case 3 : P0 = seven_seg[time[3] / 10]; break;
               case 4 : P0 = 0xc8; break;
               case 5 : P0 = 0xc8; break;
          }
     }
     P2 = scan_bit[j];
     j++;
     j %= 6;
}
/***********************主函数*************************/
void main(void)
{
     WDT_CONTR = 0x35;                    //看门狗溢出时间65.5ms,喂狗时

     timer0_init();                         //调用中断初始化函数
     sec = byte_read(0x2000);          //程序开始时读取EEPROM中数据
     min = byte_read(0x2200);          //程序开始时读取EEPROM中数据
     hour = byte_read(0x2400);          //程序开始时读取EEPROM中数据
     time[3] = byte_read(0x2600);     //程序开始时读取EEPROM中数据
     time[4] = byte_read(0x2800);     //程序开始时读取EEPROM中数据
 
     while(1)
     {
          delayms(45);     //该时间可以调,控制看门狗复位
          scan_key();          //调按键扫描函数
              
          WDT_CONTR = 0x35;//设定看门狗寄存器,如果内部寄存器的CLR_WDT位被置为1,有硬件自动将看门狗定时器清零                
     }                                                                
}


/*E2ROM.c源程序*/
#include <intrins.h>
#include <reg52.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  &= 0x18;          /*0001, 1000*/
     ISP_CONTR |= WaitTime;     /*写入硬件延时*/
     ISP_CONTR |= 0x80;          /*ISPEN = 1*/
}
/*关闭ISP, IAP功能*/
void ISP_IAP_disable(void)
{
     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 &=  0xf8;                              /*清除低3位*/
     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 &= 0xf8;                              /*清除低三位*/
     ISP_CMD |= EraseCommand;                    /*擦除命令*/
     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 &= 0xf8;                              /*清除低3位*/
     ISP_CMD |= PrgCommand;                         /*写命令2*/
     ISP_DATA = original_data;                    /*写数据准备*/
     ISPgoon();                                        /*触发执行*/

     ISP_IAP_disable();                              /*关闭ISP,IAP功能*/              
}
/*按键key.c源程序*/
#define uchar unsigned char     //宏定义用uchar 代替 unsigned char
#define uint unsigned int     //宏定义用uint 代替 unsigned int

sbit key_set = P1^4;          //模式按键分别调 时,分,秒,定时,定分。(调到该模式会闪烁)
sbit key_add = P1^5;          //加按键
sbit key_cut = P1^6;          //减按键
sbit key_rest = P1^7;         //复位键

uchar hour = 12;
uchar min = 55;
uchar sec = 56;                    //正在走的时间
char time[5] = 0;               //调整的时间
char key_flag = 0;               //案件调整模式与是时间显示的中间变量

void delay(uint x);               //声明延时函数
/*****************按键扫描函数********************/
void scan_key(void)
{
     //模式按键分别调 时,分,秒,定时,定分。(调到该模式会闪烁)
     if(key_set == 0)     //如果按键按下
     {                        
          delay(300);          //消除键抖
          if(key_set == 0)//如果按键确实按下
          {
               while(key_set == 0);//按键抬起有效
               key_flag++;
               if(key_flag >= 6)
               {
                    key_flag = 1;
               }
               time[0] = hour;          //将正在走的小时赋值调整的小时time[0]
               time[1] = min;          //将正在走的分钟赋值调整的分钟time[1]
               time[2] = sec;          //将正在走的秒赋值调整的秒time[2]
          }
     }
     //加按键
     if(key_add == 0)    //如果按键按下
     {
          delay(300);         //消除键抖
          if(key_add == 0)//如果按键确实按下
          {
               while(key_add == 0);//按键抬起有效
               if(key_flag == 1) time[0]++; if(time[0] >= 24) time[0] = 0; hour = time[0];//调小时
               if(key_flag == 2) time[1]++; if(time[1] >= 60) time[1] = 0; min = time[1]; //调分钟
               if(key_flag == 3) time[2]++; if(time[2] >= 60) time[2] = 0; sec = time[2]; //调秒
               if(key_flag == 4) time[3]++; if(time[3] >= 24) time[3] = 0;                       //定小时
               if(key_flag == 5) time[4]++; if(time[4] >= 60) time[4] = 0;                       //定分钟
          }
     }
     //减按键
     if(key_cut == 0)    //如果按键按下
     {
          delay(300);         //消除键抖
          if(key_cut == 0)//如果按键确实按下
          {
               while(key_cut == 0);//按键抬起有效
               if(key_flag == 1) time[0]--; if(time[0] < 0) time[0] = 23; hour = time[0];//调小时
               if(key_flag == 2) time[1]--; if(time[1] < 0) time[1] = 59; min = time[1]; //调分钟
               if(key_flag == 3) time[2]--; if(time[2] < 0) time[2] = 59; sec = time[2]; //调秒
               if(key_flag == 4) time[3]--; if(time[3] < 0) time[3] = 23;                       //定小时
               if(key_flag == 5) time[4]--; if(time[4] < 0) time[4] = 59;                       //定分钟
          }
     }
     //复位键
     if(key_rest == 0)    //如果按键按下
     {
          delay(300);         //消除键抖
          if(key_rest == 0)//如果按键确实按下
          {
               while(key_rest == 0);//按键抬起有效
               key_flag = 0;
               SectorErase(0x2000);          //擦除第一扇区
               byte_write(0x2000, sec);     //重新写入数据
               SectorErase(0x2200);          //擦除第二扇区
               byte_write(0x2200, min);     //重新写入数据
               SectorErase(0x2400);          //擦除第三扇区
               byte_write(0x2400, hour);     //重新写入数据
               SectorErase(0x2600);          //擦除第四扇区
               byte_write(0x2600, time[3]);//重新写入数据
               SectorErase(0x2800);          //擦除第五扇区
               byte_write(0x2800, time[4]);//重新写入数据
          }
     }                             
}
/*******************延时函数**********************/
void delay(uint x)
{
     while(x--);
}
0 0
原创粉丝点击