📄 5045.c
字号:
/**************************************************
;5045.c
;功能描述:
;开机后在每1、2位数码管显示00,D8点亮表示目前处于调整地址的状态
;此时按S1和S2,第1、2位数码管的数据从00~FF变化
;此时若按下S4键,则读出1、2位所示数据作为地址的EEPROM中的值,显示在第5、6位上
;按下S3键,D7点亮,表示进入调整数据状态,此时第5、6位数码管点亮显示值与第1、2位同
;按下S1和S2,第5、6位上的数据从00~FF变化
;此时若按下S4键,则将5、6位上的数据写入第1、2位指定的地址单元中
**************************************************/
#define uchar unsigned char
#define uint unsigned int
#include "reg52.h"
#include "intrins.h"
sbit CS=P2^1;
sbit SI=P3^7;
sbit Sck=P3^6;
sbit SO=P3^7;
sbit WP=P2^0;
sbit D1Led=P1^0;
sbit D2Led=P1^1;
sbit D8Led=P1^7;
bit KFirst; //第一次
bit KFunc; //代表两种功能
bit KEnter; //代表执行S4键的操作
uchar AddrCount=0; //地址计数值
uchar NumCount=0; //数据计数值
#define Wdt200 0x90 //WD1 WD0=01
#define Wdt600 0xa0 //WD1 WD0=10
#define Wdt1400 0x80 //如果最高位是1代表设置看门狗WD1 WD0 =00
#define NoWdt 0xb0 //WD1 WD0=11
#define ProQtr 0x04 //BL1 BL0=01保护区域为高128字节
#define ProHalf 0x08 //BL1 BL0=10写保护区域为高256字节
#define ProAll 0x0c //BL1 BL0=11写保护区域为整个存储器
#define NoPro 0x00 //BL1 BL0=00不写保护
#define nop2() _nop_();_nop_()
#define WREN_INST 0x06 // 写允许命令字(WREN)
#define WRDI_INST 0x04 // 写禁止命令字(WRDI)
#define WRSR_INST 0x01 // 写状态寄存器命令字(WRSR)
#define RDSR_INST 0x05 // 读状态寄存器命令字(RDSR)
#define WRITE_INST 0x02 // 写存储器命令字 (WRITE)
#define READ_INST 0x03 // 读存储器命令字 (READ)
#define MAX_POLL 0x99 //测试的最大次数
#define Hidden 0x10; //消隐字符在字形码表中的位置
uchar code BitTab[]={0x7F,0xBF,0xDF,0xEF,0xF7,0xFB};
uchar code DispTab[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,0xFF};
uchar DispBuf[6]; //6字节的显示缓冲区
uchar code TH0Val=63266/256;
uchar code TL0Val=63266%256;//当晶振为11.0592时,定时2.5ms的定时器初值
/*******************************************************************************************
;名称: OutByte
;描述:将一个字节送到EEPROM
;功能:移位送出一个字节,从最高位开始送EEPROM
*******************************************************************************************/
void OutByte(uchar Data)
{ uchar Counter=8;
for(;Counter>0;Counter--)
{
Sck=0;
if((Data&0x80)==0) //最高位是0
SI=0;
else
SI=1;
Sck=1;
Data=Data<<1;
}
SI=0;
}
/*******************************************************************************************
;名称: InByte
;描述:从EEPROM中接收数据
;功能:从EEPROM中接收数据,高位在先
*******************************************************************************************/
uchar InByte(void)
{ uchar result=0;
uchar Counter=8;
for(;Counter>0;Counter--)
{
Sck=1;
nop2();
Sck=0;
result=result<<1;
if(SO) //如果输入线是高电平
result|=0x01;
}
return (result);
}
/*******************************************************************************************
;名称:RdsrCmd
;描述:读状态寄存器
;功能:送命令用以读状态寄存器
*******************************************************************************************/
uchar RdsrCmd()
{ uchar result;
Sck=0;
CS=0;
OutByte(RDSR_INST);
result=InByte(); //读状态寄存器
Sck=0;
CS=1;
return(result);
}
/*******************************************************************************************
;名称:WipPoll
;描述:器件内部编程检查
;功能:通过检查WIP位来确定X5045内部编程是否结束
*******************************************************************************************/
void WipPoll()
{ uchar tmp;
uchar i;
for(i=0;i<MAX_POLL;i++)
{
tmp=RdsrCmd();
if((tmp&0x01)==0)
break;
}
}
/*******************************************************************************************
;名称:WrenCmd
;描述:写允许
;功能:这段程序发送命令允许写存储器单元和状态寄存器
*******************************************************************************************/
void WrenCmd()
{ Sck=0; //将SCK拉低
CS=0; //将 /CS 拉低
OutByte(WREN_INST);
Sck=0; //将SCK拉低
CS=1; // 将 /CS 升高
}
#define Wdt200 0x90 //WD1 WD0=01
#define Wdt600 0xa0 //WD1 WD0=10
#define Wdt1400 0x80 //如果最高位是1代表设置看门狗WD1 WD0 =00
#define NoWdt 0xb0 //WD1 WD0=11
#define ProQtr 0x04 //BL1 BL0=01保护区域为高128字节
#define ProHalf 0x08 //BL1 BL0=10写保护区域为高256字节
#define ProAll 0x0c //BL1 BL0=11写保护区域为整个存储器
#define NoPro 0x00 //BL1 BL0=00不写保护
/*******************************************************************************************
;名称;WrsrCmd
;描述:写状态寄存器
;功能:将WD0、WD1、BP0、BP1的状态写入状态寄存器
*******************************************************************************************/
void WrsrCmd(uchar RegCode)
{ uchar tmp;
Sck=0; //将SCK拉低
CS=0; //将 /CS 拉低
tmp=RdsrCmd(); //读出当前寄存器状态
if((RegCode&0x7f)!=0) //RegCode与0x7f(01111111)相与不等于0,说明MSB=1,即设置看门狗的命令
{ tmp&=0x0f; //首先将读到的数的高4位清零
tmp|=RegCode;
}
else
{ tmp&=0xf0; //否则是写保护类指令,清除低4位
tmp|=RegCode;
}
OutByte(WRSR_INST); //写指令
OutByte(tmp);
Sck=0;
CS=1;
OutByte(WRSR_INST); //写指令
WipPoll() ; //测试是否已器件内部是否写完
}
/*******************************************************************************************
;名称:WrdiCmd
;描述:写禁止
;功能:禁止对存储单元和状态寄存器写
*******************************************************************************************/
/*void WrdiCmd()
{ Sck=0; //将SCK拉低
CS=0; //将 /CS 拉低
OutByte(WRDI_INST);
Sck=0; //将SCK拉低
CS=1; // 将 /CS 升高
} 本程序中用不到这个函数,故注释掉,以免编译警告,需要用时将注释去掉即可*/
/*******************************************************************************************
;名称:ByteWrite
;描述:单字节写
;功能:本程序用于单字节写入EEPROM
*******************************************************************************************/
void ByteWrite(uint Address,uchar Data)
{ uchar tmp;
Sck=0;
CS=0;
tmp=WRITE_INST;
if(Address>255)
tmp|=0x08;
OutByte(tmp);
tmp=(uchar)(Address&0x00ff);
OutByte(tmp);
OutByte(Data);
Sck=0;
CS=1;
WipPoll();
}
/*******************************************************************************************
;名称:ByteRead
;描述:单字节读
;功能:本程序从EEPROM中读出一个字节
*******************************************************************************************/
uchar ByteRead(uint Address)
{ uchar tmp;
Sck=0;
CS=0;
tmp=READ_INST;
if(Address>255)
tmp|=0x08;
OutByte(tmp);
tmp=(uchar)(Address&0x00ff);
OutByte(Address);
tmp=InByte();
Sck=0;
CS=1;
return (tmp);
}
/*******************************************************************************************
;名称:RstWatchDog
;描述:复位看门狗定时器
;功能:这段程序用来复位看门狗定时器,不发送命令
*******************************************************************************************/
void RstWatchDog()
{ CS=0;
nop2();
CS=1;
}
/*******************************************************************************************
;名称:WriteString
;描述:字符中写入
;功能:向X5045指定单元开始写入一串数据
;参数:*s 指向待写数据 Adress 指定待写eeprom地址 Len 待写入字节长度
;说明:不能跨页写
*******************************************************************************************/
void WriteString(uchar *s,uint Adress,uchar Len)
{ uchar i=0;
WP=1;
WrenCmd(); //写允许
WrsrCmd(NoPro); //打开写保护块
for(i=0;i<Len;i++)
ByteWrite(Adress+i,*(s+i));
WP=0;
}
/*******************************************************************************************
;名称:ReadString
;描述:字符中读出
;功能:从X5045指定单元读出一串数据,写入s指定的开始地址
;参数:*s 指向待存数据区 Adress 指定待读eeprom地址 Len 待读入字节长度
;说明:不能跨页写
*******************************************************************************************/
void ReadString(uchar *s,uint Adress,uchar Len)
{
uchar i=0;
for(i=0;i<Len;i++)
*(s+i)=ByteRead(Adress+i);
}
/*延时程序
由Delay参数确定延迟时间
*/
void mDelay(unsigned int Delay)
{ unsigned int i;
for(;Delay>0;Delay--)
{ for(i=0;i<124;i++)
{;}
}
}
//以下是中断程序,实现显示及键盘处理
void Timer0() interrupt 1
{ uchar tmp;
static uchar dCount; //计数器,显示程序通过它得知现正显示哪个数码管
static uchar KCount; //用于键盘的计数器,控制去键抖延时,首次按下延时,连续按下时的延时
static bit KMark; //有键被按下
static bit KFunc1; //用于S3键
TH0=TH0Val;
TL0=TL0Val;
tmp=BitTab[dCount]; //根据当前的计数值取位值
P2=P2|0xfc; //P2与11111100B相或,将高6位置1
P2=P2&tmp; //P2与取出的位值相与,将某一位清零
tmp=DispBuf[dCount]; //根据当前的计数值取显示缓冲待显示值
tmp=DispTab[tmp]; //取字形码
P0=tmp; //送出字形码
dCount++; //计数值加1
if(dCount==6) //如果计数值等于6,则让其回0
dCount=0;
P3|=0x3c; //按按键的各位置1
tmp=P3;
tmp|=0xc3; //未接键的各位置1
tmp=~tmp; //取反各位
if(!tmp) //如果结果是0表示无键被按下
{ KMark=0;
KFirst=0;
KCount=0;
KFunc1=0;
return;
}
if(!KMark) //如果键按下标志无效
{ KCount=4; //去键抖
KMark=1;
return;
}
KCount--;
if(KCount!=0) //如果不等于0
return;
if((tmp&0xfb)==0) //P3.2被按下
{ if(KFunc) //要求计数值操作
NumCount++;
else
AddrCount++;
}
else if((tmp&0xf7)==0) //P3.3被按下
{ if(KFunc) //要求计数值操作
NumCount--;
else
AddrCount--;
}
else if((tmp&0xef)==0) //P3.4被按下
{ if(!KFunc1) //该位为0才进行切换,防止长时间按着反复切换
{ KFunc=!KFunc; //切换状态
KFunc1=1;
}
}
else if((tmp&0xdf)==0)
{ KEnter=1;
}
else //无键按下(出错处理)
{ KMark=0;
KFirst=0;
KCount=0;
KFunc1=0;
}
if(KFirst) //不是第一次被按下(连加)
{ KCount=20;
}
else //第一次被按下(间隔较长)
{ KCount=200;
KFirst=1;
}
}
void Init()
{ TMOD=0x01;
TH0=TH0Val;
TL0=TL0Val;
ET0=1; //开T0中断
EA=1; //开总中断
TR0=1; //T0开始运行
}
void Calc(uchar Dat1,uchar Dat2) //第一个参数放在第1、2位,第二个参数放入第5、6位
{ DispBuf[0]=Dat1/16;
DispBuf[1]=Dat1%16;
DispBuf[4]=Dat2/16;
DispBuf[5]=Dat2%16;
}
void main()
{
uchar Mtd[5]; //待写数据存入该数组
uchar Mrd[5]; //读出的数据存入该数组
Init();
WrsrCmd(NoWdt); //关闭看门狗
WrsrCmd(NoPro); //不保护
DispBuf[2]=Hidden;
DispBuf[3]=Hidden;
DispBuf[4]=Hidden;
DispBuf[5]=Hidden;
D1Led=0; //点亮"读"控制灯
CS=1;
SO=1;
Sck=0;
SI=0;
RstWatchDog(); //复位看门狗
for(;;)
{
Calc(AddrCount,NumCount);
if(KFunc)
{ D2Led=0; //点亮"读"灯
D1Led=1; //关断"写"灯
}
else
{ D1Led=0; //点亮"写"灯
D2Led=1; //关掉"读"灯
}
if(KEnter) //按下了回车键
{ if(KFunc) //写数据
{ Mtd[0]=NumCount;//当前的计数值作为待写入的值
WP=1;
D8Led=0; //点亮指示灯
WriteString(Mtd,AddrCount,1); //从Mtd开始的单元中取出1字节数据写入
WP=0;
}
else //读数据
{ D8Led=0; //点亮指示灯
ReadString(Mrd,AddrCount,1);//读出1字节数据,存入Mrd开始的单元中
NumCount=Mrd[0];
}
KEnter=0; //清回车键被按下的标志
mDelay(100); //延时一段时间(为看清D8亮过)
D8Led=1;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -