24c02.c

来自「自己单片机板c程序」· C语言 代码 · 共 343 行

C
343
字号
/*EEPROM24C02,程序将对存储器进行读和写,因此涉及到键盘程序,比较复杂,耐心学,*/

#include <reg51.h>
#include <intrins.h>


#define 	W24C02		0xA0	//存储器的写地址
#define     R24C02		0xA1	//存储器的读地址
#define  MSB       0x80			//8位二进制最高位置1
#define  LSB       0x01			//8位二进制最低位置1


/********************/
sbit SDA=P3^6;	//AT24C02串行数据				5脚 
sbit SCL=P3^7;	//AT24C02串行时钟				6脚
sbit SPK=P3^4;	//蜂鸣器,按键用时蜂鸣


void I2C_write(unsigned char tmp);		//向I2C总线写数据
unsigned char I2C_read();				//向I2C总线读数据
void I2C_ACK(bit tmp);					//ACK应答
void I2C_start(void);					//I2C传送数据的开始
void I2C_stop(void);					//I2C传送数据的结束
void _24c02menu(void);					//当我们按下按键进入处理I2C数据时用的函数
void _24c02wdate(unsigned char tmp);	//当我们对24C02存储器进行写数据用到的函数

void display(unsigned char *lp,unsigned char lc);//显示,在键盘程序里用过
void displaystr(unsigned char *lp,unsigned char lc);//字符的显示函数,同上
void delay();//延时子函数
void ReadKey(void);   //扫描键盘 获取键值

unsigned char l_key=0xFF;		//定义变量,存放键值	
unsigned char l_keyold=0;		//做为按键松开否的凭证	
code unsigned char l_24C02[5]={0x5b,0x66,0x39,0x3f,0x5b};//定义数组常量在数码管上显示24C02
unsigned char l_address=0;	//读24C02的地址变量
unsigned char l_tmpdate[6]={0,0,0x10,0,0,0};	//数组变量
code unsigned char table[]=
			{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
			0x77,0x7c,0x39,0x5e,0x79,0x71,0x40};
			//共阴数码管 0-9 a-f - 表

code unsigned char key_tab[17]={0xed,0x7e,0x7d,0x7b,
								0xbe,0xbd,0xbb,0xde,
								0xdd,0xdb,0x77,0xb7,
								0xee,0xd7,0xeb,0xe7,0XFF};//========================此数组为键盘编码,
										//	1	2	3	a					
										//	4	5	6	b	
										//	7	8	9	e				
										//	*	0	#	f	
				


void main(void)     //入口函数
{
	EA=1;			//首先开启总中断
	EX0=1;  		//开启外部中断 0
	IT0=1;        // 设置成 下降沿触发方式
	P0=0xf0;		//P0口高位输高电平,经过74HC21四输入与门,连接外中断0,有键按下调用中断函数
	while(1){
		displaystr(l_24C02,5);	//用这个函数显示5个字符
		if(l_key==0x0e){		
			l_key=0xff;			//按下#键调用		
			_24c02menu();		//此函数
		}
	}
}
//以下一部份在键盘程序里有说明,此处不在讲述
void key_scan()   interrupt 0    //外部中断 0  0的优先级最高 							
{								
	EX0=0;					
	TMOD&=0XF1;				
	TH0=0X2E;				
	TL0=0X00;
	ET0=1;				
	TR0=1;					
} 
void timer0_isr(void) interrupt 1	//定时器0的中断函数
{	
	TR0=0;						
	ReadKey();				
}
void ReadKey(void)						//读键盘值
{
	unsigned char i,j,key;
	j=0xfe;
	key=0xff;			
	for (i=0;i<4;i++){		
		P0=j;				
		if ((P0&0xf0)!=0xf0){						
			key=P0;				
			break;		
		}
		j=_crol_(j,1);			
	}
	if (key==0xff){			
		l_keyold=0xff;
		P0=0xf0;			
		EX0=1;				
		SPK=1;
		return;
	}
	SPK=0;					
	if(l_keyold==key){		
		TH0=0X2E;			
		TL0=0;
		TR0=1;		
	   	return;
	}		
	TH0=0X2E;			
	TL0=0;
	TR0=1;				

	l_keyold=key;			

	for(i=0;i<17;i++){		
		if (key==key_tab[i]){
			l_key=i;
			break;
		}
	}
}  
void display(unsigned char *lp,unsigned char lc)//显示
{
	unsigned char i;		
	P2=0;					
	P1=P1&0xF8;			
	for(i=0;i<lc;i++){		
	P2=table[lp[i]];	
	delay();			
	if(i==7)				
		break;
	P2=0;				
	P1++;
	}
}

void displaystr(unsigned char *lp,unsigned char lc)//显示
{
	unsigned char i;
	P2=0;
	P1=P1&0xF8;
	for(i=0;i<lc;i++){
	P2=lp[i];											
	delay();
	P2=0;
	if(i==7)
		break;
	P1++;
	}
}
void delay(void)								//空5个指令
{
	unsigned char i=10;
	while(i)
		i--;
}

