1. 硬件連接
1.1 從設備端引腳連接
1.2 mcu端引腳連接
2. iic初始化
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 }
3.時序圖
3.1 開始和終止的定義(Start and Stop Definition)
3.1.1 開始信號
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 }
3.1.2 終止信號(停止信號)
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); }
3.2 輸出應答(Data Validity)
3.2.1 從機應答(主機等待從機應答)
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 }
3.2.2 主機應答
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,主機應答 }
3.2.3 主機不應答
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 }
3.3 讀寫時序
3.3.1 數據有效性(Data Validity)
3.3.2 設備地址(Device Address)
3.3.3 寫操作
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 }
3.3.4 讀操作
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 }
3.4 向AT24CXX寫數據
3.4.1 寫一字節數據( Byte Write)
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 }
3.4.2 寫一頁的數據(Page Write)
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 }
3.4.3 寫入多字節的數據(寫入數據流)
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 }
3.5 從AT24CXX讀數據
3.5.1 任意地址讀一個byte(Random Read)
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 }
3.5.2 讀出short或int型的數據
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 }
3.5.3 讀出epprom中一定長度的數據
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 }