1 #include "delay.h" 2 3 #define IIC_SCL PBout(8) //SCL(输出) 4 #define IIC_SDA PBout(9) //SDA(输出) 5 #define IIC_SDA_R PBin(9) //SDA(输入) 6 7 void AT24C0X_IIC_Init(void) 8 { 9 GPIO_InitTypeDef GPIO_InitStructure; 10 11 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能gpiob时钟 12 //GPIOB8,B9初始化 13 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; 14 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //普通输出模式 15 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出,增加输出电流能力 16 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz,高速响应 17 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //使能上拉电阻 18 GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化gpio 19 PBout(8)=1; // iic_scl,时序图初始为高电平 20 PBout(9)=1; // iic_sda,时序图初始为高电平 21 } 22 void sda_pin_mode(GPIOMode_TypeDef mode) // GPIO_Mode_IN,GPIO_Mode_OUT 23 { 24 GPIO_InitTypeDef GPIO_InitStructure; 25 26 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能gpiob时钟 27 //GPIOB8,B9初始化 28 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 29 GPIO_InitStructure.GPIO_Mode = mode; //普通输入或出模式 30 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出,增加输出电流能力 31 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz,高速响应 32 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //使能上拉电阻 33 GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化gpio 34 }
1 void iic_start(void) 2 { 3 //保证sda引脚为输出模式 4 sda_pin_mode(GPIO_Mode_OUT); 5 6 IIC_SCL = 1; // 1.初始电平都为高电平 7 IIC_SDA = 1; 8 delay_us(5); // 延时5us,保证电平稳定有效 9 10 IIC_SDA = 0; // 2.scl为高期间,sda:1->0 11 delay_us(5); // 产生start信号 12 13 IIC_SCL = 0; // 3.钳住iic总线,准备开始发送数据 14 delay_us(5); // 15 }
void iic_stop(void) { //保证sda引脚为输出模式 sda_pin_mode(GPIO_Mode_OUT); IIC_SCL = 1; // 1.初始电平为高电平 IIC_SDA = 0; // 初始电平为低电平 delay_us(5); IIC_SDA = 1; // 2.scl为高期间,sda:0->1 delay_us(5); }
1 uint8_t iic_wait_ack(void) 2 { 3 uint8_t ack = 0; 4 5 //保证sda引脚为输出模式 6 sda_pin_mode(GPIO_Mode_IN); 7 IIC_SCL = 1; // 在scl=1期间,读取sda 8 delay_us(5); 9 10 if(IIC_SDA_R) 11 { 12 ack = 1; // 若sda_r为1,则无应答 13 } 14 else 15 { 16 ack = 0; // 若sda_r为0,则有应答 17 } 18 return ack; 19 }
void iic_ack(void) { //保证sda引脚为输出模式 sda_pin_mode(GPIO_Mode_OUT); IIC_SCL = 0; // scl初始电平 IIC_SDA = 0; // sda初始电平 delay_us(5); IIC_SCL = 1; // scl=1期间, delay_us(5); IIC_SDA = 0; // sda=0,主机应答 }
1 void iic_no_ack(void) 2 { 3 //保证sda引脚为输出模式 4 sda_pin_mode(GPIO_Mode_OUT); 5 6 IIC_SCL = 0; // scl初始电平 7 IIC_SDA = 1; // sda初始电平 8 delay_us(5); 9 10 IIC_SCL = 1; // scl=1期间, 11 delay_us(5); 12 13 IIC_SDA = 1; // sda=1,主机不应答 14 }
1 void iic_write_byte(uint8_t byte) 2 { 3 int32_t i; 4 //保证sda引脚为输出模式 5 sda_pin_mode(GPIO_Mode_OUT); 6 7 IIC_SCL = 0; 8 delay_us(5); 9 10 for (i=7; i<0; i--) 11 { 12 if (byte & (1<<i)) // 只有scl=1时才能写数据,bit流由高到低 13 { 14 IIC_SDA = 1; 15 } 16 else 17 { 18 IIC_SDA = 0; 19 } 20 delay_us(5); 21 22 IIC_SCL = 1; // 23 delay_us(5); 24 25 IIC_SCL = 0; // 为下一次写数据做准备 26 delay_us(5); 27 } 28 }
1 uint8_t iic_read_byte(void) 2 { 3 uint8_t byte; 4 int32_t i; 5 6 //保证sda引脚为输出模式 7 sda_pin_mode(GPIO_Mode_IN); 8 9 IIC_SCL = 0; // 初始化为低电平 10 delay_us(5); 11 12 for (i=7; i>0; i--) 13 { 14 IIC_SCL = 1; // 只有在scl=1时,才可以读数据 15 delay_us(5); 16 17 if (IIC_SDA_R) 18 { 19 byte |= 1<<i; 20 } 21 else 22 { 23 byte |= 0<<i; 24 } 25 IIC_SCL = 0; // 为都下一个字节的数据做准备 26 delay_us(5); 27 } 28 return byte; 29 }
1 uint32_t AT24CXX_Byte_Write(uint8_t addr,uint8_t byte) 2 { 3 uint8_t ack; 4 5 // 1.发送开始信号 6 iic_start(); 7 8 // 2.写设备地址,选择iic总线的设备,bit流由高到低(从最高位开始写) 9 iic_write_byte(0xA0); 10 11 // 3.等待从机应答(从机位EEPROM设备,主机位mcu设备) 12 ack = iic_wait_ack(); 13 if (1 == ack) 14 { 15 printf("dev addr is error!\r\n"); 16 return -1; 17 } 18 19 // 4.写入数据地址(数据在eeprom中要存放的位置) 20 iic_write_byte(addr); 21 22 // 5.等待从机应答 23 ack = iic_wait_ack(); 24 if (1 == ack) 25 { 26 printf("data addr is error!\r\n"); 27 return -2; 28 } 29 30 // 6.写入要存入EEPROM中的数据 31 iic_write_byte(byte); 32 33 // 7.等到从机应答 34 ack = iic_wait_ack(); 35 if (1 == ack) 36 { 37 printf("data addr is error!\r\n"); 38 return -3; 39 } 40 41 // 8.发送终止信号 42 iic_stop(); 43 44 return 0; 45 }
1 int32_t AT24C0X_Page_Write(uint8_t addr,uint8_t *pbuf,uint8_t len) 2 { 3 uint8_t ack; 4 uint8_t i; 5 6 // 1.发送起始信号 7 iic_start(); 8 9 // 2.发送设备地址,iic总线寻址 10 iic_write_byte(0xA0); // 写设备地址(0xA0) 11 12 // 3.等待应答信号 13 ack = iic_wait_ack(); 14 if (ack) 15 { 16 printf("dev addr is err!\r\n"); 17 return -1; 18 } 19 20 // 4.发送要写入的数据地址 21 iic_write_byte(addr); 22 23 // 5.等待应答信号 24 ack = iic_wait_ack(); 25 if (ack) 26 { 27 printf("data addr is err!\r\n"); 28 return -2; 29 } 30 31 // 6.发送要写入的数据(多字节) 32 for (i=0; i<len; i++) 33 { 34 // 发送要写入的数据 35 iic_write_byte(pbuf[i]); 36 // 等待应答 37 ack = iic_wait_ack(); 38 if (ack) 39 { 40 printf("data is err!\r\n"); 41 return -3; 42 } 43 } 44 // 7.发送停止信号 45 iic_stop(); 46 }
1 int32_t AT24CXX_Write_Data(uint8_t Addr,uint8_t *pBuf,uint16_t Len) 2 { 3 while(Len--) 4 { 5 AT24CXX_Byte_Write(Addr,pBuf); 6 Addr++; // 目的地址(eeprom中存储数据的地址+1) 7 pBuf++; // 源地址(源数据的地址) 8 } 9 return 0; 10 }
1 uint8_t AT24CXX_Read_Byte_Random(uint8_t addr) 2 { 3 uint8_t byte; 4 uint8_t ack; 5 6 // 1.发送开始信号 7 iic_start(); 8 9 // 2.写入要读的设备地址(硬件设备id),为写方向 10 iic_write_byte(0xA0); 11 12 // 3.等待从机应答信号 13 ack = iic_wait_ack(); 14 if (ack) 15 { 16 printf("When Master read randomly,what write slave device address is error! r\n"); 17 return -1; 18 } 19 20 // 4.写入从机设备(eeprom)中,要读的位置 21 iic_write_byte(addr); 22 23 // 5.等待从机应答信号 24 ack = iic_wait_ack(); 25 if (ack) 26 { 27 printf("When Master read randomly,what write data address in slave is error! r\n"); 28 return -2; 29 } 30 31 // 6.发送开始信号 32 iic_start(); 33 34 // 7.写入要读的设备地址(硬件设备id),为读方向 35 iic_write_byte(0xA1); 36 37 // 8.等待从机应答信号 38 ack = iic_wait_ack(); 39 if (ack) 40 { 41 printf("When Master read randomly,what write data address in slave is error! r\n"); 42 return -2; 43 } 44 45 // 9.读取从机数据(eeprom) 46 byte = iic_read_byte(); 47 48 // 10.主机不应答 49 iic_no_ack(); 50 51 // 11.发送停止信号 52 iic_stop(); 53 54 return byte; 55 }
1 /** 2 * @brief 在AT24XX里面的指定地址开始读出长度为Len的数据,该函数用于读出 3 * 读出16bit或者32bit的数据 4 * @param ReadAddr:开始读出的地址 5 * @param Len: 读出数据的长度2,4 6 * 7 * @retval 数据 8 */ 9 uint32_t AT24CXX_ReadLenByte(uint16_t ReadAddr,uint8_t Len) 10 { 11 uint8_t t; 12 uint32_t temp=0; 13 for(t=0;t<Len;t++) 14 { 15 temp<<=8; 16 temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1); // 17 } 18 return temp; 19 }
1 /** 2 * @brief 在AT24XX里面的指定地址开始读出指定长度为Len的数据 3 * @param ReadAddr:开始读出的地址,对24c02为0-255 4 * @param pData: 输出数据数组首地址 5 * @param Len: 要读数据的个数 6 7 */ 8 void AT24CXX_Read_Data(uint16_t addr,uint8_t *pData, uint16_t DataLen) 9 { 10 while (DataLen--) 11 { 12 *pData++ = AT24CXX_Read_Byte_Random(addr++); 13 } 14 }
原文:https://www.cnblogs.com/sbtblogs/p/13619303.html