小熊派gd32f303学习之旅(9)— 使用硬件I2C读写EEPROM

小熊派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
下一篇:

猜你喜欢

转载自blog.csdn.net/qq_38113006/article/details/109016914