小熊派gd32f303学习之旅(9)— 使用硬件I2C读写EEPROM
一、前言
在上一篇中,我们使用软件模拟IIC对AT24C02进行了读写,通过查看GD32F30X的参考手册可以知道,其有2个硬件IIC控制器,现在我们就尝试使用其硬件IIC进行对AT24C02的读写。
查看小熊派的原理图,确定AT24C02其使用的IIC引脚为SCL->PB6、SDA->PB7
查看数据手册可以知道这两个引脚被I2C0控制器复用为I2C引脚了,那么就可以满足我们的使用需求了
二、初始化I2C0控制器
如下所示,将I2C0控制器进行初始化
/* 描述:IIC0控制器初始化
* 参数:无
* 返回值:无*/
void i2c0_init(void)
{
/* 使能 GPIOB 时钟 */
rcu_periph_clock_enable(RCU_GPIOB);
/* 使能 I2C0 时钟 */
rcu_periph_clock_enable(RCU_I2C0);
/* 初始化 PB6 复用为 I2C0_SCL, PB7 复用为 I2C0_SDA */
gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
/* 设置I2C0 为标速模式 100 KHz */
i2c_clock_config(I2C0, 100000, I2C_DTCY_2);
/* 设置为I2C模式,并设置其为从机模式下的7位地址 */
i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x78);
/* 使能 I2C0 */
i2c_enable(I2C0);
/* 使能I2C发送应答 */
i2c_ack_config(I2C0, I2C_ACK_ENABLE);
}
三、编写AT24C02控制函数
通过查看AT24C02的数据手册可以看到其读写时序如下
然后编写AT24C02的读取和写入函数
#define AT24C02_Addr 0x50 /* AT24C02的7位器件地址 */
/* 描述:AT24C02初始化
* 参数:无
* 返回值:无*/
void at24c02_init(void)
{
i2c0_init();
}
/* 描述:在AT24C02指定地址读出一个字节的数据
* 参数:ReadAddr: 需要读出数据的地址
* ReadByte: 读出的数据值的存放指针
* 返回值:0:读取成功 其他:读取错误*/
uint8_t AT24C02_Read_Byte(uint16_t ReadAddr, uint8_t *ReadByte)
{
uint8_t err = 1;
i2c_start_on_bus(I2C0); /* 发送一个起始位到I2C总线 */
while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)); /* 等待起始位发送完成 */
i2c_master_addressing(I2C0, AT24C02_Addr<<1, I2C_TRANSMITTER);/* 发送器件地址,写数据 */
while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)); /* 等待从机地址发送完成 */
i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); /* 清除从机地址发送完成标志位 */
while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); /* 等待IIC发送区为空 */
i2c_data_transmit(I2C0, ReadAddr); /* IIC发送数据,AT24C02需要读出数据的地址*/
while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); /* 等待IIC发送区为空,即发送完成 */
i2c_start_on_bus(I2C0); /* 再次发送一个起始位到I2C总线 */
while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)); /* 等待起始位发送完成 */
i2c_master_addressing(I2C0, AT24C02_Addr<<1, I2C_RECEIVER); /* 发送器件地址,读数据 */
while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)); /* 等待从机地址发送完成 */
i2c_ack_config(I2C0, I2C_ACK_DISABLE); /* 设置为非应答 NACK, 要在清除FLAG_ADDSEND前*/
i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); /* 清除从机地址发送完成标志位 */
i2c_stop_on_bus(I2C0); /* 发送一个停止位到I2C总线 */
while(!i2c_flag_get(I2C0, I2C_FLAG_RBNE)); /* 等待数据寄存器可读 */
*ReadByte = i2c_data_receive(I2C0); /* 读出接收到的数据 */
i2c_ack_config(I2C0, I2C_ACK_ENABLE); /* 使能应答 ACK, */
err = 0;
return err;
}
/* 描述:在AT24C02指定地址写入一个字节的数据
* 参数:WriteAddr: 需要写入数据的地址
* WriteByte: 要写入的数据
* 返回值:0:写入成功 其他:写入错误*/
uint8_t AT24C02_Write_Byte(uint16_t WriteAddr,uint16_t WriteByte)
{
uint8_t err = 0;
i2c_start_on_bus(I2C0); /* 发送一个起始位到I2C总线 */
while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)); /* 等待起始位发送完成 */
i2c_master_addressing(I2C0, AT24C02_Addr<<1, I2C_TRANSMITTER);/* 发送器件地址,写数据 */
while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)); /* 等待从机地址发送完成 */
i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); /* 清除从机地址发送完成标志位 */
while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); /* 等待IIC发送区为空 */
i2c_data_transmit(I2C0, WriteAddr); /* IIC发送数据,AT24C02要写入数据的地址*/
while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); /* 等待IIC发送区为空,即发送完成 */
i2c_data_transmit(I2C0, WriteByte); /* IIC发送数据,AT24C02要写入的数据*/
while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); /* 等待IIC发送区为空,即发送完成 */
i2c_stop_on_bus(I2C0); /* 发送一个停止位到I2C总线 */
return err;
}
四、编写主函数
int main(void)
{
uint8_t buff;
uint8_t err;
/* 配置系统时钟 */
systick_config();
/* 初始化LED */
// led_init();
/* 初始化USART0 */
uart0_init(115200);
/* 初始化AT24C02 */
at24c02_init();
/* 通过串口打印 Hello world! */
u0_printf("Hello world! ");
u0_printf("I am William. \r\n");
err = AT24C02_Write_Byte(0x0a, 0xa5);
if(err == 0)
printf("Write 0xa5 to addr 0x0a ok \r\n");
else
{
printf("Write 0xa5 to addr 0x0a err \r\n");
printf("err num : 0x%x \r\n",err);
}
if(AT24C02_Read_Byte(0x0a, &buff) == 0)
printf("Read data: 0x%x from addr 0x0a ok \r\n", buff);
else
printf("Read data from addr 0x0a err \r\n");
while(1)
{
if(UART0_RX_STAT > 0)
{
UART0_RX_STAT = 0;
u0_printf("RECEIVE %d data:%s \r\n", UART0_RX_NUM, UART0_RX_BUF);
}
delay_1ms(10);
}
}
五、功能验证
编译链接烧录到小熊派开发板,然后观察串口输出情况,可以看到读取和写入都成功了
六、附录
完整代码我存放在码云,可以查看:https://gitee.com/william_william/BearPi-GD32F303RGT6.git
上一篇:小熊派gd32f303学习之旅(8)— 使用软件模拟I2C读写EEPROM
下一篇: