AVR单片机SD24XX读写演示程序

//-------------------------------------------------------------------------
// SD24XX读写演示程序,此程序仅供参考
// e-mail:   FAE@whwave.com.cn
// TEL:0755-83114387
//                    2014/07/01
//-------------------------------------------------------------------------

#include <iom64v.h>
#include <macros.h>
#define  uchar unsigned char
#define  uint  unsigned int
#define  ulong unsigned long
//数据sda的位设置
#define sda_in	    DDRC &= ~(1 << PC1)	      //数据设置输入
#define sda_out	    DDRC |= (1 << PC1)	      //数据设置输出
#define sda_setb    PORTC |= (1 << PC1)       //数据拉高      
#define sda_clr     PORTC &= ~(1 << PC1)      //数据拉低      
#define sda_r       PINC & (1 << PC1)         //数据读取  
//时钟scl的位设置
#define scl_in	    DDRC &= ~(1 << PC0)	      //时钟设置输入
#define scl_out	    DDRC |= (1 << PC0)	      //时钟设置输出
#define scl_setb    PORTC |= (1 << PC0)       //时钟拉高      
#define scl_clr     PORTC &= ~(1 << PC0)      //时钟拉低      
#define scl_r       PINC & (1 << PC0)         //时钟读取 
//===============
#define true  1
#define false 0
//===============
#define		RTC_Address			0x64//RTC器件地址
//EEPROM/NVSRAM地址定义。尾缀为A的内部不带EEPROM存储器
#define		EE_FirstPage_Address		0xA0//第一页(尾缀B、C、D、E、F型有)
#define		EE_SecondPage_Address		0xA2//第二页(尾缀B、C型有)
#define		EE_ThirdPage_Address		0xA4//第三页(尾缀C型)
#define		EE_FourthPage_Address		0xA6//第四页(尾缀C型)
#define		EE_FifthPage_Address		0xA8//第五页(尾缀C型)
#define		EE_SixthPage_Address		0xAA//第六页(尾缀C型)
#define		EE_SeventhPage_Address		0xAC//第七页(尾缀C型)
#define		EE_EighthPage_Address		0xAE//第八页(尾缀C型)

uchar   data1[8];  		// EEPROM数据
uchar	Sram[8]={"01234567"};	//通用数据缓存器
typedef	struct
{
	uchar 	second;
	uchar	minute;
	uchar	hour;
	uchar	week;
	uchar	day;
	uchar	month;
	uchar	year;
}S_Time;	

S_Time  RTC={0x55,0x59,0x14,0x01,0x12,0x11,0x14};	//初始化时间结构体变量(设置时间:2014年11月12日 14:59:55  星期一)
//           55秒 59分 14时 周一 10日 11月 14年
/********SD24XX函数名********/
uchar I2CReadOneByte(uchar DeviceAddress,uchar add);//读一字节
char I2CWriteOneByte(uchar DeviceAddress,uchar add, uchar date);//写一字节
uchar I2CReadSerial(uchar DeviceAddress, uchar Address, uchar length,uchar *ps);//连续读
uchar I2CWriteSerial(uchar DeviceAddress, uchar Address, uchar length,uchar *ps);//连续写
char I2CWriteDate(S_Time	SetRTC);//写时间	
char I2CReadDate(S_Time	*psRTC);//读时间
char	WriteTimeOn(void);//写允许
char	WriteTimeOff(void);//写禁止
void Delay(uint nn);
//====================================================================
/*延时子程序*/
void delay_ms(uint time)    	       //11.0592M,time=1表示延时1ms
{
 uint i;
 for(;time>0;time--)
  for(i=0;i<1571;i++);
  asm("nop");
  asm("nop");
  asm("nop");
}
void delay_1us(void)        	       //11.0592M, 1us延时函数
  {
   asm("nop");
  }
void delay_us(uint time)     	       //11.0592M, Nus延时函数
  {
   uint i;
   for (i=0;i<time;i++)
   asm("nop");
  }  
//=====================================================================  


/********开启SD24XX的I2C总线********/
uchar I2CStart(void)
{
    	sda_out;
	scl_out;
	delay_1us();
    	sda_setb;	
	scl_setb;	
	delay_us(5);
	sda_in;
	delay_us(5);
	if(!sda_r)return false;		//SDA线为低电平则总线忙,退出
	sda_out;
	delay_1us();
	sda_clr;	
	delay_us(10);
	sda_in;    	
	delay_us(10);
	while(sda_r)return false;	//SDA线为高电平则总线出错,退出
	scl_clr;	
	delay_us(5);
	return true;

}


