这里以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