1、概述
(1)e2prom简介--通过i2c控制
(2)如何对I2C控制器初始化
①允许中断,主要中断控制器的寄存器也要设置
②设置时钟
③设置引脚为串口输出,因为用到的是GPE这一组寄存器
(3)裸机初始化
在第二季的代码基础上修改:
(4)读写流程图
/* 写过程
1.设置处理器为主设备+发送模式
2.将从设备的地址写入到IICDS寄存器
3.写入0xF0写入IICSTAT 代表起始信号,写入0XF0之后,IICDS中的设备地址就开始传输了
4.等待ACK的产生
5.1接下来才开始传输数据,写入字节的地址到IICDS寄存器
5.2等待ACK的产生
6.将要传输的字节数据写入IICDS寄存器
8.等待ACk的产生
9.写入0xD0到IICSTAT,代表结束信号
10.清除中断
*/
void write_byte(unsigned char xchar, unsigned char daddr) { //1. 设置处理器为主设备+发送模式 IICSTAT |= (3<<6); //2. 将从设备的地址写入到IICDS寄存器 IICDS = SLAVE_WRITE_ADD; IICCON &= ~(1<<4); //3. 写入0xF0写入IICSTAT IICSTAT = 0xF0; //4. 等待ACK的产生 while ((IICCON & (1<<4)) == 0 ) delay(100); //5.1写入字节的地址到IICDS寄存器 IICDS = daddr; IICCON &= ~(1<<4); //5.2等待ACK的产生 while ((IICCON & (1<<4)) == 0 ) delay(100); //6. 将要传输的字节数据写入IICDS寄存器 IICDS = xchar; IICCON &= ~(1<<4); //8. 等待ACk的产生 while ((IICCON & (1<<4)) == 0 ) delay(100); //9. 写入0xD0到IICSTAT,代表结束信号 IICSTAT = 0xD0; //10. 清除中断 IICCON &= ~(1<<4); delay(100); }
//buff读出来数据放进去 daddr从哪个地址开始读 length长度 //随机读的过程是有一些区别的, void read_data(unsigned char *buf, unsigned char daddr, int length) { int j =0; unsigned char unusedata; //1. 设置为主设备发送模式 IICSTAT |= (3<<6); //写入从设备地址 IICDS = SLAVE_WRITE_ADD; IICCON &= ~(1<<4); //写入0xF0到IICSTAT IICSTAT = 0xF0; //等待ACK while ((IICCON & (1<<4)) == 0 ) delay(100); //写入eeprom内部地址 IICDS = daddr;//内部地址为什么是char类型的8位?最大256字节? IICCON &= ~(1<<4);//清除中断 //等待ACK while ((IICCON & (1<<4)) == 0 ) delay(100); //设置为主设备接收模式 IICSTAT &= ~(3<<6); IICSTAT |= (2<<6); //2.写入从设备地址到IICDS IICDS = SLAVE_READ_ADD; IICCON &= ~(1<<4);//清除中断 //3.写入0xB0到IICSTAT开始接收 IICSTAT = 0xb0; while ((IICCON & (1<<4)) == 0 )//等待中断 delay(100); /*写入设备内部地址*/ IICDS = daddr; IICCON &= ~(1 << 4); while((IICCON & (1 << 4)) == 0) { delay(100); } //丢掉收到的第1个字节 unusedata = IICDS; IICCON &= ~(1<<4); while ((IICCON & (1<<4)) == 0 ) delay(100); for(j=0;j<length;j++) { if(j == (length -1)) { IICCON &= ~(1<<7); } //5.1 从IICDS里取出数据 buf[j]=IICDS; //5.2 清除中断 IICCON &= ~(1<<4); //4.等待中断 while ((IICCON & (1<<4)) == 0 ) delay(100); } //写入0x90到IICSTAT IICSTAT = 0x90; // 清除中断 IICCON &= ~(1<<4); }
(5)测试代码
#define INTPND (*(volatile unsigned long*)0x4a000010) #define SRCPND (*(volatile unsigned long*)0x4a000000) #define INTMSK (*(volatile unsigned long*)0x4a000008) #define GPECON (*(volatile unsigned long*)0x56000040) #define GPEUP (*(volatile unsigned long*)0x56000048) #define IICCON (*(volatile unsigned char*)0x54000000) // IIC控制器的地址 #define IICSTAT (*(volatile unsigned char*)0x54000004) #define IICDS (*(volatile unsigned char*)0x5400000C) #define SLAVE_WRITE_ADD 0xa0 #define SLAVE_READ_ADD 0xa1 void delay(int i) { int j = 0; while (i--) { for (j=0;j<100;j++) { ; } } } void i2c_init() { //1.a 初始化中断,要初始化中断控制器中串口对应的中断位 INTPND |= (1<<27);//因为中断控制器中的27号中断是串口中断 SRCPND |= (1<<27); INTMSK &= ~(1<<27); IICCON |= (1<<5); //要找到IIC中断在中断系统对应的是哪一位 //1.b 设置scl时钟,时钟由第6位和0-3位一起决定。0:IICCLK=fPCLK/16 1:IICCLK=fPCLK/512 IICCON &= ~(1<<6);//确定IIC时钟用哪个,可以设置为1或者0 IICCON &= ~(0xf<<0);//先把0-3位清零 IICCON |= (0x5<<0);//再把0-3位设置成5 //2. 设置IICSTAT IICCON |= (1<<4); //3.设置引脚功能,由于SCL SDL引脚对应的是GPE14/15复用的引脚,所以需要设置 /*注意,在核心板图中IIC和GPE14引脚是复用的,因此我们需要设置引脚功能为IIC功能*/ GPECON |= (0x2<<28)|(0x2<<30); GPEUP |= (0x3<<14);//关掉上拉电阻,为什么要关掉? //4.允许产生ACK IICCON |= (1<<7); } void write_byte(unsigned char xchar, unsigned char daddr) { //1. 设置处理器为主设备+发送模式 IICSTAT |= (3<<6); //2. 将从设备的地址写入到IICDS寄存器 IICDS = SLAVE_WRITE_ADD; IICCON &= ~(1<<4);//清除中断 //3. 写入0xF0写入IICSTAT IICSTAT = 0xF0; //4. 等待ACK的产生,通过判断中断是否产生来确定 while ((IICCON & (1<<4)) == 0 ) delay(100); //5.1写入字节的地址到IICDS寄存器 IICDS = daddr; IICCON &= ~(1<<4); //5.2等待ACK的产生,继续等待中断到达 while ((IICCON & (1<<4)) == 0 ) delay(100); //6.将要传输的字节数据写入IICDS寄存器 IICDS = xchar; IICCON &= ~(1<<4); //7.清除中断 //8.等待ACk的产生 while ((IICCON & (1<<4)) == 0 ) delay(100); //9.写入0xD0到IICSTAT,代表结束信号 IICSTAT = 0xD0; //10.清除中断 IICCON &= ~(1<<4); delay(100); } //buff读出来数据放进去 daddr从哪个地址开始读 length长度 //随机读的过程是有一些区别的, void read_data(unsigned char *buf, unsigned char daddr, int length) { int j =0; unsigned char unusedata; //1. 设置为主设备发送模式 IICSTAT |= (3<<6); //写入从设备地址 IICDS = SLAVE_WRITE_ADD; IICCON &= ~(1<<4); //写入0xF0到IICSTAT IICSTAT = 0xF0; //等待ACK while ((IICCON & (1<<4)) == 0 ) delay(100); //写入eeprom内部地址 IICDS = daddr;//内部地址为什么是char类型的8位?最大256字节? IICCON &= ~(1<<4);//清除中断 //等待ACK while ((IICCON & (1<<4)) == 0 ) delay(100); //设置为主设备接收模式 IICSTAT &= ~(3<<6); IICSTAT |= (2<<6); //2.写入从设备地址到IICDS IICDS = SLAVE_READ_ADD; IICCON &= ~(1<<4);//清除中断 //3.写入0xB0到IICSTAT开始接收 IICSTAT = 0xb0; while ((IICCON & (1<<4)) == 0 )//等待中断 delay(100); /*写入设备内部地址*/ IICDS = daddr; IICCON &= ~(1 << 4); while((IICCON & (1 << 4)) == 0) { delay(100); } //丢掉收到的第1个字节 unusedata = IICDS; IICCON &= ~(1<<4); while ((IICCON & (1<<4)) == 0 ) delay(100); for(j=0;j<length;j++) { if(j == (length -1)) { IICCON &= ~(1<<7); } //5.1 从IICDS里取出数据 buf[j]=IICDS; //5.2 清除中断 IICCON &= ~(1<<4); //4.等待中断 while ((IICCON & (1<<4)) == 0 ) delay(100); } //写入0x90到IICSTAT IICSTAT = 0x90; // 清除中断 IICCON &= ~(1<<4); } void i2c_test() { int i=0; unsigned char sbuf[256]={0}; unsigned char dbuf[256]={0}; i2c_init(); for(i=0;i<256;i++) { sbuf[i] = i+1; dbuf[i] = 0; } printf("dbuf befor I2C read:\r\n"); for(i =0; i<256;i++) { if(i%8==0) printf("\r\n"); printf("%d\t",dbuf[i]); } for(i=0;i<256;i++) write_byte(sbuf[i],i); printf("i2c reading, plese wait!\n\r"); read_data(dbuf,0,256); printf("dbuf after I2C read:\r\n"); for(i =0; i<256;i++) { if(i%8==0) printf("\r\n"); printf("%d\t",dbuf[i]); } }