//********关闭SD24XX的I2C总线****//
void I2CStop(void)
{
    scl_out;
	sda_out;
	delay_1us();
	sda_clr;
	delay_1us();
	scl_clr;
	delay_us(5);
	scl_setb;
	delay_us(2);
	sda_setb;
}


//*********发送 ACK****//
void I2CAck(void)
{	
    scl_out;
	sda_out;
	delay_1us();
	sda_clr;	
	delay_1us();
	scl_clr;	
	delay_us(5);
	scl_setb;	
	delay_us(5);
	scl_clr;	
}


/*********发送NO ACK*********/
void I2CNoAck(void)
{	
    scl_out;
	sda_out;
	delay_1us();
	sda_setb;	
	delay_1us();
	scl_clr;	
	delay_us(5);
	scl_setb;	
	delay_us(5);
	scl_clr;	
}



//*********读取ACK信号*********
uchar I2CWaitAck(void) 			 //返回为:1=有ACK,0=无ACK
{
	uchar errtime=255;
	scl_out;
	sda_in;
	delay_1us();
	scl_clr;	
	delay_us(5);
	scl_setb;	
	delay_1us();
	sda_in;
	delay_1us();
	while(sda_r)	
	{
		errtime--;
		delay_1us();
		if(!errtime)
		{delay_us(10);
		scl_clr;
		return false;
                 }
	}
	scl_clr;	
	return true;
}


/************MCU向SD24XX发送一个字节*************/             
void I2CSendByte(uchar demand)		 //数据从高位到低位
{
	uchar bd=8;                                                        
	sda_out;
	scl_out;
		while(bd--)
		{
			scl_clr;  
			delay_1us;
			if(demand&0x80)
			{
			 sda_setb;
			}
			 else
			 {
			  sda_clr;
			 }
			demand<<=1;
			delay_us(3);
			scl_setb;
			delay_us(3);
		}
		scl_clr;	 
	
     
}


/*********MCU从SD24XX读入一字节*********/
uchar I2CReceiveByte(void) 		//数据从高位到低位//
{
	uchar bl=8;
	uchar ddata=0;
	scl_out;
	delay_1us();
	delay_1us();
	sda_in;			 	//端口切换为输入状态!!
	sda_setb;  			//有的单片机需要加这句,如果不需要可以删掉
	delay_1us();
	while(bl--)
	{
		ddata<<=1;              //数据从高位开始读取
		delay_1us();
		scl_clr;
		delay_us(5);	        //从高位开始 ddata|=SDA;ddata<<=1
		scl_setb;
		delay_us(5);	
		if(sda_r)
		{
			ddata|=0x01;
		}
		
		
	}
	scl_clr;
	return ddata;
}

/******I2C写一个字节******/
uchar I2CWriteOneByte(uchar DeviceAddress,uchar add, uchar date)
{		
	if(!I2CStart())return false;
	I2CSendByte(DeviceAddress);      
	I2CWaitAck();   
	I2CSendByte(add);		//设置写地址      
	I2CWaitAck();	
	I2CSendByte(date);		//写数据
	I2CWaitAck();	
	I2CStop(); 
	return	true;
}

/******I2C读一个字节程序******/
uchar I2CReadOneByte(uchar DeviceAddress,uchar add)
{		
	uchar dat;
	if(!I2CStart())return false;
	I2CSendByte(DeviceAddress);      
	if(!I2CWaitAck()){I2CStop(); return false;}
  	I2CSendByte(add);		//设置要读的地址
	I2CWaitAck();
	I2CStart();	
 	I2CSendByte(DeviceAddress+1);	
	I2CWaitAck();	
	dat=I2CReceiveByte();		//读数据
	I2CNoAck();
	I2CStop(); 
	return  dat;
}

/******写SD24XX允许程序******/
uchar WriteTimeOn(void)
{		
	if(!I2CWriteOneByte(RTC_Address,0x10,0x80))return false;
	I2CWriteOneByte(RTC_Address,0x0f,0x84);
	return	true;
}

/******写SD24XX禁止程序******/
uchar WriteTimeOff(void)
{		
	if(!I2CWriteOneByte(RTC_Address,0x0f,0))return false;
	I2CWriteOneByte(RTC_Address,0x10,0);
	return	true;
}

