工控BLUCK 2021-08-09 11:06 采纳率: 78.3%
浏览 210
已结题

1602掉电怎么保存数据,上电显示掉电前数据?

开发板有256字节片内EEPROM,程序加了1602读功能,是不是哪没写对啊?就想实现掉电 数据保留,上电显示掉电前数据,这么难吗?
开个价,只要能搞定,价格合理的!普中科技的板子。

/********************************************************
* 文    件: 1602显示屏按键计数
* 作    者:
* 外部晶振: 11.0592MHZ
* 编译环境: Keil μVisio4
* 功    能: 数码管静态显示
* 注意事项:
********************************************************/
#include<reg52.h>
unsigned char code table1[] = "COUNT:";             //命名数组用来显示字符“COUNT:”
#include <intrins.h>
//定义类型,方便代码移植
 
typedef unsigned char UINT8;
typedef unsigned int  UINT16;
typedef unsigned long UINT32;
 
typedef char INT8;
typedef int  INT16;
typedef long INT32;
/*
定义寄存器 ISP
*/
sfr ISP_DATA = 0xe2;  // Flash数据寄存器
sfr ISP_ADDRH = 0xe3;// Flash高字节地址寄存器
sfr ISP_ADDRL = 0xe4;// Flash低字节地址寄存器
sfr ISP_CMD = 0xe5;// Flash命令模式寄存器
sfr ISP_TRIG = 0xe6;// Flash命令触发寄存器
sfr ISP_CONTR = 0xe7;// ISP/IAP 控制寄存器
                                  //全局变量初始化
sbit RW = P2 ^ 5;
sbit RS = P2 ^ 6;                                    //数据/命令选择接口
sbit EN = P2 ^ 7;                                    //使能接口
sbit k1 = P3 ^ 2;                            //按键1接在P3^2接口,对应外部中断0
sbit k2 = P3 ^ 3;                            //按键2接在P3^3接口,对应外部中断1
int count ;
#define NOP()
#define EEPROM_START_ADDRESS   0X2000
//微秒级延时
void DelayNus(UINT16 t)
{
UINT16 d=0;
d=t;
{
NOP();
}while(--d>0);
}
//毫秒级延时
void DelayNms(UINT16 t)
{
do
{DelayNus(1000);
}while(--t>0);
}
//EEPROM使能
void EEPROMEnable(void)
{
    ISP_CONTR = 0x81;//使能并设置好等待时间 
}
//EEPROM禁用
void EEPROMDisable(void)
{
    ISP_CONTR = 0x00;//禁止EEPROM
    ISP_CMD = 0X00;//无ISP操作
    ISP_TRIG = 0X00;//清零
    ISP_ADDRH = 0X00;//清零
    ISP_ADDRL = 0X00;//清零
}
//eeprom 设置读写地址(相对地址)
void EEPROMSetAddress(UINT16 addr)
{
    addr += EEPROM_START_ADDRESS;//初始化地址
    ISP_ADDRH = (UINT8)(addr >> 8);//设置读写地址高字节
    ISP_ADDRL = (UINT8)addr;         //设置读写地址低字节
}
//EEPROM启动
void EEPROMStart(void)
{
    ISP_TRIG = 0x46;
    ISP_TRIG = 0xB9;
}
//EEPROM读取单个字节
UINT8 EEPROMReadByte(UINT16 addr)
{
    ISP_DATA = 0X00;
    ISP_CMD = 0X01;
    EEPROMEnable();
    EEPROMSetAddress(addr);
    EEPROMStart();
    DelayNus(10);//读取一个字节需要10us
    EEPROMDisable();
    return (ISP_DATA);
}
 
