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

📄 eeprom.c

📁 C51 IIC总线驱动 在单片机上测试通过 凑字凑字凑字
💻 C
字号:
//-------------------------------------------------------------------------------//
//----------void write_AT24(unsigned char address,unsigned char word);-----------//
//----------unsigned char read_AT24(unsigned char address);----------------------//
//----------使用以上两个函数可以向at24分别写读一个字节---------------------------//
//----------注意在写完一个字节后必须使用delay10ms()延迟10ms----------------------//
//-------------------------------------------------------------------------------//

//void write_AT24_S(unsigned char address,unsigned char *word,unsigned char number)//
//可以连续写字节,最多8个字节,但只能在一个扇区内写,一个扇区8个字节。因为AT24-----//
//内部地址的低三位每读一次加一位,不会进位到第四位,比如写地址为0x0f=0b00001111,---//
//低三为111加一位为000,写完地址00001111后下一个地址被写入00001000,而不是0001000--//

//void char read_AT24_S(unsigned char address,unsigned char *word,unsigned char number)//
//----------------连续读字节,同样有扇区和最多读8字节的限制,不然会--------------------//
//----------重复读之前读过的东西.最后读取的字节放在word中-------此函数暂时无法使用-----//



#include "reg51.h"
#include "intrins.h"

sbit SCL=P0^0;//rom输入时钟,最大频率为400khz,周期为2.5us,模拟时钟输出时一个周期的高低位都设为2us,也不违反高低脉冲的占空比要求,另外读或写时都最好保留1u的建立时间和保持时间
sbit SDA=P0^1;

void delay10ms(void);//数据写入rom后需要一个最大10ms的内部写入周期
void delay(void);//SCL最大时钟频率是400Khz,即一个周期最少为2.5us
void start(void);//进入start condition,进入条件为scl为高电平时sda由高电平变为低电平
void stop(void);//进入stop condition,进入条件为scl为高电平时sda有低电平变为高电平,因此sda必须在scl高电平时稳定不然就判断是否进入stat或stop
void ack(void);//每次像eeprom写入一个字节(8个scl时钟周期)数据都要确认,确认信号为eeprom发过来的0,在scl的下降沿接受
void write_byte(unsigned char);//单片机向a24写一个字节,写数据实在时钟的上升沿
void write_AT24(unsigned char,unsigned char);//将一个字节写入rom中的某个地址,地址为7位,注意用完后必须延迟10ms使数据真正写入rom
unsigned char read_byte(void);//向at24读取一个字节的过程
unsigned char read_AT24(unsigned char);//从rom读取指定地址的字节到单片机
void write_AT24_S(unsigned char,unsigned char*,unsigned char);//连续向AT24的某个地址写入i个字节,i必须小于8,不然会重写
void read_AT24_S(unsigned char,unsigned char*,unsigned char);//从指定地址连续读出指定字节
void Rack(bit);

void main(void)//测试用主函数
{
    unsigned char cc[20];
	unsigned char temp[8]={0x14,0x53,0xa6,0xff,0x1f,0x20,0xc4,0x87};
	//unsigned char temp1[8]={0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01};
    //unsigned char uu;
	unsigned char i;
	for(i=0;i<16;i++)
    {
	    //write_AT24(i,1);
		write_AT24_S((0x00+8*i),temp,0x08);
		delay10ms();
    }

    //char vv[3];//
    write_AT24_S(0x00,temp,0x08);
	delay10ms();

	//read_AT24_S(0x02,cc,0x01);

	//start();//再一个开始,不然就变写的操作了
    //write_byte(0xA1);//写入设备地址10100001,进行读的操作
	//ack();
	//cc[19]=read_byte();
	//Rack(0);
	//cc[18]=read_byte();
	//Rack(0);
	//i=read_byte();
	//Rack(1);
	//stop();
	//start();//再一个开始,不然就变写的操作了
    //write_byte(0xA1);//写入设备地址10100001,进行读的操作
	//ack();
	//cc[19]=read_byte();
	//Rack(0);
	//cc[18]=read_byte();
	//Rack(0);
	//i=read_byte();
	//Rack(1);
	//stop();
    //write_AT24(0x10,3)
	//cc[0]=read_AT24(0x00);
	for(i=0;i<20;i++)
    {
	    cc[i]=read_AT24(0x00+i);
    }
    //write_AT24(0x01,0xAA);
	//write_AT24(0x02,0xBA);
	//delay10ms();
    //ACC=read_AT24(0x01);
	    
	//delay10ms();
    //ACC=read_AT24(0x02);
	//    write_AT24(0x03,0xA0);
	//delay10ms();
   // ACC=read_AT24(0x03);
//	    write_AT24(0x04,0x4A);
//	delay10ms();
   // ACC=read_AT24(0x04);

	while(1);
	//return (0);
}