/******读SD24XX实时数据寄存器******/
uchar I2CReadDate(S_Time	*psRTC)
{
	
	if(!I2CStart())return false;
	I2CSendByte(RTC_Address+1); 
    if(!I2CWaitAck()){I2CStop(); return false;}
	psRTC->second=I2CReceiveByte();
	I2CAck();
	psRTC->minute=I2CReceiveByte();
	I2CAck();
	psRTC->hour=I2CReceiveByte();
	I2CAck();
	psRTC->week=I2CReceiveByte();
	I2CAck();
	psRTC->day=I2CReceiveByte();
	I2CAck();
	psRTC->month=I2CReceiveByte();
	I2CAck();
	psRTC->year=I2CReceiveByte();
	I2CNoAck();		//读时间完成,发送NoAck
	I2CStop();
	return	true;
}

/******写SD24XX实时数据寄存器******/
uchar I2CWriteDate(S_Time	SetRTC)	//写时间操作要求一次对实时时间寄存器(00H~06H)依次写入,
{                               //不可以单独对7个时间数据中的某一位进行写操作,否则可能会引起时间数据的错误进位. 
                                //要修改其中某一个数据 , 应一次性写入全部 7 个实时时钟数据.
	S_Time 	*psRTC;
    psRTC=&SetRTC;
	WriteTimeOn();				//使能,开锁
	if(!I2CStart())return false;
	I2CSendByte(RTC_Address); 
	if(!I2CWaitAck()){I2CStop(); return false;}
	I2CSendByte(0x00);			//设置写起始地址      
	I2CWaitAck();	
	I2CSendByte(psRTC->second);		//second     
	I2CWaitAck();	
	I2CSendByte(psRTC->minute);		//minute      
	I2CWaitAck();	
	I2CSendByte(psRTC->hour|0x80);		//hour ,同时设置小时寄存器最高位(0:为12小时制,1:为24小时制)
	I2CWaitAck();	
	I2CSendByte(psRTC->week);		//week      
	I2CWaitAck();	
	I2CSendByte(psRTC->day);		//day      
	I2CWaitAck();	
	I2CSendByte(psRTC->month);		//month      
	I2CWaitAck();	
	I2CSendByte(psRTC->year);		//year      
	I2CWaitAck();	
	I2CStop();
	
	WriteTimeOff();				//使能,关锁
	return	true;
}


/******设置SD24XX报警中断演示程序演示******/
void WriteALARM(void)				//设置报警时间:2015年2月14日 8:00
{						//只有设置未来的时间才有效
	WriteTimeOn();
	I2CWriteOneByte(RTC_Address,0x09,0x08);	//8时
	I2CWriteOneByte(RTC_Address,0x0b,0x14);	//14日
	I2CWriteOneByte(RTC_Address,0x0c,0x02);	//02月
	I2CWriteOneByte(RTC_Address,0x0d,0x15);	//15年
	I2CWriteOneByte(RTC_Address,0x0e,0x74);	//设置报警允许(使能年、月、日、小时报警)
	I2CWriteOneByte(RTC_Address,0x10,0x92);	//设置INT中断选通(INTS1,INTS0),及报警中断总允许位(INTAE)
	WriteTimeOff();
}

/******关闭SD24XX报警中断程序******/
void ClrALARM(void)				//关闭报警中断
{
	WriteTimeOn();
	I2CWriteOneByte(RTC_Address,0x10,0x90);
	WriteTimeOff();
}
/******设置SD24XX倒计时中断演示******/
void SetDjs(void)				//设置倒计时中断
{
	WriteTimeOn();
	I2CWriteOneByte(RTC_Address,0x10,0x0f);//先清倒计时中断总允许位(INTDE)
	I2CWriteOneByte(RTC_Address,0x10,0xf4);//设置周期性中断(IM=1)INT中断选通(INTS1,INTS0),配置倒计时中断总允许位(INTDE)
	I2CWriteOneByte(RTC_Address,0x11,0x30);//选择定时器频率源(TDS1、TDS0)为1/60HZ
	I2CWriteOneByte(RTC_Address,0x13,0x05);//倒计时初值寄存器,设置8位倒计时计数初值(5min)
	WriteTimeOff();
}

