IIC专题(三)-smart210裸机透过IIC操作板载AT24LC04

前两篇已经讲了如何在Linux下操作AT24C04,本篇来实现裸奔的代码吧

首先因为要操作AT24C04当然就得先了解一下这个EEPROM及相关的知识

我们在第一篇中已经介绍了AT24LC04他的设备地址是0xA0如果是读就是0xA1

我们都知道裸机操作设备至少需要两个部分,一个是初始化,一个是实际的操作(读/写)

初始化都需要干些啥呢?

1.初始化GPIO引脚

2.初始化硬件

先说说初始化GPIO引脚,从原理图上



可以知道使用了这两个脚,对应到GPIO就是



GPD1_0 跟GPD1_1 然后找到210的手册找到GPD1的0跟1脚,也就是需要设定为 0x22


然后从AT24LC04的时序上发现



空闲的时候需要为高电平,但是原理图上发现他已经接了上拉电阻,所以空闲时我们只要让GPIO呈现高阻就可以,所以要设定GPIO的PUD寄存器


这样GPIO就設定好了

然后再来是IIC的初始化,因为我们用210提供的II控制器来驱动,所以看下需要设定什么,查找210的手册I2C的部份



1.是说如果我们需要把设备做为从设备需要设定I2CADD显然我们是主设备不管他

2.设定I2CCON寄存器,主要要做启用中断、设定时钟参数


启用中断,主要是操作两个位一个是清空中断标志(bit4)、一个是启用中断(bit5)