//EEPROM写入单个字节
UINT8 EEPROMWriteByte(UINT16 addr, UINT8 byte)
{
 
    EEPROMEnable();
    ISP_CMD = 0X02;
    EEPROMSetAddress(addr);
    ISP_DATA = byte;
 
    EEPROMStart();
    DelayNus(60);
    EEPROMDisable();
}
UINT8 EEPROMSectorErase(UINT16 addr)
{
    ISP_CMD=0X03;
    EEPROMEnable();
    EEPROMSetAddress(addr);
    EEPROMStart();
    DelayNus(10);
    EEPROMDisable();
    }
/********************************************************
函数名:毫秒级CPU延时函数
调  用:delay_ms(?);
参  数:1~65535(参数不可为0)
返回值:无
结  果:占用CPU方式延时与参数数值相同的毫秒时间
备  注:应用于1T单片机时i<600,应用于12T单片机时i<125
/********************************************************/
void delay(unsigned int a)
{
    unsigned int i;
    while (--a != 0) {
        for (i = 0; i < 125; i++);
    }
}
/********************************************************
函数名:写指令函数
调  用:writeinstruction(x);
参  数:无符号十六进制数0x??
返回值:无
结  果:将指令发送给1602控制器
/********************************************************/
void  writeinstruction(unsigned char x)
{
    RS = 0;
    EN = 0;
    RW = 0;
    P0 = x;
    delay(5);
    EN = 1;
    delay(5);
    EN = 0;
}
/*********************************************************
函数名:写数据函数
调  用:writedata(y);
参  数:无符号十六进制数0x??
返回值:无
结  果:将数据发送至1602内部的显示内存中
/*********************************************************/
void  writedata(unsigned char y)
{
    RS = 1;
    EN = 0;
    RW = 0;
    P0 = y;
    delay(5);
    EN = 1;
    delay(5);
    EN = 0;
}
void  readdata(unsigned char y)
{
    RS = 1;
    RW = 1;
    EN = 0;
    P0 = y;
    delay(5);
    EN = 1;
    delay(5);
    EN = 0;
    EEPROMWriteByte(0x2000, count);
    EEPROMWriteByte(0x2001, count>>8);
}
/********************************************************
函数名:写变量函数
调  用:writechar(z);
参  数:无符号十六进制数0x??
返回值:无
结  果:将数据发送至1602内部的显示内存中
备  注:不能将整数型变量count直接作为writedata的参数,需要将个、十、百位分别+48(0x30)转化成ascii码。
/*********************************************************/
void  writechar(unsigned char z)
{
    unsigned char A;
    unsigned char B;
    unsigned char C;
    RS = 1;
    EN = 0;
    RW = 0;
    A = z / 1 % 10;                                    //取个位
    B = z / 10 % 10;                                //取十位
    C = z / 100 % 10;                                //取百位
    writedata(C + 48);
    delay(5);
    writedata(B + 48);                            //分离出变量的每一位数,再将每一位加上0x30,
    delay(5);
    writedata(A + 48);                            //这样就变成了ASCII码了,再送给LCD才能显示出来变量的每一位的值。
    delay(5);
}
/*********************************************************
函数名:1602设置初始化函数
调  用:init1602();
参  数:无
返回值:无
结  果:初始化。具体指令在手册中查询。
/*********************************************************/
void  init1602()
{
    writeinstruction(0x38);                        //设置显示模式 指令码 00111000 => 0x38      
    delay(5);
    writeinstruction(0x0C);                        //[00001DCB]:D为显示开关,B为光标开关,C为光标闪烁开关。0x0C:开显示 不显示光标 不闪烁
    delay(5);
    writeinstruction(0x06);                        //写一个字符后地址指针加一
    delay(5);
    writeinstruction(0x01);                       //清屏       
    delay(5);
}
/**********************************************************
函数名:主函数main
/**********************************************************/
void  main()
{
    char i;
    EEPROMSectorErase(0);
    EEPROMWriteByte(0x2000, count);
    EEPROMWriteByte(0x2001, count>>8);
    count = EEPROMReadByte(0x2000);
    count |= (EEPROMReadByte(0x2001)<<8);
    init1602();

    writeinstruction(0x80);                      //设置数据地址指针从第一个开始
    delay(5);
    /* 初始化中断 */
    EA = 1;
    EX0 = 1;
    EX1 = 1;
    /* 写初始字符:COUNT:0 */
    for (i = 0; i < 6; ++i)                     //逐个写入第一行数据
    {
        writedata(table1[i]);
        delay(10);
    }
    writeinstruction(0x02);                     //第一行光标返回
    writeinstruction(0x80 + 0x40);                 //数据地址指针指向第二行第一个    
    
    
    writechar(count);
    /*砸瓦鲁多 */
    while (1);                                    //程序停在这里,等待中断到来
}
/*********************************************************
函数名:中断显示计数值函数
调  用:按下button1
参  数:无
返回值:无
结  果:显示当前计数值。具体指令在手册中查询。
/*********************************************************/
void Display()interrupt 0 using 1
{
    int i;
    if (k1 == 0)
    {
        delay(20);
        if (k1 == 0)
        {
         
            count++;                              //按键松开后,程序会运行到这里,计数值加1
            while (!k1);                          //如果按键没有松开,程序会停在这里
        }
        writeinstruction(0x01);                     //清屏   
        for (i = 0; i < 6; ++i)                  //逐个写入第一行数据
        {
            writedata(table1[i]);
            delay(20);
        }
        
        EEPROMWriteByte(0x2000, count);
        EEPROMWriteByte(0x2001, count>>8);
        writeinstruction(0x02);                 //回车
        writeinstruction(0x80 + 0x40);          //换行                    
        writechar(count);
        
    }
    /*********************************************************
    函数名:中断清零函数
    调  用:按下button2;
    参  数:无
    返回值:无
    结  果:计数值清零。具体指令在手册中查询。
    /*********************************************************/
}
void Clear() interrupt 2 using 1
{
    int i;
    writeinstruction(0x01);
    count = 0;                                     //count计数清零
    for (i = 0; i < 6; ++i)                     //逐个写入第一行数据
    {
        writedata(table1[i]);
        delay(20);
    }
    writeinstruction(0x02);                     //回车
    writeinstruction(0x80 + 0x40);                 //换行
    writechar(count);
}