/******关闭SD24XX倒计时中断程序******/
void ClrDjs(void)          
{
	WriteTimeOn();
	I2CWriteOneByte(RTC_Address,0x10,0xf0);
	WriteTimeOff();
}
/******设置SD24XX频率中断演示******/
void SetFrq(void)					
{
	WriteTimeOn();
	I2CWriteOneByte(RTC_Address,0x10,0xa1);	//选通频率中断(INTS1,INTS0),设置频率中断总允许位(INTFE)
	I2CWriteOneByte(RTC_Address,0x11,0x09);	//设置2Hz频率中断
	WriteTimeOff();
}
/******关闭SD24XX频率中断******/
void ClrFrq(void)         
{
	WriteTimeOn();
	I2CWriteOneByte(RTC_Address,0x10,0xa0);
	WriteTimeOff();
}
//|************I2C连续读多个字节************|
//|***尾缀B、C、F型读EEPROM程序(连续读)***|
uchar I2CReadSerial(uchar DeviceAddress, uchar Address, uchar length,uchar *ps)
{
	uchar	i;
	if(!I2CStart())return false;
	I2CSendByte(DeviceAddress);      
	if(!I2CWaitAck()){I2CStop(); return false;}
  	I2CSendByte(Address);			//设置要读的地址
	I2CWaitAck();
	I2CStart();	
 	I2CSendByte(DeviceAddress+1);
	I2CWaitAck();
	for(i=0;i<length-1;i++,ps++)
	{
		*ps=I2CReceiveByte();		//读数据
		I2CAck();
	}
	*ps=I2CReceiveByte();	
	I2CNoAck();
	I2CStop(); 
	return	true;
}

//|******************I2C连续写多个字节******************|
//|******尾缀B、C型和F型写EEPROM程序(连续写)演示******|
uchar I2CWriteSerial(uchar DeviceAddress, uchar Address, uchar length,uchar *ps)
{
	uchar	i;
	if(!I2CStart())return false;
	I2CSendByte(DeviceAddress);      	//器件地址(或EEPROM页地址)
	if(!I2CWaitAck()){I2CStop(); return false;}
  	I2CSendByte(Address);			//设置起始地址
	I2CWaitAck();
	for(i=0;i<length;i++)
	{ 	
		I2CSendByte(*(ps++));		//B、C型最多连续发送16个字节数据,F型最多连续发送8个字节数据,若使
		I2CAck();			//用的是NVSRAM则无此限制,可连续写任意多个数据直到存储器的末地址。
	}
	I2CStop(); 
	return	true;
}

/******尾缀D、E型写EEPROM程序(连续写)******/
void WriteEE_DE(uchar sramadd_hi,uchar sramadd_lo,uchar sramdata)
{
	uchar n;
	I2CStart();
	I2CSendByte(EE_FirstPage_Address);		//发送页地址
	I2CWaitAck();
	I2CSendByte(sramadd_hi);			//先发送高8位地址
	I2CWaitAck();
	I2CSendByte(sramadd_lo);			//再发送低8位地址
	I2CWaitAck();  
	for(n=0;n<8;n++)
	{
		I2CSendByte(sramdata++);		//D型最多连续发送32个字节数据,E型最多连续发送64个字节数据,若使用
		I2CWaitAck();				//的是NVSRAM则无此限制,可连续写任意多个数据直到存储器的末地址。
	}
	I2CStop();
	        
}

/******D、E型读EEPROM程序******/
void ReadEE_DE(uchar sramadd_hi,uchar sramadd_lo,uchar m)
{
	uchar n;
	I2CStart();
	I2CSendByte(EE_FirstPage_Address);		//发送页地址
  	I2CWaitAck();
	I2CSendByte(sramadd_hi);			//先发送高8位地址
	I2CWaitAck();	
	I2CSendByte(sramadd_lo);			//再发送低8位地址
	I2CWaitAck(); 
	I2CStart();					//重发起始信号
	I2CSendByte(EE_FirstPage_Address+1);//发送读EEPROM命令
  	I2CWaitAck();
	for(n=0;n<m;n++)				//可读任意多个数据,直到存储器的末地址
	{
		data1[n]=I2CReceiveByte();
		if (n!=m-1)				//最后一个数据不应答
		{
			I2CAck();
		}
	}
	I2CNoAck();
	I2CStop();
}

//*****主程序演示*****//
void main()
{
	
	I2CWriteDate(RTC);	//设置时间演示
//	WriteALARM();    	//设置报警中断时间演示
//	SetDjs();		 	//设置倒计时中断演示
	SetFrq();			//设置频率中断演示
	
	I2CWriteSerial(EE_FirstPage_Address,0,8,Sram);	//Sram1数据写入EEPROM的00-07地址
	Delayms(4);					//写完EEPROM以后需要延时10ms
	I2CReadSerial(EE_FirstPage_Address,0,8,data1);	//读从EEPROM第一页的00地址开始读8字节数据(00-07地址)演示

    while(1)
	{
		I2CReadDate(&RTC);			//读时间演示
		delay_ms(100);			
    }

}
//特别提醒:当写实时时间数据时 (00H~06H), 不可以单独 对 7 个时间数据中的某一位进行写操作 ,
//否则可能会引起时间数据的错误进位 , 所以要修改其中某一个数据 , 应一次性写入全部 7 个实时时钟数据 .

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值