【学习记录】GD32 IIC读写BL24C256A 256Kbits(EEPROM)

文章详细描述了如何使用GD32F303CG微控制器通过I2C接口与BL24C256AEEPROM进行通信,包括起始信号、从机地址发送、数据读写以及停止信号的生成。提供了单字节和随机读写的函数实现,强调了在长字节操作中需注意页限制的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主控平台使用gd32f303cg,eeprom使用BL24C256A 大小32kb
使用iic主要有以下的几种信号
起始信号:

//在iic总线上发送起始位
uint8_t iic_start(void){
    uint16_t timeout=0;
		while(i2c_flag_get(I2CX, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) {
				timeout++;
		}
		if(timeout < I2C_TIME_OUT) {
				i2c_start_on_bus(I2CX);
				return 1;
		} else {
				return 0;
		}
}

在总线上发送从机设备地址:
这里trandirection参数表示读取还是写入,如果是读取在i2c_master_addressing函数内部会自动在最低位置1,如果是写入那么会自动将最低为清零

//在iic总线上发送从机地址并清除ADDSEND
uint8_t iic_slave_address(uint8_t addr,uint32_t trandirection){
	 uint16_t timeout=0;
	 while((!i2c_flag_get(I2CX, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) {
       timeout++;
   }
		if(timeout < I2C_TIME_OUT) {
			i2c_master_addressing(I2CX,addr, trandirection);
			timeout=0;
			while((!i2c_flag_get(I2CX, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)) {
					timeout++;
			}
			if(timeout < I2C_TIME_OUT) {
					i2c_flag_clear(I2CX, I2C_FLAG_ADDSEND);//根据要求清除ADDSEND位
        return 1;
			} else {
				return 0;
			}
		} else {
			return 0;
		}
}

读出iic总线上的数据:
根据gd32官方文档在读取最后一个字节之前要将ACKEN位清0,并将STOP位置1,以确保NACK发送给最后一个字节。

//查询TBE的方式写入数据,适用与前n-2个数据
uint8_t iic_datasendTBE(uint8_t iic_data){
	  uint16_t timeout=0;
		while((! i2c_flag_get(I2CX, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) {
				timeout++;
		}
		if(timeout < I2C_TIME_OUT) {
				i2c_data_transmit(I2CX, iic_data);
			return 1;
		} else {
      return 0;
		}
}
//最后一位数据读取时调用
uint8_t iic_dataread_N_2(uint8_t* p_buffer){
	  uint16_t timeout=0;
		/* wait until BTC bit is set */
	//	while(!i2c_flag_get(I2CX, I2C_FLAG_BTC));
		/* disable acknowledge */
		i2c_ack_config(I2CX, I2C_ACK_DISABLE);

		/* wait until BTC bit is set */
	//	while(!i2c_flag_get(I2CX, I2C_FLAG_BTC));
		/* send a stop condition to I2C bus */
		i2c_stop_on_bus(I2CX);
		while(timeout<I2C_TIME_OUT) {
			timeout++;
						/* wait until RBNE bit is set */
			if(i2c_flag_get(I2CX, I2C_FLAG_RBNE)) {
					/* read a byte from the EEPROM */
					*p_buffer = i2c_data_receive(I2CX);
				  return 1;
					/* point to the next location where the byte read will be saved */
			}
		
		}

		return 0;
}

在总线上生成停止位

uint8_t iic_stop(void){
	  uint16_t timeout=0;
		while((!i2c_flag_get(I2CX, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) {//等待最后一个字节发送完成,随后产生停止信号
				timeout++;
		}
		if(timeout < I2C_TIME_OUT) {
		 i2c_stop_on_bus(I2CX);
			timeout=0;
		  while((I2C_CTL0(I2CX) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) {//等待停止信号发送完成
                timeout++;
            }
            if(timeout < I2C_TIME_OUT) {
              return 1;
           
            } else {
			  return 0;
            }
		} else {
			return 0;
	
		}
}

然后是读写的函数,这里给出单字节写入,单字节读取,随机不定长写入和随机不定长数据读取。最常用还是最后两个,单字节读取只能读取上一次写入的地址不能指定地址

//eepron单字节写入
uint8_t eeprom_writeonebyte(uint16_t addr,uint8_t data){
	//i2c_bus_reset();
	if(!iic_start()) return 0;   //发送起始信号
  if(!iic_slave_address(EERPOM_ADD,I2C_TRANSMITTER)) return 0;  //发送设备地址
  if(!iic_datasendTBE(((uint8_t)(addr>>8)))) return 0;   //发送写入地址高8位
  if(!iic_datasendTBE(((uint8_t)(addr)))) return 0;   //发送写入地址低8位
	
	if(!iic_datasendTBE(((uint8_t)(data)))) return 0;   //发送写入的数据
  if(!iic_stop()) return 0;   //发送停止信号
	return 1;
}
//eepron单字节读取
uint8_t eeprom_readonebyte(uint8_t* data){
	uint16_t timeout=0;
	//i2c_bus_reset();
	i2c_ack_config(I2CX, I2C_ACK_ENABLE);//使能回复应答
	if(!iic_start()) return 0;   //发送起始信号
  if(!iic_slave_address(EERPOM_ADD,I2C_RECEIVER)) return 0;  //发送设备地址

  if(!iic_dataread_N_2(data)) return 0;  //读取一字节数据
		while((I2C_CTL0(I2CX) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) {//等待停止位发送完成
				timeout++;
		}
		if(timeout < I2C_TIME_OUT) {
       return 1;
		} else {
			 return 0;
		}
}
//随机写入
uint8_t eeprom_writeRandombyte(uint16_t addr,uint8_t* data,uint16_t length){
	if(!iic_start()) return 0;   //发送起始信号
  if(!iic_slave_address(EERPOM_ADD,I2C_TRANSMITTER)) return 0;  //发送设备地址
  if(!iic_datasendTBE(((uint8_t)(addr>>8)))) return 0;   //发送写入地址高8位
  if(!iic_datasendTBE(((uint8_t)(addr)))) return 0;   //发送写入地址低8位
	
	while(length){
	  if(!iic_datasendTBE(((uint8_t)(*data)))) return 0;   //发送写入的数据
	  length--;
		data++;
	}
  if(!iic_stop()) return 0;   //发送停止信号
	return 1;

}
//随机读取
uint8_t eeprom_readRandombyte(uint16_t addr,uint8_t* data,uint16_t length){
	
	if(!iic_start()) return 0;   //发送起始信号
  if(!iic_slave_address(EERPOM_ADD,I2C_TRANSMITTER)) return 0;  //发送设备地址
  if(!iic_datasendTBE(((uint8_t)(addr>>8)))) return 0;   //发送写入地址高8位
  if(!iic_datasendTBE(((uint8_t)(addr)))) return 0;   //发送写入地址低8位
  while(!i2c_flag_get(I2CX, I2C_FLAG_BTC));
	i2c_bus_reset();
	i2c_ack_config(I2CX, I2C_ACK_ENABLE);//使能回复应答
	if(!iic_start()) return 0;   //发送起始信号
  if(!iic_slave_address(EERPOM_ADD,I2C_RECEIVER)) return 0;  //发送设备地址

	while(length){
		if(length<2){
			 iic_dataread_N_2(data);
		}
		else{
			iic_dataread_N(data);
		}
		data++;
		length--;
	}
	return 1;
}

这里在随机读取写入的时候并没有限制一页多少个,所以在进行长字节的写入和读出的时候需要对这个函数在封装一遍以分配写入读出的页数。
然后是一些主要参考资料:
eeprom的数据手册
单字写入:
在这里插入图片描述单字读取:
在这里插入图片描述
随机写入:
在这里插入图片描述
随机读取:
在这里插入图片描述
最后附上gd32官方提供的iic读写软件流程
在这里插入图片描述
在这里插入图片描述
最后附上全部代码
.h如下

#ifndef AT24CXX_H
#define AT24CXX_H
#include "M_IIC.h"
#include "gd32f30x.h"

#define I2C_SPEED               400000U
#define I2CX_SLAVE_ADDRESS7     0xA0
#define I2C_PAGE_SIZE           8

#define I2CX                    I2C0
#define RCU_GPIO_I2C            RCU_GPIOB
#define RCU_I2C                 RCU_I2C0
#define I2C_SCL_PORT            GPIOB
#define I2C_SDA_PORT            GPIOB
#define I2C_SCL_PIN             GPIO_PIN_6
#define I2C_SDA_PIN             GPIO_PIN_7

#define I2C_TIME_OUT           (uint16_t)(5000)

#define EERPOM_ADD                (uint8_t)0xA0   //0xA0写入 0xA1读取
#define OPENWRITE                  gpio_bit_reset(GPIOB,GPIO_PIN_5)
#define CLOSEWRITE                 gpio_bit_set(GPIOB,GPIO_PIN_5)

uint8_t eeprom_writeRandombyte(uint16_t addr,uint8_t* data,uint16_t length);
uint8_t eeprom_readRandombyte(uint16_t addr,uint8_t* data,uint16_t length);

void iic_test(void);
#endif  /* AT24CXX_H */

.c如下

#include "at24cxx.h"
#include <stdio.h>

//在iic总线上发送起始位
uint8_t iic_start(void){
    uint16_t timeout=0;
		while(i2c_flag_get(I2CX, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) {
				timeout++;
		}
		if(timeout < I2C_TIME_OUT) {
				i2c_start_on_bus(I2CX);
				return 1;
		} else {
				return 0;
		}
}

//在iic总线上发送从机地址并清除ADDSEND
uint8_t iic_slave_address(uint8_t addr,uint32_t trandirection){
	 uint16_t timeout=0;
	 while((!i2c_flag_get(I2CX, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) {
       timeout++;
   }
		if(timeout < I2C_TIME_OUT) {
			i2c_master_addressing(I2CX,addr, trandirection);
			timeout=0;
			while((!i2c_flag_get(I2CX, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)) {
					timeout++;
			}
			if(timeout < I2C_TIME_OUT) {
					i2c_flag_clear(I2CX, I2C_FLAG_ADDSEND);//根据要求清除ADDSEND位
        return 1;
			} else {
				return 0;
			}
		} else {
			return 0;
		}
}
//查询TBE的方式写入数据,适用与前n-2个数据
uint8_t iic_datasendTBE(uint8_t iic_data){
	  uint16_t timeout=0;
		while((! i2c_flag_get(I2CX, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) {
				timeout++;
		}
		if(timeout < I2C_TIME_OUT) {
				i2c_data_transmit(I2CX, iic_data);
			return 1;
		} else {
      return 0;
		}
}
//最后一位数据读取时调用
uint8_t iic_dataread_N_2(uint8_t* p_buffer){
	  uint16_t timeout=0;
		/* wait until BTC bit is set */
	//	while(!i2c_flag_get(I2CX, I2C_FLAG_BTC));
		/* disable acknowledge */
		i2c_ack_config(I2CX, I2C_ACK_DISABLE);

		/* wait until BTC bit is set */
	//	while(!i2c_flag_get(I2CX, I2C_FLAG_BTC));
		/* send a stop condition to I2C bus */
		i2c_stop_on_bus(I2CX);
		while(timeout<I2C_TIME_OUT) {
			timeout++;
						/* wait until RBNE bit is set */
			if(i2c_flag_get(I2CX, I2C_FLAG_RBNE)) {
					/* read a byte from the EEPROM */
					*p_buffer = i2c_data_receive(I2CX);
				  return 1;
					/* point to the next location where the byte read will be saved */
			}
		
		}

		return 0;
}
//前0-N-2个数据调用
uint8_t iic_dataread_N(uint8_t* p_buffer){
	  uint16_t timeout=0;
		while(timeout<I2C_TIME_OUT) {
			timeout++;
						/* wait until RBNE bit is set */
			if(i2c_flag_get(I2CX, I2C_FLAG_RBNE)) {
					/* read a byte from the EEPROM */
					*p_buffer = i2c_data_receive(I2CX);
				  return 1;
					/* point to the next location where the byte read will be saved */
			}
		}
		return 0;
}

uint8_t iic_stop(void){
	  uint16_t timeout=0;
		while((!i2c_flag_get(I2CX, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) {//等待最后一个字节发送完成,随后产生停止信号
				timeout++;
		}
		if(timeout < I2C_TIME_OUT) {
		 i2c_stop_on_bus(I2CX);
			timeout=0;
		  while((I2C_CTL0(I2CX) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) {//等待停止信号发送完成
                timeout++;
            }
            if(timeout < I2C_TIME_OUT) {
              return 1;
           
            } else {
							return 0;
            }
		} else {
			return 0;
	
		}
}

//eepron单字节写入
uint8_t eeprom_writeonebyte(uint16_t addr,uint8_t data){
	//i2c_bus_reset();
	if(!iic_start()) return 0;   //发送起始信号
  if(!iic_slave_address(EERPOM_ADD,I2C_TRANSMITTER)) return 0;  //发送设备地址
  if(!iic_datasendTBE(((uint8_t)(addr>>8)))) return 0;   //发送写入地址高8位
  if(!iic_datasendTBE(((uint8_t)(addr)))) return 0;   //发送写入地址低8位
	
	if(!iic_datasendTBE(((uint8_t)(data)))) return 0;   //发送写入的数据
  if(!iic_stop()) return 0;   //发送停止信号
	return 1;
}
//eepron单字节读取
uint8_t eeprom_readonebyte(uint8_t* data){
	uint16_t timeout=0;
	//i2c_bus_reset();
	i2c_ack_config(I2CX, I2C_ACK_ENABLE);//使能回复应答
	if(!iic_start()) return 0;   //发送起始信号
  if(!iic_slave_address(EERPOM_ADD,I2C_RECEIVER)) return 0;  //发送设备地址

  if(!iic_dataread_N_2(data)) return 0;  //读取一字节数据
		while((I2C_CTL0(I2CX) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) {//等待停止位发送完成
				timeout++;
		}
		if(timeout < I2C_TIME_OUT) {
       return 1;
		} else {
			 return 0;
		}
}
//随机写入
uint8_t eeprom_writeRandombyte(uint16_t addr,uint8_t* data,uint16_t length){
	OPENWRITE;
	//delay_1ms(10);
	if(!iic_start()) return 0;   //发送起始信号
  if(!iic_slave_address(EERPOM_ADD,I2C_TRANSMITTER)) return 0;  //发送设备地址
  if(!iic_datasendTBE(((uint8_t)(addr>>8)))) return 0;   //发送写入地址高8位
  if(!iic_datasendTBE(((uint8_t)(addr)))) return 0;   //发送写入地址低8位
	
	while(length){
	  if(!iic_datasendTBE(((uint8_t)(*data)))) return 0;   //发送写入的数据
	  length--;
		data++;
	}
  if(!iic_stop()) return 0;   //发送停止信号
//	CLOSEWRITE;
	return 1;

}
//随机读取
uint8_t eeprom_readRandombyte(uint16_t addr,uint8_t* data,uint16_t length){
	
	if(!iic_start()) return 0;   //发送起始信号
  if(!iic_slave_address(EERPOM_ADD,I2C_TRANSMITTER)) return 0;  //发送设备地址
  if(!iic_datasendTBE(((uint8_t)(addr>>8)))) return 0;   //发送写入地址高8位
  if(!iic_datasendTBE(((uint8_t)(addr)))) return 0;   //发送写入地址低8位
  while(!i2c_flag_get(I2CX, I2C_FLAG_BTC));
	i2c_bus_reset();
	i2c_ack_config(I2CX, I2C_ACK_ENABLE);//使能回复应答
	if(!iic_start()) return 0;   //发送起始信号
  if(!iic_slave_address(EERPOM_ADD,I2C_RECEIVER)) return 0;  //发送设备地址

	while(length){
		if(length<2){
			 iic_dataread_N_2(data);
		}
		else{
			iic_dataread_N(data);
		}
		data++;
		length--;
	}
	return 1;
}
void iic_test(void){
//	uint8_t buf[10]={0},buf2[10]={0x12,0x34,3,4,5,6,7,8,9,10};
//  eeprom_writeRandombyte(0x0000,buf2,2);
//	uint8_t ad=0;
//	delay_1ms(5);
//  eeprom_readRandombyte(0x0000,buf,2);
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值