這里以M24C04存儲芯片為例:
一、數據格式
1、讀數據:
2、寫數據:
二、I2C時序圖
1、讀寫時序圖:
三、軟件實現
1、開始
在SCL處於高電平的狀態時,SDA產生一個下降沿信號;
/* *@brief i2c Start *@author Mr.W *@date 2020-8-3 */ static void i2c_start(void) { I2C_SDA_OUTPUT_DIR; I2C_SDA_SET; i2c_delay(5); I2C_SCL_SET; i2c_delay(5); I2C_SDA_CLR; i2c_delay(5); I2C_SCL_CLR; i2c_delay(5); }
2、停止
在SCL處於高電平的狀態時,SDA產生一個上升沿信號;
/* *@brief i2c Stop *@author Mr.W *@date 2020-8-3 */ static void i2c_stop(void) { I2C_SDA_OUTPUT_DIR; I2C_SCL_CLR; i2c_delay(5); I2C_SDA_CLR; i2c_delay(5); I2C_SCL_SET; i2c_delay(5); I2C_SDA_SET; i2c_delay(5); }
3、等待響應信號
如果等到響應信號SDA電平信號由高電平變成低電平,否則未等到響應信號;
/* *@brief i2c Wait Acknowledge *@author Mr.W *@date 2020-8-3 */ static uint8_t i2c_wait_ack(void) { I2C_SDA_SET; I2C_SDA_INPUT_DIR; i2c_delay(5); I2C_SCL_SET; i2c_delay(5); if(I2C_PIN_SDA) { i2c_stop(); return 0; } I2C_SCL_CLR; return 1; }
4、發送響應
/* *@brief i2c Send Acknowledge *@author Mr.W *@date 2020-8-3 */ static void i2c_send_ack(void) { I2C_SDA_OUTPUT_DIR; I2C_SDA_CLR; i2c_delay(5); I2C_SCL_SET; i2c_delay(5); I2C_SCL_CLR; }
5、發送未響應
/* *@brief i2c Send No Acknowledge *@author Mr.W *@date 2020-8-3 */ static void i2c_send_noack(void) { I2C_SDA_OUTPUT_DIR; I2C_SDA_SET; i2c_delay(5); I2C_SCL_SET; i2c_delay(5); I2C_SCL_CLR; }
6、發送數據
發送一個字節數據;
/* *@brief i2c Send Data *@author Mr.W *@date 2020-8-3 */ static void i2c_send_data(uint8_t data) { uint8_t i = 8; I2C_SDA_OUTPUT_DIR; while(i--) { I2C_SCL_CLR; i2c_delay(10); if(data & 0x80) { I2C_SDA_SET; } else { I2C_SDA_CLR; } i2c_delay(5); data <<= 1; I2C_SCL_SET; i2c_delay(5); I2C_SCL_CLR; i2c_delay(5); } }
7、接收數據
接收一個字節數據;
/* *@brief i2c Receive Data *@author Mr.W *@date 2020-8-3 */ static uint8_t i2c_receive_data(void) { uint8_t i = 8; uint8_t data = 0; I2C_SDA_SET; I2C_SDA_INPUT_DIR; while(i--) { data <<= 1; I2C_SCL_CLR; i2c_delay(5); I2C_SCL_SET; i2c_delay(5); if(I2C_PIN_SDA) data |= 0x01; } I2C_SCL_CLR; return(data); }
8、讀多個數據
/* *@brief Read Data *@author Mr.W *@date 2020-8-3 */ uint8_t ReadNByte(uint8_t dev_addr, uint8_t addr, uint8_t *pdata, uint16_t num) { uint8_t i; i2c_start(); i2c_send_data(dev_addr); if(i2c_wait_ack() == 0) { i2c_stop(); return 0; } i2c_send_data(addr); if(i2c_wait_ack() == 0) { i2c_stop(); return 0; } i2c_start(); i2c_send_data(dev_addr|0x01); if(i2c_wait_ack() == 0) { i2c_stop(); return 0; } for(i = 0; i < num; i++) { *pdata++ = i2c_receive_data(); if(i < (num - 1)) i2c_send_ack(); } i2c_send_noack(); i2c_stop(); return 1; }
9、寫一個字節數據
/* *@brief i2c Write one byte *@author Mr.W *@date 2020-8-3 */ static uint8_t i2c_write_one_byte(uint8_t dev_addr, uint8_t addr, const uint8_t *pdata) { i2c_start(); i2c_send_data(dev_addr); if(i2c_wait_ack() == 0) { i2c_stop(); return 0; } i2c_send_data(addr); if(i2c_wait_ack() == 0) { i2c_stop(); return 0; } i2c_send_data(*pdata); if(i2c_wait_ack() == 0) { i2c_stop(); return 0; } i2c_stop(); return 1; }
10、寫多個數據
/* *@brief Write Data *@author Mr.W *@date 2020-8-3 */ uint8_t WriteNByte(uint8_t dev_addr, uint8_t addr, const uint8_t *pdata, uint16_t num) { uint8_t ret = 0; uint16_t i; for(i = 0; i < num; i++) { ret = i2c_write_one_byte(dev_addr, addr++, pdata++); if(ret == 0) { return 0; } /* 此處延時應大於4ms,等待芯片內部寫完成 */ i2c_delay(1500); } return 1; }
11、I2C初始化
/* *@brief i2c Init *@author Mr.W *@date 2020-8-3 */ void i2c_init(void) { I2C_SCL_OUTPUT_DIR; I2C_SDA_OUTPUT_DIR; i2c_stop(); }
11、下面是針對M24C04的讀寫函數實現
/* *@brief M24C04 Write Data *@param addr 數據存儲的起始地址 *@param num 數據大小 *@param 數據起始地址 *@author Mr.W *@date 2020-8-3 */ uint8_t M24C04_WriteByte(uint16_t addr, const uint8_t *pdata, uint16_t size) { uint8_t ret = 0; uint8_t dev_addr = 0xA0; uint32_t bytes; if(addr > 511) return 0; bytes = size; if(addr/256 == 0) { dev_addr = 0xA0; if((addr + bytes) > 511) bytes = 511 - addr; if((addr + bytes) > 256) { ret = WriteNByte((uint8_t)dev_addr, (uint8_t)addr, pdata, (uint16_t)(256 - addr)); dev_addr = 0xA2; ret = WriteNByte((uint8_t)dev_addr, 0, (pdata + 256 - addr), (uint16_t)(addr + bytes - 256)); } else { ret = WriteNByte((uint8_t)dev_addr, (uint8_t)addr, pdata, (uint16_t)bytes); } } else { dev_addr = 0xA2; if((addr + bytes) > 511) { bytes = 511 - addr; } addr &= ~(0x100); ret = WriteNByte(dev_addr, addr, pdata, bytes); } return ret; } /* *@brief M24C04 Read Data *@param addr 數據存儲的起始地址 *@param num 數據大小 *@param 數據起始地址 *@author Mr.W *@date 2020-8-3 */ uint8_t M24C04_ReadByte(uint16_t addr, uint8_t *pdata, uint16_t size) { uint8_t ret = 0; uint8_t dev_addr = 0xA0; uint32_t bytes; if(addr > 511) return 0; bytes = size; if((addr/256) == 0) { dev_addr = 0xA0; if(addr + bytes > 511) bytes = 511 - addr; if((addr + bytes) > 256) { ret = ReadNByte((uint8_t)dev_addr, (uint8_t)addr, pdata, (uint16_t)(256 - addr)); dev_addr = 0xA2; ret = ReadNByte((uint8_t)dev_addr, (uint8_t)0, (pdata + 256 - addr), (uint16_t)(addr + bytes - 256)); } else { ret = ReadNByte((uint8_t)dev_addr, (uint8_t)addr, pdata, (uint16_t)bytes); } } else { dev_addr = 0xA2; if((addr + bytes) > 511) { bytes = 511 - addr; } addr &= ~(0x100); ret = ReadNByte((uint8_t)dev_addr, (uint8_t)addr, pdata, (uint16_t)bytes); } return ret; }
#end