开发板有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
/********************************************************
* 文 件: 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;
}
你的主函数里每次启动时都先给EEPROM写了一个初始值,然后再读取,把主函数里这段删掉应该就可以了
删掉以后每次就是读取上次存储在EEPROM里的值了
void main()
{
char i;
EEPROMSectorErase(0);
// 删掉这两段 EEPROMWriteByte(0x2000, count);
//删掉这两段 EEPROMWriteByte(0x2001, count>>8);
...............