IIC读写AT24Cxx (S3C2440)

IIC(Inter-Integrated Circuit,I2C)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微处理器及其外围设备,它的最主要优点是简单和有效。它只需要数据线SDA和时钟线SCL,就能够实现CPU与被控IC之间、IC与IC之间进行双向传送。

s3c2440内部有一个IIC总线接口,因此为我们连接带有IIC通信模块的外围设备提供了便利。它具有四种操作模式:主设备发送模式、主设备接收模式、从设备发送模式和从设备接收模式。在这里我们只把s3c2440当做IIC总线的主设备来使用,因此只介绍前两种操作模式。在主设备发送模式下,它的工作流程为:首先配置IIC模式,然后把从设备地址写入接收发送数据移位寄存器IICDS中,再把0xF0写入控制状态寄存器IICSTAT中,这时等待从设备发送应答信号,如果想要继续发送数据,那么在接收到应答信号后,再把待发送的数据写入寄存器IICDS中,清除中断标志后,再次等待应答信号;如果不想再发送数据了,那么把0x90写入寄存器IICSTAT中,清除中断标志并等待停止条件后,即完成了一次主设备的发送。在主设备接收模式下,它的工作流程为:首先配置IIC模式,然后把从设备地址写入接收发送数据移位寄存器IICDS中,再把0xB0写入控制状态寄存器IICSTAT中,这时等待从设备发送应答信号,如果想要接收数据,那么在应答信号后,读取寄存器IICDS,清除中断标志;如果不想接收数据了,那么就向寄存器IICSTAT写入0x90,清除中断标志并等待停止条件后,即完成了一次主设备的接收。在完成上述两个模式时,主要用到了控制寄存器IICCON、控制状态寄存器IICSTAT和发送接收数据移位寄存器IICDS。由于我们只把s3c2440当做主设备来用,并且系统的IIC总线上只有这么一个主设备,因此用来设置从设备地址的地址寄存器IICADD,和用于仲裁总线的多主设备线路控制寄存器IICLC都无需配置。寄存器IICCON的第6位和低4位用于设置IIC的时钟频率,因为IIC的时钟线SCL都是由主设备提供的。s3c2440的IIC时钟源为PCLK,当系统的PCLK为50MHz,而从设备最高需要100kHz时,可以将IICCON的第6位置1,IICCON的低4位全为0即可。寄存器IICCON的第7位用于设置是否发出应答信号,第5位用于是否使能发送和接收中断,第4位用于中断的标志,当接收或发送数据后一定要对该位进行清零,以清除中断标志。寄存器IICSTAT的高2位用于设置是哪种操作模式,当向第5位写0或写1时,则表示结束IIC或开始IIC通讯,第4位用于是否使能接收/发送数据。 由于通讯是双方的事情,在了解了主设备的操作模式后,还要清楚从设备的运行机制,两者要达到完美地结合,才能实现彼此的通讯。在这里,从设备是EEPROM——AT24C02A,要想让s3c2440能够正确地对AT24C02A读写,就必须让s3c2440的时序完全按照AT24C02A的时序。AT24C02A的写操作有两种模式:字节写和页写。字节写是先接收带有写命令的设备地址信息,如果符合就应答,再接收设备内存地址信息,发出应答后,再接收要写入的数据,这样就完成了字节写过程。页写与字节写的区别就是,页写可以一次写多个数据,而字节写只能一次写一个数据。但由于AT24C02A的一页才8个字节,所以页写也最多写8个数据,而且只能在该页内写,不会发生一次页写同时写两页的情况。AT24C02A的读操作有三种模式:当前地址读、随机读和序列读。当前地址读是只能读取当前地址内的数据,它的时序是先接收带有读命令的设备地址信息,如果符合就应答,然后发送当前地址内的数据,在没有接收从主设备发来的应答信号的情况下终止该次操作。随机读的时序是,连续接收带有写命令的设备地址信息和设备内存地址信息,然后主设备重新开启IIC通信,AT24C02A再次接收到带有读命令的设备地址信息,在发出应答信号以后,发送该内存地址的数据,在没有接收到任何应答信号的情况下结束该次通信。当前地址读和随机读一次都只能读取一个数据,而序列读一次可以读取若干个数据,它的时序就是在当前地址读或随机读发出数据后,接收到了应答信号,那么AT24C02A会把下一个内存地址中的数据送出,除非AT24C02A接收不到任何应答信号,否则它会一直把下一个内存地址中的数据送出。序列读没有一页8个字节的限制。

在介绍完了s3c2440和AT24C02A的IIC通讯方式后,我们就可以写程序了。在这里,我们用UART来实现PC机对AT24C02A的读写。UART的通讯协议是,PC机先发送命令字节:0xC0表示要向AT24C02A写数据,0xC1表示要读取AT24C02A的数据,在命令字节后,紧跟着的是设备内存地址和写入或读取的字节数。如果是要写EEPROM数据,则在这三个字节后是要写入的数据内容。在UART通讯完毕后,s3c2440会根据命令的不同,写入或读取AT24C02A,如果是读取EEPROM,则s3c2440还会利用UART把读取到的数据上传到PC机。在这个程序中,我们只开启了UART的接收中断,而没有开启发送中断,即让s3c2440主动去完成发送任务。并且在与AT24C02A操作中,我们使用的是页写和序列读的模式,这样可以最大程度的完成一次读或写操作,而且我们所编写的页写和序列读子程度也同样可以实现字节写和随机读的模式。在这里我们限制一次读或写的数据量最多为8个字节。

以上转自:
作者:zhaocj
来源:CSDN
原文:https://blog.csdn.net/zhaocj/article/details/5477152
版权声明:本文为博主原创文章,转载请附上博文链接!