设定时钟,因为之前时钟初始化我将我的PCLK_DSYS设置为667M,(bit0-3)跟(bit6)两个合并可以知道时钟信号的公式为 fPCLK 667M / (16 or 512(bit6) * (1+n(bit0-3))

并且最终的时钟要保持在1MHz左右,所以我们用 512分频系数0(实际我测试过16分频bit6跟15系数bit0-3发现还是太快),然后发现bit7自动应答我们也开启他


3.设定I2CSTAT启用串行输出


这就比较简单了所以初始化代码如下

void i2c_init(void)
{
	///*****************
	//1.设置引脚-I2C复用
	GPD1CON &= ~(0xFF <<0);
	GPD1CON |= (0x22 <<0);
	//设定引脚上拉,但是原理图上已经加了上拉电阻,所以直接悬空就可以了
	GPD1PUD &= ~(0xF);
	
	//2.设置I2CCON寄存器
	//2.1使能中断

	//清除中断标示
	I2CCON0 &= ~(1<<4);
	//启用中断
	I2CCON0 |= (1<<5);
	//2.2设定SCL时钟-PCLK=96M/(16 * (11+1)) 大约在500KHz
	//I2CCON0 &= ~(1<<6);
	//I2CCON0 |= (15<<0);
	
	//改用512分频 96M/512 = 187.5KHz 就正常了
	I2CCON0 |= (1<<6);        //设置成512分频
	//2.3允许返回ack
	I2CCON0 |= (1<<7);
	
	//3.设定I2CSTAT寄存器使能串行输出
	//3.1设定工作模式为写
	I2CSTAT0 |= (1<<4);
	//************************************/

}
这样初始化就设定完成再来考虑读写操作

找到210的I2C控制器的流程,顺带需要说的是这里是不涉及设备的部份,所以我们还要结合AT24LC04的手册的写流程一起看

也就是说发送数据部分得先发送数据地址,再发送写入的数据

当数据全部发送完成才走stop = y 这边的流程,因此写成代码就是

void i2c_24c04_write_byte(unsigned char dataAddr,unsigned char data)
{
	
	///************************
	//设置为发送模式
	I2CSTAT0 |= (0x3<<6);
	//写入从设备地址-I2CDS
	I2CDS0 = I2C24C04_WRITE_ADDR;
	I2CCON0 &= ~(1<<4);
	//写0xF0 到I2CSTAT
	I2CSTAT0 = 0xF0;
	//等待ACK
	while((I2CCON0 & 0x10) ==0)
		delay_xz(100);
	//发送数据地址到I2CDS
	I2CDS0 = dataAddr;
	I2CCON0 &= ~(1<<4);
	//等待ACK
	while((I2CCON0 & 0x10) ==0)
		delay_xz(100);
	//写入数据
	I2CDS0 = data;
	I2CCON0 &= ~(1<<4);
	//等待ACK
	while((I2CCON0 & 0x10) ==0)
		delay_xz(100);
	//写入0xD0到I2CSTAT
	I2CSTAT0 = 0xD0;
	//清除PEND
	I2CCON0 &= ~(1<<4);
	//等待ACK
	delay_xz(100);
	//********************/

	
}

再来就是读,看下24C04的随机读部分


需要分成两个部分第一个部分也是写,把数据地址写入之后,再做读取,

因此最后代码就成为了

//随机读
void i2c_24c04_read(unsigned char *buf,unsigned char dataAddr,unsigned int length)
{
	
	
	//------------以下为第一阶段的写入数据地址-------------
	int i =0;
	unsigned char unusedData;
	//设置为主设备发送模式
	I2CSTAT0 |= (0x3<<6);
	//写入从设备地址-I2CDS
	I2CDS0 = I2C24C04_WRITE_ADDR;
	I2CCON0 &= ~(1<<4);
	//写0xF0 到I2CSTAT
	I2CSTAT0 = 0xF0;
	//等待ACK
	while((I2CCON0 & 0x10) ==0)
		delay_xz(100);
	//发送数据地址到I2CDS
	I2CDS0 = dataAddr;
	I2CCON0 &= ~(1<<4);
	//等待ACK
	while((I2CCON0 & 0x10) ==0)
		delay_xz(100);
	//---------写过程到此为止-------------------
	//---------接下来是第二阶段的读-------------
	//设定为主机读模式
	I2CSTAT0 &= ~(0x3<<6);
	I2CSTAT0 |= (0x2<<6);
	//写入从设备地址-I2CDS
	I2CDS0 = I2C24C04_READ_ADDR;
	I2CCON0 &= ~(1<<4);
	//写0xB0 到 I2CSTAT
	I2CSTAT0 = 0xB0;
	//这边设备有个问题第一个字节的数据是无效的,因此需要丢弃

	//等待中断--循环读取
	while((I2CCON0 & 0x10) ==0)
		delay_xz(100);
	//定义了一个无效变量接收无用数据
	unusedData = I2CDS0;
	//清除pend --循环结束
	I2CCON0 &= ~(1<<4);	
	
	for (i=0;i<length;i++)
	{
		//读取完数据所有需要的数据时,需要回覆NOACK
		if (i==(length-1))
		{
			I2CCON0 &= ~(1<<7);
		}
		
		//等待中断--循环读取
		while((I2CCON0 & 0x10) ==0)
			delay_xz(100);
		//从I2CDS读取数据
		buf[i] = I2CDS0;
		//清除pend --循环结束
		I2CCON0 &= ~(1<<4);
	}
	
	
	//等待中断--循环读取
	while((I2CCON0 & 0x10) ==0)
		delay_xz(100);
	
	//写入0x90到I2CSTAT
	I2CSTAT0 = 0x90;
	//清除中断
	I2CCON0 &= ~(1<<4);
	
	//为了后续操作应该要恢复ACK
	I2CCON0 |= (1<<7);
	//*************************/
}

最后完成实现代码

/***********************************************
* 档名:i2c.c
* 作者:yang@wapoop.com
* 日期:2016/10/13
* 描述:i2c 驱动程序读写板载AT24C04
************************************************/
//GPIO寄存器--GPD1共用
#define GPD1CON  		(*((volatile unsigned int *)0xE02000C0))
#define GPD1PUD  		(*((volatile unsigned int *)0xE02000C8))


//I2C相关寄存器
#define I2CCON0  		(*((volatile unsigned char *)0xE1800000))
#define I2CSTAT0  		(*((volatile unsigned char *)0xE1800004))
#define I2CDS0  		(*((volatile unsigned char *)0xE180000C))
//仅有在开发板做为Slave情况下需要设定I2CADD寄存器
#define I2CADD0  		(*((volatile unsigned char *)0xE1800008))
#define I2CLC0  		(*((volatile unsigned char *)0xE1800010))

#define I2C24C04_READ_ADDR 0xA1
#define I2C24C04_WRITE_ADDR 0xA0

static void delay_xz(int i)
{
   int j = 0;
   while (i--)	
   {
       for (j=0;j<100;j++)
       {	
           ;
       }  
   }	
}


void i2c_24c04_write_byte(unsigned char dataAddr,unsigned char data)
{
	
	///************************
	//设置为发送模式
	I2CSTAT0 |= (0x3<<6);
	//写入从设备地址-I2CDS
	I2CDS0 = I2C24C04_WRITE_ADDR;
	I2CCON0 &= ~(1<<4);
	//写0xF0 到I2CSTAT
	I2CSTAT0 = 0xF0;
	//等待ACK
	while((I2CCON0 & 0x10) ==0)
		delay_xz(100);
	//发送数据地址到I2CDS
	I2CDS0 = dataAddr;
	I2CCON0 &= ~(1<<4);
	//等待ACK
	while((I2CCON0 & 0x10) ==0)
		delay_xz(100);
	//写入数据
	I2CDS0 = data;
	I2CCON0 &= ~(1<<4);
	//等待ACK
	while((I2CCON0 & 0x10) ==0)
		delay_xz(100);
	//写入0xD0到I2CSTAT
	I2CSTAT0 = 0xD0;
	//清除PEND
	I2CCON0 &= ~(1<<4);
	//等待ACK
	delay_xz(100);
	//********************/

	
}
//随机读
void i2c_24c04_read(unsigned char *buf,unsigned char dataAddr,unsigned int length)
{
	
	
	//------------以下为第一阶段的写入数据地址-------------
	int i =0;
	unsigned char unusedData;
	//设置为主设备发送模式
	I2CSTAT0 |= (0x3<<6);
	//写入从设备地址-I2CDS
	I2CDS0 = I2C24C04_WRITE_ADDR;
	I2CCON0 &= ~(1<<4);
	//写0xF0 到I2CSTAT
	I2CSTAT0 = 0xF0;
	//等待ACK
	while((I2CCON0 & 0x10) ==0)
		delay_xz(100);
	//发送数据地址到I2CDS
	I2CDS0 = dataAddr;
	I2CCON0 &= ~(1<<4);
	//等待ACK
	while((I2CCON0 & 0x10) ==0)
		delay_xz(100);
	//---------写过程到此为止-------------------
	//---------接下来是第二阶段的读-------------
	//设定为主机读模式
	I2CSTAT0 &= ~(0x3<<6);
	I2CSTAT0 |= (0x2<<6);
	//写入从设备地址-I2CDS
	I2CDS0 = I2C24C04_READ_ADDR;
	I2CCON0 &= ~(1<<4);
	//写0xB0 到 I2CSTAT
	I2CSTAT0 = 0xB0;
	//这边设备有个问题第一个字节的数据是无效的,因此需要丢弃

	//等待中断--循环读取
	while((I2CCON0 & 0x10) ==0)
		delay_xz(100);
	//定义了一个无效变量接收无用数据
	unusedData = I2CDS0;
	//清除pend --循环结束
	I2CCON0 &= ~(1<<4);	
	
	for (i=0;i
   
   
    
    <<0);
	GPD1CON |= (0x22 <<0);
	//设定引脚上拉,但是原理图上已经加了上拉电阻,所以直接悬空就可以了
	GPD1PUD &= ~(0xF);
	
	//2.设置I2CCON寄存器
	//2.1使能中断

	//清除中断标示
	I2CCON0 &= ~(1<<4);
	//启用中断
	I2CCON0 |= (1<<5);
	//2.2设定SCL时钟-PCLK=96M/(16 * (11+1)) 大约在500KHz
	//I2CCON0 &= ~(1<<6);
	//I2CCON0 |= (15<<0);
	
	//改用512分频 96M/512 = 187.5KHz 就正常了
	I2CCON0 |= (1<<6);        //设置成512分频
	//2.3允许返回ack
	I2CCON0 |= (1<<7);
	
	//3.设定I2CSTAT寄存器使能串行输出
	//3.1设定工作模式为写
	I2CSTAT0 |= (1<<4);
	//************************************/

}

void i2c_test()
{
    int i=0;	

    unsigned char sbuf[10]={0x41,0x32,0x43,0x34,0x45,0x36,0x47,0x38,0x49,0x3A};
    unsigned char dbuf[256]={0};
    
    i2c_init();
    ///********因为读写有次数限制,启动暂且就把写注释但是确实好使-开始******************
    printf("start write! \r\n");
    for (i=0;i<10;i++)
	{
		i2c_24c04_write_byte(0x20 + i,sbuf[i]);
    }  
	//********因为读写有次数限制,启动暂且就把写注释但是确实好使-结束******************/  
	delay_xz(1000);  
    printf("i2c reading, plese wait!\n\r");
    
    i2c_24c04_read(dbuf,0,256);
    
    printf("dbuf after I2C read:\r\n");
    
    for(i =0; i<256;i++)
    {
       if(i%16==0)
           printf("\r\n");
           
       printf("%0.2x\t",dbuf[i]);	
    }
	
}

   
   




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值