基于软件模拟的I2C对开发板上的AT24C02(EEPROM)进行读写,实现按字节写和指定地址读的函数
时间: 2024-02-27 19:54:22 浏览: 111
好的,针对您的问题,以下是基于软件模拟的I2C对开发板上的AT24C02(EEPROM)进行读写,实现按字节写和指定地址读的函数示例代码。
首先,我们需要定义I2C总线的相关参数,包括SCL和SDA的GPIO引脚号、总线速率等:
```c
#define I2C_SCL_PIN 15
#define I2C_SDA_PIN 2
#define I2C_FREQ_HZ 400000 // I2C总线速率,单位Hz
```
接下来,我们需要实现I2C总线的初始化函数,该函数需要根据上述参数,配置对应的GPIO引脚,设置总线速率等:
```c
void i2c_init(void)
{
gpio_config_t io_conf;
// 配置SCL引脚为开漏输出
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT_OD;
io_conf.pin_bit_mask = (1ULL << I2C_SCL_PIN);
gpio_config(&io_conf);
// 配置SDA引脚为开漏输出
io_conf.pin_bit_mask = (1ULL << I2C_SDA_PIN);
gpio_config(&io_conf);
// 设置I2C总线速率
i2c_set_clk(I2C_FREQ_HZ);
}
```
接下来,我们需要实现I2C总线的发送一个字节的函数,该函数需要根据I2C总线的协议,依次输出8个bit,同时接收从设备的ACK信号:
```c
bool i2c_write_byte(uint8_t data)
{
uint8_t bit;
for (bit = 0; bit < 8; bit++)
{
gpio_set_level(I2C_SDA_PIN, (data & 0x80) ? 1 : 0);
i2c_delay_us();
gpio_set_level(I2C_SCL_PIN, 1);
i2c_delay_us();
gpio_set_level(I2C_SCL_PIN, 0);
data <<= 1;
}
// 接收从设备的ACK信号
gpio_set_direction(I2C_SDA_PIN, GPIO_MODE_INPUT);
i2c_delay_us();
gpio_set_level(I2C_SCL_PIN, 1);
i2c_delay_us();
bool ack = !gpio_get_level(I2C_SDA_PIN);
gpio_set_level(I2C_SCL_PIN, 0);
gpio_set_direction(I2C_SDA_PIN, GPIO_MODE_OUTPUT_OD);
return ack;
}
```
接下来,我们需要实现I2C总线的读取一个字节的函数,该函数需要根据I2C总线的协议,依次输出8个bit,同时接收从设备的数据:
```c
uint8_t i2c_read_byte(bool ack)
{
uint8_t bit, data = 0;
gpio_set_direction(I2C_SDA_PIN, GPIO_MODE_INPUT);
for (bit = 0; bit < 8; bit++)
{
data <<= 1;
gpio_set_level(I2C_SCL_PIN, 1);
i2c_delay_us();
data |= gpio_get_level(I2C_SDA_PIN);
gpio_set_level(I2C_SCL_PIN, 0);
i2c_delay_us();
}
// 发送ACK信号
gpio_set_direction(I2C_SDA_PIN, GPIO_MODE_OUTPUT_OD);
gpio_set_level(I2C_SDA_PIN, ack ? 0 : 1);
i2c_delay_us();
gpio_set_level(I2C_SCL_PIN, 1);
i2c_delay_us();
gpio_set_level(I2C_SCL_PIN, 0);
return data;
}
```
接下来,我们需要实现I2C总线的开始信号和停止信号函数,该函数需要根据I2C总线的协议,依次输出START或STOP信号:
```c
void i2c_start(void)
{
gpio_set_direction(I2C_SDA_PIN, GPIO_MODE_OUTPUT_OD);
gpio_set_level(I2C_SDA_PIN, 1);
gpio_set_level(I2C_SCL_PIN, 1);
i2c_delay_us();
gpio_set_level(I2C_SDA_PIN, 0);
i2c_delay_us();
gpio_set_level(I2C_SCL_PIN, 0);
}
void i2c_stop(void)
{
gpio_set_direction(I2C_SDA_PIN, GPIO_MODE_OUTPUT_OD);
gpio_set_level(I2C_SDA_PIN, 0);
gpio_set_level(I2C_SCL_PIN, 1);
i2c_delay_us();
gpio_set_level(I2C_SDA_PIN, 1);
i2c_delay_us();
}
```
最后,我们需要实现AT24C02(EEPROM)读写的函数,该函数需要根据AT24C02的地址和数据,依次发送START信号、设备地址、数据地址、数据等信息,并接收从设备的ACK信号:
```c
bool i2c_write_eeprom_byte(uint8_t addr, uint8_t data)
{
i2c_start();
if (!i2c_write_byte(0xA0) || !i2c_write_byte(addr) || !i2c_write_byte(data))
{
i2c_stop();
return false;
}
i2c_stop();
return true;
}
bool i2c_read_eeprom_byte(uint8_t addr, uint8_t *data)
{
i2c_start();
if (!i2c_write_byte(0xA0) || !i2c_write_byte(addr))
{
i2c_stop();
return false;
}
i2c_start();
if (!i2c_write_byte(0xA1))
{
i2c_stop();
return false;
}
*data = i2c_read_byte(false);
i2c_stop();
return true;
}
```
以上就是基于软件模拟的I2C对开发板上的AT24C02(EEPROM)进行读写,实现按字节写和指定地址读的函数示例代码。
阅读全文