在发送模式:
1.往寄存器IICDS寄存器放入一个val值。
2.发完,产生中断,并且会把 SCL拉低。
3.在中断程序里,判断状态,然后往IICDS里面写入下一个数据,一旦写入下一个数据IIC继续操作,若再次发完,就会再次产生中断。
在接受模式:
1.我的程序发起传输,接受数据。
2.接收到数据之后,产生中断,SCL被拉低。
3.中断程序里,判断数据是否要继续接受等,如果还有继续接受的话,再次设置,设置好之后读IICDS寄存器,一但读出来IIC。
继续接受下一个数据,收到新数据之后,又会产生一个中断(就是这样循环操作)。

按照S3C2440的IIC传输流程图
在这里插入图片描述
在这里插入图片描述
和AT24Cxx的传送模式
在这里插入图片描述
在这里插入图片描述
ARM每传完一个数据就进入一次中断,所以,在中断服务程序中清中断。下次传输时还要清除IICCON的bit4的中断标志位。

/*
###  i2c_drive文件
###  包括,初始化i2c,读i2c,写i2c,i2c中断处理函数

*/

#include "i2c_drive.h"


#define AT24Cxx_ADDR 0x50

unsigned char ask = 1;			//应答标志位,0表示应答成功

static void delay(unsigned int time)
{
	for (; time>0; time--);
}

void i2c_init(void)
{
	/* GPE15--IICSDA, GPE14--IICSCL */
	GPECON &= ~((3<<28) | (3<<30));
	GPECON |= (2<<28) | (2<<30);
	
	/* 设置IICCON总线控制寄存器 */
	/* [7] : IIC-bus acknowledge enable bit, 1-enable in rx mode
	 * [6] : 时钟源, 0: IICCLK = fPCLK /16; 1: IICCLK = fPCLK /512
	 * [5] : 1-enable interrupt
	 * [4] : 读出为1时表示中断发生了, 写入0来清除并恢复I2C操作
	 * [3:0] : Tx clock = IICCLK/(IICCON[3:0]+1).
	 * Tx Clock = 100khz = 50Mhz/16/(IICCON[3:0]+1)
	 */
	IICCON = 0xe0;
	IICSTAT = 0x10;
	
	INTMSK &= ~(1<<27);
}


void i2c_interrupt(void)
{
	/* 清除中断标志位 */
	SRCPND &= ~(1<<27);
	INTPND &= ~(1<<27);
	
	ask = 0;
}

void write_at24cxx(unsigned char addr, unsigned char *buffer, int sizeofdate)
{
	int i;
	ask = 1;
	
	IICDS = AT24Cxx_ADDR;
	IICCON &= ~(1<<4);		//清中断
	IICSTAT = 0xf0;			//配置为主机发送模式,发出S信号,
							//IICDS寄存器中的数据自动发出,使能串行发送接收功能
	while (ask == 1)		//等待从设备应答
		delay(100);			//一旦应答,进入中断使得ASK=0,则跳出该死循环
	
	
	ask = 1;
	IICDS = addr;			//发送设备内存地址
	IICCON &= ~(1<<4);		//清中断
	while (ask == 1)		//等待从设备应答
		delay(100);			//一旦应答,进入中断使得ASK=0,则跳出该死循环
		
	
	for (i=0; i<sizeofdate; i++)
	{
		ask = 1;
		IICDS = *(buffer+i);
		IICCON &= ~(1<<4);		//清中断
		while (ask == 1)		//等待从设备应答
			delay(100);			//一旦应答,进入中断使得ASK=0,则跳出该死循环
	}
	
	IICSTAT = 0xd0;				//发送P
	
	IICCON = 0xe0;
	
	delay(100);
}


void read_at24cxx(unsigned char addr, unsigned char *buffer, int sizeofdate)
{
	int i;
	unsigned char temp;
	ask = 1;
	
	IICDS = AT24Cxx_ADDR;
	IICCON &= ~(1<<4);		//清中断
	IICSTAT = 0xf0;			//配置为主机发送模式,发出S信号,
							//IICDS寄存器中的数据自动发出,使能串行发送接收功能
	while (ask == 1)		//等待从设备应答
		delay(100);			//一旦应答,进入中断使得ASK=0,则跳出该死循环
	
	ask = 1;
	IICDS = addr;			//发送设备内存地址
	IICCON &= ~(1<<4);		//清中断
	while (ask == 1)		//等待从设备应答
		delay(100);			//一旦应答,进入中断使得ASK=0,则跳出该死循环
	
	ask = 1;
	IICDS = AT24Cxx_ADDR;	//发送设备内存地址
	IICCON &= ~(1<<4);		//清中断
	IICSTAT = 0xb0;			//主设备接收模式
	while (ask == 1)		//等待从设备应答
		delay(100);			//一旦应答,进入中断使得ASK=0,则跳出该死循环
		
	ask = 1;
	temp = IICDS;
	IICCON &= ~(1<<4);		//清中断
	while (ask == 1)		//等待从设备应答
		delay(100);			//一旦应答,进入中断使得ASK=0,则跳出该死循环

		
	for (i=0; i<sizeofdate; i++)
	{
		ask = 1;
		if (i == sizeofdate-1)
			IICCON &= ~(1<<7);		//ACK信号禁止
		*(buffer+i) = IICDS;
		IICCON &= ~(1<<4);			//清中断
		while (ask == 1)		//等待从设备应答
			delay(100);			//一旦应答,进入中断使得ASK=0,则跳出该死循环
		
	}
	
	IICSTAT = 0x90;				//发送P
	
	IICCON = 0xe0;
	
	delay(100);
}







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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值