#include "24cxx.h" #include "bsp_i2c_gpio.h" #include "led.h" //初始化IIC void ee_Init(void) { bsp_InitI2C(); } //在AT24CXX指定地址读取一个数据 //ReadAddr :开始读数的地址 //返回值 :读取到的数据 u8 ee_ReadOneByte(u16 ReadAddr) { u8 temp = 0; IIC_Start(); if (EE_TYPE > AT24C16) { IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_WR);//发送写命令 IIC_Wait_Ack(); IIC_Send_Byte(ReadAddr / 256); //发送高地址 } else IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_WR + ((ReadAddr / 256) << 1)); //发送器件地址0xA0,写数据 IIC_Wait_Ack(); IIC_Send_Byte(ReadAddr % 256); //发送低地址 IIC_Wait_Ack(); IIC_Start(); if (1)IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_RD); //进入接收模式 else IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_RD + ((ReadAddr / 256) << 1)); //进入接收模式 IIC_Wait_Ack(); temp = IIC_Read_Byte(1); IIC_Stop();//产生一个停止条件 return temp; } //在AT24CXX指定地址写一个数据 //WriteAddr:写入数据的目的地址 //data :要写入的数据 void ee_WriteOneByte(u16 WriteAddr, u8 data) { IIC_Start(); if (EE_TYPE > AT24C16) { IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_WR); IIC_Wait_Ack(); IIC_Send_Byte(WriteAddr / 256); //发送高地址 } else IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_WR + ((WriteAddr / 256) << 1)); IIC_Wait_Ack(); IIC_Send_Byte(WriteAddr % 256); //发送低地址 IIC_Wait_Ack(); IIC_Send_Byte(data); IIC_Wait_Ack(); IIC_Stop();//产生一个停止条件 Delay_MS(6); } #if 1 //向EEPROM写入多个字节 uint8_t ee_WriteBytes(uint8_t *_pWriteBuf, uint16_t _usAddress, uint16_t _usSize) { uint16_t i, m; uint16_t addr; addr = _usAddress; for (i = 0; i < _usSize; i++) { //当第一次或者地址对齐到8就要重新发起起始信号和EEPROM地址 //为了解决8地址对齐问题 if (i == 0 || (addr % EE_PAGE_SIZE) == 0) { if (i != 0) { IIC_Stop(); Delay_MS(6); } //发送起始地址 IIC_Start(); //发送设备写地址 if (EE_TYPE > AT24C16) { IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_WR); if (IIC_Wait_Ack() != 0) { goto cmd_fail; } IIC_Send_Byte(addr / 256); //发送高地址 } else IIC_Send_Byte((EE_DEV_ADDR + ((addr / 256) << 1)) | EEPROM_I2C_WR); //等待从机应答 if (IIC_Wait_Ack() != 0) { goto cmd_fail; } //EEPROM应答后发送EEPROM的内部存储器地址 IIC_Send_Byte((uint8_t)addr); //等待从机应答 if (IIC_Wait_Ack() != 0) { goto cmd_fail; } } //发送数据 IIC_Send_Byte(_pWriteBuf[i]); //等待应答 if (IIC_Wait_Ack() != 0) { goto cmd_fail; } //写入地址加1 addr++; } IIC_Stop(); return 1; cmd_fail: IIC_Stop(); return 0; } uint8_t ee_ReadBytes(uint8_t *_pReadBuf, uint16_t _usAddress, uint16_t _usSize) { uint16_t i; //发送起始地址 IIC_Start(); //发送设备写地址 if (EE_TYPE > AT24C16) { IIC_Send_Byte(EE_DEV_ADDR); if (IIC_Wait_Ack() != 0) { goto cmd_fail; } IIC_Send_Byte(_usAddress / 256); //发送高地址 } else IIC_Send_Byte((EE_DEV_ADDR + ((_usAddress / 256) << 1)) | EEPROM_I2C_WR); if (IIC_Wait_Ack() != 0) { goto cmd_fail; } IIC_Send_Byte((uint8_t)_usAddress); if (IIC_Wait_Ack() != 0) { goto cmd_fail; } IIC_Start(); if (EE_TYPE > AT24C16) IIC_Send_Byte(EE_DEV_ADDR | EEPROM_I2C_RD); else IIC_Send_Byte((EE_DEV_ADDR + ((_usAddress / 256) << 1)) | EEPROM_I2C_RD); if (IIC_Wait_Ack() != 0) { goto cmd_fail; } for (i = 0; i < _usSize; i++) { /* 每读完1个字节后,需要发送Ack, 最后一个字节不需要Ack,发Nack */ _pReadBuf[i] = IIC_Read_Byte(i != _usSize - 1?1:0); } IIC_Stop(); return 1; cmd_fail: IIC_Stop(); return 0; } #endif #if 0 static void IIC1_Start(void); //发送起始信号 static void IIC1_Stop(void); //发送停止信号 static void IIC1_Write_Byte(u8 dat);//发送一个字节 static u8 IIC1_Read_Byte(unsigned char ack);//接收一个字节 static u8 IIC1_Wait_Ack(void);//等待ACK信号 static void IIC1_Ack(void);//发送ACK信号 static void IIC1_NAck(void);//不发送ACK信号 void I2C_delay(uint16_t n) { u8 i = 100 * n; //这里可以优化速度 ,经测试最低到5还能写入 while (i) { i--; } } //初始化IIC void AT24cxx_init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /* 打开GPIO时钟 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; //SDA,SCL GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); IIC_SDA1; IIC_SCL1; } //在AT24CXX指定地址读取一个数据 //ReadAddr :开始读数的地址 //返回值 :读取到的数据 u8 AT24cxx_ReadOneByte(u16 ReadAddr) { u8 temp = 0; IIC1_Start(); if (EE_TYPE > AT24C16) { IIC1_Write_Byte(0xa0);//发送写命令 IIC1_Wait_Ack(); IIC1_Write_Byte(ReadAddr / 256); //发送高地址 } else IIC1_Write_Byte(0xa0 + ((ReadAddr / 256) << 1)); //发送器件地址0xA0,写数据 IIC1_Wait_Ack(); IIC1_Write_Byte(ReadAddr % 256); //发送低地址 IIC1_Wait_Ack(); IIC1_Start(); if (EE_TYPE > AT24C16)IIC1_Write_Byte(0xa1); //进入接收模式 else IIC1_Write_Byte(0xa1 + ((ReadAddr / 256) << 1)); //进入接收模式 IIC1_Wait_Ack(); temp = IIC1_Read_Byte(1); IIC1_Stop();//产生一个停止条件 return temp; } //在AT24CXX指定地址写一个数据 //WriteAddr:写入数据的目的地址 //data :要写入的数据 void AT24cxx_WriteOneByte(u16 WriteAddr, u8 data) { IIC1_Start(); if (EE_TYPE > AT24C16) { IIC1_Write_Byte(0xa0); IIC1_Wait_Ack(); IIC1_Write_Byte(WriteAddr / 256); //发送高地址 } else IIC1_Write_Byte(0xa0 + ((WriteAddr / 256) << 1)); IIC1_Wait_Ack(); IIC1_Write_Byte(WriteAddr % 256); //发送低地址 IIC1_Wait_Ack(); IIC1_Write_Byte(data); IIC1_Wait_Ack(); IIC1_Stop();//产生一个停止条件 I2C_delay(2); } //在AT24CXX指定地址开始写入指定长度的数据 //该函数用于写入16位或32位的数据 //WriteAddr:开始写入的地址 //data :要写入的数据 //len :要写入数据的长度2,4 void AT24cxx_WriteLenByte(u16 WriteAddr, u32 data, u8 len) { u8 i; for (i = 0; i < len; i++) { AT24cxx_WriteOneByte(WriteAddr + i, (data >> (8 * i)) & 0xff); } } //在AT24CXX指定地址开始读出指定长度的数据 //该函数用于读出16bit或者32bit的数据. //ReadAddr :开始读出的地址 //返回值 :数据 //len :要读出数据的长度2,4 u32 AT24cxx_ReadLenByte(u16 ReadAddr, u8 len) { u8 i; u32 temp = 0; for (i = 0; i < len; i++) { temp <<= 8; temp += AT24cxx_ReadOneByte(ReadAddr + len - i - 1); } return temp; } //在AT24CXX指定地址开始写入指定长度的数据 //该函数用于写入指定的字节数 //WriteAddr:开始写入的地址 //buf :数据数组首地址 //len :要写入数据的个数 void AT24cxx_Write(u16 WriteAddr, u8 *buf, u16 len) { u16 i; for (i = 0; i < len; i++) { IWDG_Feed(); AT24cxx_WriteOneByte(WriteAddr, *buf); WriteAddr++; buf++; } } //在AT24CXX指定地址开始读出指定长度的数据 //该函数用于读出指定的字节数 //ReadAddr:开始读出数据的地址 //len :要写入数据的个数 //buf :数据数组首地址 void AT24cxx_Read(u16 ReadAddr, u8 *buf, u16 len) { while (len--) { IWDG_Feed(); *buf++ = AT24cxx_ReadOneByte(ReadAddr++); } } //检查AT24CXX是否正常 //这里用了24XX的第一个地址(0)来存储标志字. //返回1:检测失败 //返回0:检查成功 u8 AT24cxx_Check(void) { u8 temp1, temp2; AT24cxx_WriteOneByte(0x010, 0x55); temp1 = AT24cxx_ReadOneByte(0x010); //避免每次开机都写AT24CXX temp2 = temp1; if (temp2 == 0x55)return 0; else { AT24cxx_WriteOneByte(0x010, 0x55); temp1 = AT24cxx_ReadOneByte(0x010); temp2 = temp1; if (temp2 == 0x55)return 0; } return 1; } //产生IIC起始信号 static void IIC1_Start(void) { IIC_SDA1; IIC_SCL1; I2C_delay(4); IIC_SDA0; I2C_delay(4); IIC_SCL0; I2C_delay(4); } //产生IIC停止信号 static void IIC1_Stop(void) { IIC_SDA0; IIC_SCL1; I2C_delay(2); IIC_SDA1; I2C_delay(4); // IIC_SCL0; } //返回1,接收应答失败,返回0,接收应答成功 static u8 IIC1_Wait_Ack(void) { u8 i; SDA_IN(); IIC_SCL0; I2C_delay(2); IIC_SCL1; I2C_delay(2); while (Read_IIC_SDA()) { i++; if (i > 250) { IIC1_Stop(); return 1; } } IIC_SCL0; I2C_delay(2); return 0; } //产生ACK应答 static void IIC1_Ack(void) { IIC_SCL0; SDA_OUT(); IIC_SDA0; I2C_delay(2); IIC_SCL1; I2C_delay(2); IIC_SCL0; } //不产生ACK应答 static void IIC1_NAck(void) { IIC_SCL0; SDA_OUT(); IIC_SDA1; I2C_delay(2); IIC_SCL1; I2C_delay(2); IIC_SCL0; } //IIC发送一个字节 //返回从机有无应答 //0,有应答 //1,无应答 void IIC1_Write_Byte(u8 dat) { u8 t; SDA_OUT(); I2C_delay(2); for (t = 0; t < 8; t++) { IIC_SCL0; if (dat & 0x80) { IIC_SDA1; } else { IIC_SDA0; } I2C_delay(2); IIC_SCL1; dat <<= 1; I2C_delay(2); } IIC_SCL0; I2C_delay(2); } //读1个字节,ack=0时,发送ACK,ack=1,发送NACK u8 IIC1_Read_Byte(unsigned char ack) { u8 i, receive; SDA_IN();//SDA设为输入 IIC_SDA0; I2C_delay(2); for (i = 0; i < 8; i++) { IIC_SCL0; I2C_delay(2); IIC_SCL1; receive <<= 1; I2C_delay(2); if (Read_IIC_SDA())receive++; I2C_delay(2); } IIC_SDA1; I2C_delay(2); IIC_SCL0; I2C_delay(2); if (!ack) IIC1_Ack(); else IIC1_NAck(); return receive; } #endif