⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 5045.c

📁 功能描述: 开机后在每1、2位数码管显示00
💻 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 + -