#include "includes.h" #include "AT24C128.h" #include "stdio.h" //#include "sys.h" #include "delay.h" //#include "sys.h" /* AT24C128C organized as 256 pages of 64-bytes each AT24C512C, organized as 512 pages of 128 bytes each 不同的的EEPROM对应的页大小不一样,注意修改 */ #define PAGE_SIZE 64 void I2C_init(void) { rcu_periph_clock_enable(RCU_GPIOB);//使能GPIOB时钟 rcu_periph_clock_enable(RCU_GPIOD); //解除写保护 gpio_init(IIC_WP_PORT,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,IIC_WP_PIN); //打开写保护 IIC_WRITE_PROTECT_ENABLE(); //关闭写保护 // IIC_WRITE_PROTECT_DISABLE(); //IIC时钟信号位 gpio_bit_set(IIC_SCL_PORT,IIC_SCL_PIN); gpio_init(IIC_SCL_PORT,GPIO_MODE_OUT_OD,GPIO_OSPEED_50MHZ,IIC_SCL_PIN); //IIC数据信号位 gpio_bit_set(IIC_SDA_PORT,IIC_SDA_PIN); gpio_init(IIC_SDA_PORT,GPIO_MODE_OUT_OD,GPIO_OSPEED_50MHZ,IIC_SDA_PIN); } u8 iic_cmd_delay=0; /***********************iic**************************/ void delay_nop(void) { unsigned int i; for(i=0;i<50;i++) __nop(); } //产生IIC起始信号 void IIC_Start(void) { /*while(iic_cmd_delay < E_DELAY) // 距上一个命令时间太短 { R_WDT_Restart(); }*/ // SDA_OUT();//sda线输出 // IIC_SDA_HIGH; // IIC_SCL_HIGH; // delay_us(4); // IIC_SDA_LOW;//START:when CLK is high,DATA change form high to low // delay_us(4); // IIC_SCL_LOW;//钳住I2C总线,准备发送或接收数据 SDA_OUT(); IIC_SDA(1);//IIC_SDA = 1; IIC_SCL(1);//IIC_SCL = 1; delay_us(4); IIC_SDA(0);//IIC_SDA = 0;//START:when CLK is high,DATA change form high to low delay_us(4); IIC_SCL(0);//IIC_SCL = 0; } //产生IIC停止信号 void IIC_Stop(void) { // SDA_OUT();//sda线输出 // IIC_SDA_LOW; // IIC_SCL_LOW; // delay_us(4); // IIC_SCL_HIGH; // IIC_SDA_HIGH;//发送I2C总线结束信号 // delay_us(4); // iic_cmd_delay=0; SDA_OUT(); IIC_SDA(0);//IIC_SDA = 0; IIC_SCL(0);//IIC_SCL = 0; delay_us(4); IIC_SCL(1);//IIC_SCL = 1; delay_us(4); IIC_SDA(1);//IIC_SDA = 1; delay_us(4); } //等待应答信号到来 //返回值: // 1,接收应答失败 // 0,接收应答成功 u8 IIC_Wait_Ack(void) { // u8 ucErrTime=0; // SDA_IN(); //SDA设置为输入 // IIC_SDA_HIGH;delay_us(1); // IIC_SCL_HIGH;delay_us(1); // while(READ_SDA) // { // ucErrTime++; // if(ucErrTime>250) // { // IIC_Stop(); // return 1; // } // } // IIC_SCL_LOW;//时钟输出0 // return 0; uint8_t ucErrTime=0; SDA_IN(); // SDA 配置成输入 IIC_SDA(1);//IIC_SDA=1; delay_us(1); IIC_SCL(1);//IIC_SCL=1; delay_us(1); while(READ_SDA) { ucErrTime++; if(ucErrTime>250) { IIC_Stop(); return 1; } } IIC_SCL(0);//IIC_SCL=0; return 0; } //产生ACK应答 void IIC_Ack(void) { // IIC_SCL_LOW; // SDA_OUT();//sda线输出 // IIC_SDA_LOW; // delay_us(4); // IIC_SCL_HIGH; // delay_us(2); // IIC_SCL_LOW; IIC_SCL(0);//IIC_SCL = 0; SDA_OUT(); IIC_SDA(0);//IIC_SDA = 0; delay_us(4); IIC_SCL(1);//IIC_SCL = 1; delay_us(2); IIC_SCL(0);//IIC_SCL = 0; } //不产生ACK应答 void IIC_NAck(void) { // IIC_SCL_LOW; // SDA_OUT();//sda线输出 // IIC_SDA_HIGH; // delay_us(4); // IIC_SCL_HIGH; // delay_us(2); // IIC_SCL_LOW; IIC_SCL(0);//IIC_SCL = 0; SDA_OUT(); IIC_SDA(1);//IIC_SDA = 1; delay_us(4); IIC_SCL(1);//IIC_SCL = 1; delay_us(2); IIC_SCL(0);//IIC_SCL = 0; } //IIC发送一个字节 //返回从机有无应答 //1,有应答 //0,无应答 void IIC_Send_Byte(u8 txd) { // u8 t; // IIC_SCL_LOW;//拉低时钟开始数据传输 // SDA_OUT(); // for(t=0;t<8;t++) // { //// IIC_SDA=(txd&0x80)>>7; //// SDA_OUT(); // if((txd&0x80)>>7) // IIC_SDA_HIGH; // else // IIC_SDA_LOW; // txd<<=1; // delay_us(4); //对TEA5767这三个延时都是必须的 // IIC_SCL_HIGH; // delay_us(2); // IIC_SCL_LOW; // delay_us(2); // } uint8_t t; IIC_SCL(0);//IIC_SCL=0;// 电平置低,开始传输数据 SDA_OUT(); for(t=0;t<8;t++) { // IIC_SDA=(txd&0x80)>>7; if((txd&0x80)>>7) IIC_SDA(1); else IIC_SDA(0); txd<<=1; delay_us(4); // IIC_SCL(1);//IIC_SCL=1; delay_us(2); IIC_SCL(0);//IIC_SCL=0; delay_us(2); } } //读1个字节,ack=1时,发送ACK,ack=0,发送nACK u8 IIC_Read_Byte(u8 ack) { // u8 i,receive=0; // SDA_IN();//SDA设置为输入 // for(i=0;i<8;i++ ) // { // IIC_SCL_LOW; // delay_us(4); // IIC_SCL_HIGH; // receive<<=1; // if(READ_SDA)receive++; // delay_us(1); // } // if (!ack) // IIC_NAck();//发送nACK // else // IIC_Ack(); //发送ACK // return receive; uint8_t i,receive=0; SDA_IN();//SDA设置为输入 for(i=0;i<8;i++ ) { IIC_SCL(0);//IIC_SCL=0; delay_us(4); IIC_SCL(1);//IIC_SCL=1; receive<<=1; if(READ_SDA)receive++; delay_us(1); } if(!ack) IIC_NAck();//发送nACK else IIC_Ack(); //发送ACK return receive; } /***********************以上为IIC驱动**************************/ /***********************iic**************************/ //在AT24CXX指定地址读出一个数据 //ReadAddr:开始读数的地址 //返回值 :读到的数据 u8 AT24CXX_ReadOneByte(u32 ReadAddr) { u8 temp; u8 addrH,addrL; addrH=ReadAddr>>8; addrL=ReadAddr&0xff; IIC_Start(); IIC_Send_Byte(0xa0); IIC_Wait_Ack(); IIC_Send_Byte(addrH); //发送高地址 IIC_Wait_Ack(); IIC_Send_Byte(addrL); //发送低地址 IIC_Wait_Ack(); IIC_Start(); IIC_Send_Byte(0xa1); //进入接收模式 IIC_Wait_Ack(); temp= IIC_Read_Byte(0); IIC_Stop();//产生一个停止条件 delay_us(4); return temp; } //在AT24CXX指定地址写入一个数据 //WriteAddr :写入数据的目的地址 //DataToWrite:要写入的数据 void AT24CXX_WriteOneByte(u32 WriteAddr,u8 DataToWrite) { u8 addrH,addrL; addrH=WriteAddr>>8; addrL=WriteAddr&0xff; IIC_Start(); IIC_Send_Byte(0xa0); IIC_Wait_Ack(); IIC_Send_Byte(addrH); //发送高地址 IIC_Wait_Ack(); IIC_Send_Byte(addrL); //发送低地址 IIC_Wait_Ack(); IIC_Send_Byte(DataToWrite); //发送字节 IIC_Wait_Ack(); IIC_Stop();//产生一个停止条件 delay_ms(10);//两次写操作,必须加间隔,否则写不进去 } //在AT24CXX里面的指定地址开始读出指定个数的数据 //ReadAddr :开始读出的地址 对24c02为0~255 //pBuffer :数据数组首地址 //NumToRead:要读出数据的个数 void AT24CXX_Read(u32 ReadAddr,u8 *pBuffer,u16 NumToRead) { // OS_ERR err; u8 addrH,addrL; u16 lentmp,lentow,lens; u8 tmp; if(NumToRead==0) return; // I2C_init(); // OSTimeDlyHMSM(0, 0, 0, 40, OS_OPT_TIME_DLY, &err); // delay_ms(40); delay_us(500); lentmp=NumToRead; while(lentmp) { tmp=ReadAddr%PAGE_SIZE; tmp=PAGE_SIZE-tmp; if(tmp>=lentmp)//当页剩余空间大于要写入的长度 { lentow=lentmp; } else { lentow=tmp;//写入长度只能是剩余空间长度 } lentmp=lentmp-lentow;//计算要在下一页写入的长度 lens=lentow; addrH=ReadAddr>>8; addrL=ReadAddr&0xff; IIC_Start(); IIC_Send_Byte(0xa0);//写 IIC_Wait_Ack(); IIC_Send_Byte(addrH); //发送高地址 IIC_Wait_Ack(); IIC_Send_Byte(addrL); //发送低地址 IIC_Wait_Ack(); delay_us(4); IIC_Start(); IIC_Send_Byte(0xa1); //读 //进入接收模式 IIC_Wait_Ack(); while(lentow) { *pBuffer=IIC_Read_Byte(1); pBuffer++; //ReadAddr++; lentow--; } IIC_Read_Byte(0); IIC_Stop();//产生一个停止条件 delay_us(4); //printf("at24 read %d %d\r\n", ReadAddr, lens); ReadAddr=ReadAddr+lens;//下一页的地址 } //打开写保护 // IIC_WRITE_PROTECT_ENABLE(); } //在AT24CXX里面的指定地址开始写入指定个数的数据 //WriteAddr :开始写入的地址 对24c02为0~255 //pBuffer :数据数组首地址 //NumToWrite:要写入数据的个数 // 每128bytes为一个page,写操作不能跨页 void AT24CXX_Write(u32 WriteAddr,u8 *pBuffer,u16 NumToWrite) { // OS_ERR err; u8 addrH,addrL; u16 lentmp,lentow,lens; u8 tmp; if(NumToWrite==0) return; // I2C_init(); //关闭写保护 IIC_WRITE_PROTECT_DISABLE(); // OSTimeDlyHMSM(0, 0, 0, 10, OS_OPT_TIME_DLY, &err); // delay_ms(10); delay_us(500); lentmp=NumToWrite; while(lentmp) { tmp=WriteAddr%PAGE_SIZE; tmp=PAGE_SIZE-tmp; if(tmp>=lentmp)//当页剩余空间大于要写入的长度 { lentow=lentmp; } else { lentow=tmp;//写入长度只能是剩余空间长度 } lentmp=lentmp-lentow;//计算要在下一页写入的长度 lens=lentow; addrH=WriteAddr>>8; addrL=WriteAddr&0xff; IIC_Start(); IIC_Send_Byte(0xa0); IIC_Wait_Ack(); IIC_Send_Byte(addrH); //发送高地址 IIC_Wait_Ack(); IIC_Send_Byte(addrL); //发送低地址 IIC_Wait_Ack(); while(lentow--) { IIC_Send_Byte(*pBuffer); IIC_Wait_Ack(); pBuffer++; } IIC_Stop();//产生一个停止条件 delay_ms(10); // OSTimeDlyHMSM(0, 0, 0, 10, OS_OPT_TIME_DLY, &err); //printf("at24 write %d %d %d, %d\r\n", WriteAddr, lens, addrH, addrL); WriteAddr=WriteAddr+lens;//下一页的地址 } // delay_ms(10);//两次写操作,必须加间隔,否则写不进去 // OSTimeDlyHMSM(0, 0, 0, 10, OS_OPT_TIME_DLY, &err); //打开写保护 IIC_WRITE_PROTECT_ENABLE(); } void AT24CXX_clr(u32 WriteAddr,u32 NumToWrite) { u8 addrH,addrL; u16 lentmp,lentow,lens; u8 tmp; //关闭写保护 IIC_WRITE_PROTECT_DISABLE(); lentmp=NumToWrite; while(lentmp) { tmp=WriteAddr%PAGE_SIZE; tmp=PAGE_SIZE-tmp; if(tmp>=lentmp) { lentow=lentmp; } else { lentow=tmp; } lentmp=lentmp-lentow; lens=lentow; addrH=WriteAddr>>8; addrL=WriteAddr&0xff; IIC_Start(); IIC_Send_Byte(0xa0); IIC_Wait_Ack(); IIC_Send_Byte(addrH); //发送高地址 IIC_Wait_Ack(); IIC_Send_Byte(addrL); //发送低地址 IIC_Wait_Ack(); while(lentow--) { IIC_Send_Byte(0xff); IIC_Wait_Ack(); } IIC_Stop();//产生一个停止条件 delay_ms(10); WriteAddr=WriteAddr+lens; } //打开写保护 IIC_WRITE_PROTECT_ENABLE(); delay_ms(10); } //----------------------EEPROM---------------------------// //--------------------------------------------------------EEPROM DATA /*********************************************END OF FILE**********************/ #define I2C_DATA_LEN 256 u8 I2c_Buf_Write[I2C_DATA_LEN], I2c_Buf_Read[I2C_DATA_LEN]; /** * @brief I2C(AT24C02)读写测试 * @param 无 * @retval 正常返回 1 ,不正常返回 0 */ uint8_t I2C_Test(void) { u16 i; I2C_init(); EEPROM_INFO("\r\nI2C(AT24C128)字节读写测试\r\n"); memset(I2c_Buf_Write, 0, I2C_DATA_LEN); memset(I2c_Buf_Read, 0, I2C_DATA_LEN); // for ( i=0; i< I2C_DATA_LEN; i++ ) //填充缓冲 // { // I2c_Buf_Write[i] = i+9; // AT24CXX_WriteOneByte(i, i); // I2c_Buf_Read[i] = AT24CXX_ReadOneByte(i); // } // data_dump("I2C Write", I2c_Buf_Write, I2C_DATA_LEN); // data_dump("I2C Read", I2c_Buf_Read, I2C_DATA_LEN); EEPROM_INFO("\r\nI2C(AT24C128)连续地址读写测试\r\n"); memset(I2c_Buf_Write, 0, I2C_DATA_LEN); memset(I2c_Buf_Read, 0, I2C_DATA_LEN); for ( i=0; i< I2C_DATA_LEN; i++ ) //填充缓冲 { I2c_Buf_Write[i] = i+1; } AT24CXX_clr(512, I2C_DATA_LEN); delay_ms(10); AT24CXX_Read(512, I2c_Buf_Read, I2C_DATA_LEN); data_dump("I2C Read", I2c_Buf_Read, I2C_DATA_LEN); delay_ms(10); AT24CXX_Write(512, I2c_Buf_Write, I2C_DATA_LEN); delay_ms(10); AT24CXX_Read(512, I2c_Buf_Read, I2C_DATA_LEN); data_dump("I2C Write", I2c_Buf_Write, I2C_DATA_LEN); data_dump("I2C Read", I2c_Buf_Read, I2C_DATA_LEN); EEPROM_INFO("\r\nI2C(AT24C128)读写测试成功\r\n"); return 1; }