上电就显示000

img

  • 写回答

2条回答 默认 最新

  • soar3033 2021-08-09 13:07
    关注
    
    /********************************************************
    * 文    件: 1602显示屏按键计数
    * 作    者:
    * 外部晶振: 11.0592MHZ
    * 编译环境: Keil μVisio4
    * 功    能: 数码管静态显示
    * 注意事项:
    ********************************************************/
    #ifndef __I2C_H_
    #define __I2C_H_
    #include <reg52.h>
    sbit SCL = P2 ^ 1;
    sbit SDA = P2 ^ 0;
    void I2cStart();
    void I2cStop();
    unsigned char I2cSendByte(unsigned char dat);
    unsigned char I2cReadByte();
    void At24c02Write(unsigned char addr, unsigned char dat);
    unsigned char At24c02Read(unsigned char addr);
    #endif
    
    unsigned char code table1[] = "COUNT:";             //命名数组用来显示字符“COUNT:”
    unsigned char count = 0;     
    unsigned char countl;
    unsigned char num = 0;
    
    sbit RW = P2 ^ 5;
    sbit RS = P2 ^ 6;                                    //数据/命令选择接口
    sbit EN = P2 ^ 7;                                    //使能接口
    sbit k1 = P3 ^ 2;                            //按键1接在P3^2接口,对应外部中断0
    sbit k2 = P3 ^ 3;                            //按键2接在P3^3接口,对应外部中断1
    /********************************************************
    函数名:毫秒级CPU延时函数
    调  用:delay_ms(?);
    参  数:1~65535(参数不可为0)
    返回值:无
    结  果:占用CPU方式延时与参数数值相同的毫秒时间
    备  注:应用于1T单片机时i<600,应用于12T单片机时i<125
    /********************************************************/
    void delay(unsigned int a)
    {
        unsigned int i;
        while (--a != 0) {
            for (i = 0; i < 125; i++);
        }
    }
    /********************************************************
    函数名:写指令函数
    调  用:writeinstruction(x);
    参  数:无符号十六进制数0x??
    返回值:无
    结  果:将指令发送给1602控制器
    /********************************************************/
    void  writeinstruction(unsigned char x)
    {
        RS = 0;
        EN = 0;
        RW = 0;
        P0 = x;
        delay(5);
        EN = 1;
        delay(5);
        EN = 0;
    
    }
    /*********************************************************
    函数名:写数据函数
    调  用:writedata(y);
    参  数:无符号十六进制数0x??
    返回值:无
    结  果:将数据发送至1602内部的显示内存中
    /*********************************************************/
    void  writedata(unsigned char y)
    {
        RS = 1;
        EN = 0;
        RW = 0;
        P0 = y;
        delay(5);
        EN = 1;
        delay(5);
        EN = 0;
    }
    void  readdata(unsigned char y)
    {
        RS = 1;
        RW = 1;
        EN = 0;
        P0 = y;
        delay(5);
        EN = 1;
        delay(5);
        EN = 0;
        delay(50);
    }
    /*********************************************************
    函数名:写变量函数
    调  用:writechar(z);
    参  数:无符号十六进制数0x??
    返回值:无
    结  果:将数据发送至1602内部的显示内存中
    备  注:不能将整数型变量count直接作为writedata的参数,需要将个、十、百位分别+48(0x30)转化成ascii码。
    /*********************************************************/
    void  writechar(unsigned char z)
    {
        unsigned char A;
        unsigned char B;
        unsigned char C;
        RS = 1;
        EN = 0;
        RW = 0;
        A = z / 1 % 10;                                    //取个位
        B = z / 10 % 10;                                //取十位
        C = z / 100 % 10;                                //取百位
        writedata(C + 48);
        delay(5);
        writedata(B + 48);                            //分离出变量的每一位数,再将每一位加上0x30,
        delay(5);
        writedata(A + 48);                            //这样就变成了ASCII码了,再送给LCD才能显示出来变量的每一位的值。
        delay(5);
    
    }
    /*********************************************************
    函数名:1602设置初始化函数
    调  用:init1602();
    参  数:无
    返回值:无
    结  果:初始化。具体指令在手册中查询。
    /*********************************************************/
    void  init1602()
    {
        writeinstruction(0x38);                        //设置显示模式 指令码 00111000 => 0x38      
        delay(5);
        writeinstruction(0x0C);                        //[00001DCB]:D为显示开关,B为光标开关,C为光标闪烁开关。0x0C:开显示 不显示光标 不闪烁
        delay(5);
        count = At24c02Read(1);
        delay(5);
        writeinstruction(0x06);                        //写一个字符后地址指针加一
        delay(5);
        writeinstruction(0x01);                       //清屏       
        delay(5);
    }
    /**********************************************************
    函数名:主函数main
    /**********************************************************/
    void  main()
    {
        char i;
        init1602();
        writeinstruction(0x80);                      //设置数据地址指针从第一个开始
        delay(5);
    
        /* 初始化中断 */
        EA = 1;
        EX0 = 1;
        EX1 = 1;
        /* 写初始字符:COUNT:0 */
        for (i = 0; i < 6; ++i)                     //逐个写入第一行数据
        {
            writedata(table1[i]);
            delay(20);
    
        }
        writeinstruction(0x02);                     //第一行光标返回
        writeinstruction(0x80 + 0x40);                 //数据地址指针指向第二行第一个    
        delay(10);
        writechar(count);
        delay(10);
        count = At24c02Read(1);
        countl = count;
        delay(10);
        /*砸瓦鲁多 */
        while (1)                                 //程序停在这里,等待中断到来
        {
            if (count!=countl)
            {
                At24c02Write(1, count);
            }
            countl = count;
            delay(100);
        }
    }
    /*********************************************************
    函数名:中断显示计数值函数
    调  用:按下button1
    参  数:无
    返回值:无
    结  果:显示当前计数值。具体指令在手册中查询。
    /*********************************************************/
    void Display()interrupt 0 using 1
    {
        int i;
        if (k1 == 0)
        {
            delay(10);
            if (k1 == 0)
            {
                count++;
                delay(10);
                readdata(count);
                delay(100);
    
                //按键松开后,程序会运行到这里,计数值加1
                while (!k1);                     //如果按键没有松开,程序会停在这里
            }
            writeinstruction(0x01);                     //清屏   
            for (i = 0; i < 6; ++i)                  //逐个写入第一行数据
            {
                writedata(table1[i]);
                delay(20);
            }
            writeinstruction(0x02);                 //回车
            writeinstruction(0x80 + 0x40);          //换行
            delay(15);
            writechar(count);
        }
        /*********************************************************
        函数名:中断清零函数
        调  用:按下button2;
        参  数:无
        返回值:无
        结  果:计数值清零。具体指令在手册中查询。
        /*********************************************************/
    }
    /*void Clear() interrupt 2 using 1
    {
        int i;
        writeinstruction(0x01);
        count = 0;                                     //count计数清零
        for (i = 0; i < 6; ++i)                     //逐个写入第一行数据
        {
            writedata(table1[i]);
            delay(20);
        }
        writeinstruction(0x02);                     //回车
        writeinstruction(0x80 + 0x40);                 //换行
        writechar(count);
    }     */
    
    /*******************************************************************************
    * oˉêy??         : Delay10us()
    * oˉêy1|?ü           : ?óê±10us
    * ê?è?           : ?T
    * ê?3?              : ?T
    *******************************************************************************/
    void Delay10us()
    {
        unsigned char a, b;
        for (b = 1; b > 0; b--)
            for (a = 2; a > 0; a--);
    }
    /*******************************************************************************
    * oˉêy??         : I2cStart()
    * oˉêy1|?ü         : ?eê?D?o?£o?úSCLê±?óD?o??ú??μ????ú??SDAD?o?2úéúò??????μ??
    * ê?è?           : ?T
    * ê?3?              : ?T
    * ±?×¢           : ?eê???oóSDAoíSCL???a0
    *******************************************************************************/
    void I2cStart()
    {
        SDA = 1;
        Delay10us();
        SCL = 1;
        Delay10us();//?¨á¢ê±??ê?SDA±£3?ê±??>4.7us
        SDA = 0;
        Delay10us();//±£3?ê±??ê?>4us
        SCL = 0;
        Delay10us();
    }
    /*******************************************************************************
    * oˉêy??         : I2cStop()
    * oˉêy1|?ü         : ???1D?o?£o?úSCLê±?óD?o???μ????ú??SDAD?o?2úéúò???é?éy??
    * ê?è?           : ?T
    * ê?3?              : ?T
    * ±?×¢           : ?áê???oó±£3?SDAoíSCL???a1£?±íê?×ü?????D
    *******************************************************************************/
    void I2cStop()
    {
        SDA = 0;
        Delay10us();
        SCL = 1;
        Delay10us();//?¨á¢ê±??′óóú4.7us
        SDA = 1;
        Delay10us();
    }
    /*******************************************************************************
    * oˉêy??         : I2cSendByte(unsigned char dat)
    * oˉêy1|?ü         : í¨1yI2C·¢?íò???×??ú?£?úSCLê±?óD?o???μ????ú??£?±£3?·¢?íD?o?SDA±£3??è?¨
    * ê?è?           : num
    * ê?3?              : 0?ò1?£·¢?í3é1|·μ??1£?·¢?í꧰ü·μ??0
    * ±?×¢           : ·¢?ííêò???×??úSCL=0,SDA=1
    *******************************************************************************/
    unsigned char I2cSendByte(unsigned char dat)
    {
        unsigned char a = 0, b = 0;//×?′ó255£?ò????ú?÷?ü?ú?a1us£?×?′ó?óê±255us?£        
        for (a = 0; a < 8; a++)//òa·¢?í8??£?′ó×??????aê?
        {
            SDA = dat >> 7;     //?eê?D?o???oóSCL=0£??ùò??éò??±?ó??±?SDAD?o?
            dat = dat << 1;
            Delay10us();
            SCL = 1;
            Delay10us();//?¨á¢ê±??>4.7us
            SCL = 0;
            Delay10us();//ê±??′óóú4us        
        }
        SDA = 1;
        Delay10us();
        SCL = 1;
        while (SDA)//μè′yó|′e£?ò2?íê?μè′y′óéè±?°?SDAà-μí
        {
            b++;
            if (b > 200)     //è?1?3?1y2000us??óDó|′e·¢?í꧰ü£??ò???a·?ó|′e£?±íê??óê??áê?
            {
                SCL = 0;
                Delay10us();
                return 0;
            }
        }
        SCL = 0;
        Delay10us();
        return 1;
    }
    /*******************************************************************************
    * oˉêy??         : I2cReadByte()
    * oˉêy1|?ü           : ê1ó?I2c?áè?ò???×??ú
    * ê?è?           : ?T
    * ê?3?              : dat
    * ±?×¢           : ?óê?íêò???×??úSCL=0,SDA=1.
    *******************************************************************************/
    unsigned char I2cReadByte()
    {
        unsigned char a = 0, dat = 0;
        SDA = 1;            //?eê?oí·¢?íò???×??ú??oóSCL??ê?0
        Delay10us();
        for (a = 0; a < 8; a++)//?óê?8??×??ú
        {
            SCL = 1;
            Delay10us();
            dat <<= 1;
            dat |= SDA;
            Delay10us();
            SCL = 0;
            Delay10us();
        }
        return dat;
    }
    /*******************************************************************************
    * oˉêy??         : void At24c02Write(unsigned char addr,unsigned char dat)
    * oˉêy1|?ü           : íù24c02μ?ò???μ??·D′è?ò???êy?Y
    * ê?è?           : ?T
    * ê?3?              : ?T
    *******************************************************************************/
    void At24c02Write(unsigned char addr, unsigned char dat)
    {
        I2cStart();
        I2cSendByte(0xa0);//·¢?íD′?÷?tμ??·
        I2cSendByte(addr);//·¢?íòaD′è??ú′?μ??·
        I2cSendByte(dat);    //·¢?íêy?Y
        I2cStop();
    }
    /*******************************************************************************
    * oˉêy??         : unsigned char At24c02Read(unsigned char addr)
    * oˉêy1|?ü           : ?áè?24c02μ?ò???μ??·μ?ò???êy?Y
    * ê?è?           : ?T
    * ê?3?              : ?T
    *******************************************************************************/
    unsigned char At24c02Read(unsigned char addr)
    {
        unsigned char num;
        I2cStart();
        I2cSendByte(0xa0); //·¢?íD′?÷?tμ??·
        I2cSendByte(addr); //·¢?íòa?áè?μ?μ??·
        I2cStart();
        I2cSendByte(0xa1); //·¢?í?á?÷?tμ??·
        num = I2cReadByte(); //?áè?êy?Y
        I2cStop();
        return num;
    }
    
    
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 8月10日
  • 已采纳回答 8月10日
  • 修改了问题 8月9日
  • 赞助了问题酬金 8月9日
  • 展开全部

悬赏问题

  • ¥15 #MATLAB仿真#车辆换道路径规划
  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建
  • ¥15 数据可视化Python
  • ¥15 要给毕业设计添加扫码登录的功能!!有偿
  • ¥15 kafka 分区副本增加会导致消息丢失或者不可用吗?
  • ¥15 微信公众号自制会员卡没有收款渠道啊
  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