void _24c02menu(void)		//处理I2C数据时用的函数
{
	unsigned char tmp,tmp2;
	P2=0;					//数码管显示清0
	l_key=0xfe;				//进入存储器处理程序先读取0地址的数据
	while (1){
		if(l_key==0x0c){	//如果按下*号键退出循环,即退出回到主函数
			l_key=0xff;			
			break;
		}
		switch(l_key){		//扫描键盘做相应处理
		case 0x0a:			//按下0X0A键,我们可将它理解为上翻键
			l_key=0xff;
			if(l_address>0){
				l_address--;	//将地址减1
				l_key=0xfe;		//读取数据
			}
			break;
		case 0x0b:			//按下0X0A键,我们可将它理解为下翻键
			l_key=0xff;
			if(l_address<255){
				l_address++;	//将地址加1
				l_key=0xfe;		////读取数据
			}
			break;
		case 0x0e:				//如果按下#号键,调用写存储器函数
			l_key=0xff;
			_24c02wdate(tmp);
			l_key=0xfe;
	   		break;
		case 0xfe:				//此按值是在键盘是没有的,我们有内部给他增加做为读数据处理
			l_key=0xff;		
			I2C_start();		//I2C读数据的开始,到下面的结束是读一地址的整个过程,
			I2C_write(W24C02);	//向I2C总线发出读取24C02的地址
			I2C_ACK(0);			//下面就得你们自己结合I2C串口协议进行,先看看24C02数据手册是怎么讲I2C协议的
			I2C_write(l_address);//先写入地址,
			I2C_ACK(1);
			I2C_stop();			

			I2C_start();		//再开始读取数据
			I2C_write(R24C02);			
			I2C_ACK(0);
			tmp=I2C_read();
			I2C_ACK(1);
			I2C_stop();			//读取一个地址的数据结束
			l_tmpdate[0]=l_address/16;		//数码管前两位显示地址(以16进制显示)
			l_tmpdate[1]=l_address%16;		//将地址变量分开用两位数据
			l_tmpdate[3]=tmp/100;			//后面用10进制数显示数据,中间用"-"隔开,数组l_tmpdate[2]
			tmp2=tmp%100;				//8位二进制最大十进制为255,所以我们也将它分开三位显示
			l_tmpdate[4]=tmp2/10;
			l_tmpdate[5]=tmp2%10;
			break;
		}
		display(l_tmpdate,6);
	}
}
void _24c02wdate(unsigned char tmp)//对24C02的写数据处理函数
{
	unsigned char tmp2=0;
	while(1){
	if (l_key==0x0c){	//如果按下*号键退出循环,即退出回到上一极函数
		l_key=0xff;
		break;
		}
	if(l_key==0x0e){	//如果按下#号键,将更改的数据写入24C02存储器
		l_key=0xff;
		I2C_start();	//下面是写一地址数据的过程
		I2C_write(W24C02);	//先向总线发出写24C02的地址
		I2C_ACK(0);
		I2C_write(l_address);	//写入地址
		I2C_ACK(0);
		I2C_write(tmp);			//然后写入数据
		I2C_ACK(1);
		I2C_stop();
		break;
	}
	switch(l_key){		//下面是对数据的处理
	case 0x01:			//如果按下1键,数据百位加1
		l_key=0xff;
		if(tmp<155)
			tmp+=100;
		break;
	case 0x02:			//如果按下2键,数据十位加1
		l_key=0xff;
		if(tmp<245)
			tmp+=10;
		break;
	case 0x03:			//如果按下3键,数据个位加1
		l_key=0xff;
		if(tmp<255)
			tmp++;
		break;
	case 0x04:			//如果按下4键,数据百位减1
		l_key=0xff;
		if(tmp>=100)
			tmp-=100;
		break;
	case 0x05:			//如果按下5键,数据十位减1
		l_key=0xff;
		if(tmp>=10)
			tmp-=10;
		break;
	case 0x06:			//如果按下6键,数据个位减1
		l_key=0xff;
		if(tmp>0)
			tmp--;
		break;
	}
	l_tmpdate[3]=tmp/100;	//地址不变我们不用修改,更改数据显示即可
	tmp2=tmp%100;
	l_tmpdate[4]=tmp2/10;
	l_tmpdate[5]=tmp2%10;
	display(l_tmpdate,6);
	}
}
void I2C_write(unsigned char tmp)//I2C写入一个8位二进制数,高位在前低位在后
{
	unsigned char i;
	for(i=0;i<8;i++){
		SCL=0;
		_nop_();
		_nop_();
		_nop_();
		SDA=(bit)(tmp&0x80);
		tmp<<=1;
		_nop_();_nop_();_nop_();_nop_();_nop_();		
		SCL=1;
		_nop_();_nop_();_nop_();_nop_();_nop_();		
	}
	SCL=0;
}
unsigned char I2C_read(void)////I2C读取一个8位二进制数,也是高位在前低位在后
{
	unsigned char i,tmp;
	tmp=0;
	for(i=0;i<8;i++){
		SCL=0;
		_nop_();
		_nop_();
		_nop_();			//加入空指令增加稳定性,这关系到频率问题
		SDA=1;
		_nop_();_nop_();_nop_();_nop_();_nop_();
		SCL=1;
		_nop_();_nop_();_nop_();_nop_();_nop_();
		tmp<<=1;
		if(SDA==1)
			tmp++;
	}
	SCL=0;
	return tmp;		
		
}
void I2C_ACK(bit tmp)		//根据tmp的1、0来决定应答信号
{
	SDA=tmp;		
	 _nop_();_nop_();_nop_();_nop_();_nop_();
	 SCL=1;	
	 _nop_();_nop_();_nop_();_nop_();_nop_();
	 SCL=0;		
}
void I2C_start(void)		//看看I2C开始的波形,再对应SDA、SCL的输出
{
	 SDA=1;		
	 _nop_();
	 SCL=1;  	
	 _nop_();
	 SDA=0;	
	 _nop_();
	 SCL=0;		
	 _nop_();
}

/*********/
void I2C_stop(void)		//I2C结束
{
	 SDA=0;		
	 _nop_();
	 SCL=1;		
 	 _nop_();
	 SDA=1;		
	 _nop_();
	 SCL=0;		
	 _nop_();
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?