void delay10ms(void)//假设12M的晶振,一个指令周期12个震荡周期,所以一个指令周期是12/12=1us,所以需要10000个指令周期,while花费2个指令周期
{
    unsigned int i=5000;
	while(--i);
}

void delay(void)//SCL最大时钟频率是400Khz,即一个周期最少为2.5us,因此模拟时钟是高低电平的延迟时间用2us,占用两个指令周期
{
    _nop_();_nop_();
}
   
void start(void)
{
    SDA=1;
    SCL=1;
	delay();//设置Tsu.sta,按标准最小为0.6us,这里保险点用2us
	SDA=0;
	delay();//设置Thd.sta,按标准最小0.6us,这里也用2us
	SCL=0;
}

void stop(void)
{
    SDA=0;
    SCL=1;
	delay();//设置Tsu.sto,按标准最小为0.6us,这里保险点用2us
	SDA=1;
	delay();//设置Tbuf,按标准最小1.2us,这里也用2us
	//SCL=0;不用置0,可以在当前高电平中继续下一个start
}

void ack(void)
{
    //SDA=1;//锁存器置1,读取io口的值?
    SCL=0;
	delay();//scl电平的持续时间
    SCL=1;//scl时钟置0,在下降沿eeprom发出一个ack信息,单片机接受
	//if(SDA){break;} 24发送数据在时钟的下降沿,所以在scl=0和scl=1出都可以读io口的值,这里没有考虑出错的情况
	delay();//满足Tdh,标准最小50ns,这里用2us
    SCL=0;
}

void write_byte(unsigned char word)
{
	unsigned char i;
    SCL=0;
	for(i=0;i<8;i++)
	{
	    SDA=(bit)(word&0x80);
		word<<=1;
        delay();//低电平的持续时间同时保证Tsu.dat,a24准备在时钟上升沿锁存数据,前面两个语句时间够长就不用了
		SCL=1;
		delay();//高电平的持续时间,构成一个时钟周期
		SCL=0;//继续下一个时钟周期
	}
}

void write_AT24(unsigned char address,unsigned char word)
{
    start();
	write_byte(0xA0);//写入设备地址10100000
	ack();//单片机接受应答
	write_byte(address);//写入需要写入字节的地址
	ack();
	write_byte(word);//写入数据
	ack();
	stop();
}

unsigned char read_byte(void)
{
    unsigned char word;
	unsigned char i;
	unsigned char temp=0x80;
	SCL=0;
	for(i=0;i<8;i++)
	{
	    //SDA=1;//锁存器置1,准备接受io口引脚上的数据?
		delay();//时钟低电平的持续时间
		SCL=1;
		if(SDA) word|=temp;
		temp>>=1;
		delay();//时钟高电平的持续时间,可以不加,前面几个指令时间够长了
		SCL=0;
	}
	delay();//第八个也就是最后一个时钟周期读完之后产生低电平的持续时间,可以不加
	return(word);
}

unsigned char read_AT24(unsigned char address)
{
    unsigned char word;
    start();
    write_byte(0xA0);//写入设备地址10100000,先写一次需要读取自己的地址
	ack();
    write_byte(address);
	ack();
	start();//再一个开始,不然就变写的操作了
    write_byte(0xA1);//写入设备地址10100001,进行读的操作
	ack();
	word=read_byte();
	
	//SDA=1;
	//delay();
	//SCL=1;
	//delay();
	//SCL=0;
	//delay();//进行一个周期,noack
	Rack(1);

	stop();
	return(word);
}

void write_AT24_S(unsigned char address,unsigned char *word,unsigned char number)
{
    unsigned char i;
    start();
	write_byte(0xA0);//写入设备地址10100000
	ack();//单片机接受应答
	write_byte(address);//写入需要写入字节的地址
	ack();
    for(i=0;i<number;i++)
	{
	    write_byte(*(word+i));//写入数据
	    ack();
	}
	stop();
}

/*void read_AT24_S(unsigned char address,unsigned char *word,unsigned char number)
{
    //unsigned char *word;
	unsigned char i;
    start();
    write_byte(0xA0);//写入设备地址10100000,先写一次需要读取自己的地址
	ack();
    write_byte(address);
	ack();
	start();//再一个开始,不然就变写的操作了
    write_byte(0xA1);//写入设备地址10100001,进行读的操作
	ack();
	for(i=0;i<number;i++)
	{
	    *(word+i)=read_byte();
	    if(i==number-1)//如果只读一次或者读到最后一个字节要单片机要发出一个no ack信号,此外发ack
		Rack(1);
		else
		Rack(0);
	}

	stop();
	//return(word);   
}*/

void Rack(bit i)//单片机向AT24发送的ACK有ACK和no ACK两种
{
    SDA=i;
	delay();
	SCL=1;
	delay();
	SCL=0;
	delay();
}

⌨️ 快捷键说明

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